From 91c10b815ea9449fc44c64e308066dfbe49919df Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Sat, 8 Dec 2012 20:01:21 +0100 Subject: [PATCH] line separators normalized --- .idea/libraries/Ant.xml | 56 +- .idea/libraries/Netty.xml | 20 +- .idea/libraries/Snappy_Java.xml | 26 +- .idea/libraries/proxy_vole.xml | 16 +- README.md | 40 +- RegExpSupport/test/test/MainParseTest.java | 440 +- build.txt | 2 +- images/src/META-INF/ImagesPlugin.xml | 286 +- .../intellij/compiler/impl/CompileDriver.java | 5660 ++++++++--------- .../options/CompilerOptionsPanel.form | 306 +- .../options/CompilerUIConfigurable.java | 492 +- .../BuildArtifactsBeforeRunTaskProvider.java | 520 +- .../CompilerWorkspaceConfiguration.java | 130 +- .../options/CompileStepBeforeRun.java | 378 +- .../completion/ConstructorInsertHandler.java | 500 +- .../JavaClassNameCompletionContributor.java | 366 +- .../completion/JavaCompletionFeatures.java | 60 +- .../completion/JavaStaticMemberProcessor.java | 180 +- .../quickfix/DefaultQuickFixProvider.java | 256 +- ...reakStringOnLineBreaksIntentionAction.java | 218 +- .../navigation/JavaGotoSuperHandler.java | 164 +- .../FileHeaderChecker.java | 388 +- .../internal/FileEqualsUsageInspection.java | 100 +- .../filters/getters/JavaMembersGetter.java | 312 +- .../psi/formatter/java/AbstractJavaBlock.java | 2994 ++++----- .../psi/formatter/java/LeafBlock.java | 222 +- .../psi/formatter/java/SimpleJavaBlock.java | 268 +- .../com/intellij/psi/impl/JavaRegExpHost.java | 130 +- .../impl/file/JavaDirectoryServiceImpl.java | 438 +- .../intellij/psi/util/CreateClassUtil.java | 492 +- .../changeSignature/JavaMethodDescriptor.java | 190 +- .../rename/RenameJavaMethodProcessor.java | 728 +-- .../ui/JavaComboBoxVisibilityPanel.java | 76 +- .../refactoring/ui/JavaVisibilityPanel.java | 334 +- .../searches/OverridingMethodsSearch.java | 194 +- .../search/JavaOverridingMethodsSearcher.java | 160 +- .../psi/impl/search/MethodSuperSearcher.java | 142 +- .../psi/codeStyle/JavaCodeStyleManager.java | 426 +- .../search/searches/SuperMethodsSearch.java | 154 +- .../core/CoreJavaCodeStyleManager.java | 376 +- .../psi/impl/FindSuperElementsHelper.java | 112 +- .../tree/java/PsiLiteralExpressionImpl.java | 802 +-- .../completion/keywords/returnInTernary.java | 10 +- ...eferLocalsToStaticsInSecondCompletion.java | 12 +- ...PreselectMostRelevantInTheMiddleAlpha.java | 32 +- .../UnderscoresDontMakeMatchMiddle.java | 8 +- ...CollapsedInCaseOfAnonymousClasses-out.java | 64 +- ...xpectedReturnTypeWithSubstitution-out.java | 60 +- .../smartType/NewAnonymousFunction-out.java | 56 +- .../breakStringOnLineBreaks/afterAll.java | 14 +- .../breakStringOnLineBreaks/beforeAll.java | 10 +- .../beforeLastSlashN.java | 10 +- .../beforeLastSlashNSlashR.java | 10 +- .../after2Bytes.java | 42 +- .../before2Bytes.java | 42 +- .../completion/ClassNameCompletionTest.java | 538 +- .../completion/CompletionSortingTestCase.java | 164 +- .../GlobalMemberNameCompletionTest.groovy | 422 +- .../completion/HeavyNormalCompletionTest.java | 226 +- .../quickFix/BreakStringOnLineBreaksTest.java | 58 +- .../completion/CompletionTestCase.java | 246 +- .../completion/LightCompletionTestCase.java | 274 +- .../jetbrains/jps/javac/JavacFileManager.java | 482 +- .../jetbrains/jps/javac/OutputFileObject.java | 256 +- .../org/jetbrains/ether/LogParser.java | 162 +- license/kryo-license.txt | 20 +- .../openapi/application/AccessToken.java | 32 +- .../psi/stubs/StubSerializationHelper.java | 464 +- .../src/com/intellij/mock/MockProject.java | 310 +- .../application/impl/ModalityStateEx.java | 204 +- .../editor/ex/util/SegmentArrayWithData.java | 236 +- .../impl/source/tree/CompositeElement.java | 1904 +++--- .../options/feature.usage.statistics.xml | 148 +- .../completion/CompletionParameters.java | 218 +- .../completion/CompletionType.java | 30 +- .../completion/SkipAutopopupInStrings.java | 132 +- .../impl/PriorityIntentionActionWrapper.java | 192 +- .../impl/PriorityLocalQuickFixWrapper.java | 170 +- .../com/intellij/codeInspection/QuickFix.java | 104 +- .../execution/BeforeRunTaskProvider.java | 182 +- .../execution/DefaultExecutionTarget.java | 96 +- .../intellij/execution/ExecutionTarget.java | 100 +- .../execution/ExecutionTargetListener.java | 44 +- .../execution/ExecutionTargetManager.java | 146 +- .../execution/ExecutionTargetProvider.java | 62 +- .../RunnerAndConfigurationSettings.java | 144 +- .../configurations/CommandLineState.java | 304 +- .../configurations/RunConfigurationBase.java | 548 +- .../configurations/TargetAwareRunProfile.java | 46 +- .../formatting/DependentSpacingRule.java | 190 +- .../src/com/intellij/formatting/Spacing.java | 370 +- .../intellij/formatting/SpacingFactory.java | 116 +- .../intellij/patterns/PsiElementPattern.java | 678 +- .../application/options/CodeCompletion.form | 470 +- .../options/CodeCompletionPanel.java | 472 +- .../application/options/OptionId.java | 62 +- .../codeInsight/CodeInsightSettings.java | 342 +- .../completion/CodeCompletionFeatures.java | 76 +- .../completion/PrefixMatchingWeigher.java | 60 +- .../actions/BaseCodeCompletionAction.java | 138 +- .../actions/ClassNameCompletionAction.java | 60 +- .../actions/CodeCompletionAction.java | 72 +- .../actions/SmartCodeCompletionAction.java | 72 +- .../DefaultGutterIconNavigationHandler.java | 76 +- .../daemon/impl/GeneralHighlightingPass.java | 1758 ++--- .../FileReferenceQuickFixProvider.java | 356 +- .../CompletionAutoPopupHandler.java | 252 +- .../intention/impl/QuickEditAction.java | 280 +- .../template/macro/BaseCompleteMacro.java | 332 +- .../macro/ClassNameCompleteMacro.java | 64 +- .../template/macro/CompleteMacro.java | 68 +- .../template/macro/CompleteSmartMacro.java | 64 +- .../actions/InspectionListCellRenderer.java | 234 +- .../DefaultExecutionTargetProvider.java | 60 +- .../execution/ExecutionTargetManagerImpl.java | 376 +- .../intellij/execution/ProgramRunnerUtil.java | 280 +- .../ChooseDebugConfigurationPopupAction.java | 72 +- .../ChooseRunConfigurationPopupAction.java | 148 +- .../RunConfigurationsComboBoxAction.java | 656 +- .../RunConfigurationBeforeRunProvider.java | 764 +-- .../RunnerAndConfigurationSettingsImpl.java | 896 +-- .../impl/UnknownBeforeRunTaskProvider.java | 248 +- .../ui/layout/impl/GridCellImpl.java | 984 +-- .../AbstractBlockAlignmentProcessor.java | 260 +- .../formatting/AbstractBlockWrapper.java | 1058 +-- .../intellij/formatting/AlignmentImpl.java | 398 +- .../formatting/BlockAlignmentProcessor.java | 180 +- .../src/com/intellij/formatting/BlockEx.java | 64 +- .../formatting/DependantSpacingImpl.java | 234 +- .../intellij/formatting/FormatProcessor.java | 2914 ++++----- .../DataLanguageBlockWrapper.java | 366 +- .../actions/CreateFileFromTemplateAction.java | 164 +- .../favoritesTreeView/FavoritesManager.java | 1434 ++--- .../fileTemplates/FileTemplateManager.java | 232 +- .../ide/fileTemplates/FileTemplateUtil.java | 814 +-- .../ui/CreateFromTemplateDialog.java | 316 +- .../util/NavigationItemListCellRenderer.java | 400 +- .../util/gotoByName/GotoFileCellRenderer.java | 292 +- .../customFolding/GotoCustomRegionAction.java | 176 +- .../customFolding/GotoCustomRegionDialog.form | 50 +- .../customFolding/GotoCustomRegionDialog.java | 338 +- .../util/LayeredLexerEditorHighlighter.java | 1176 ++-- .../openapi/module/impl/ModuleImpl.java | 770 +-- .../paths/StaticPathReferenceProvider.java | 188 +- .../common/InjectedLanguageBlockWrapper.java | 310 +- .../injected/InjectedLanguageManagerImpl.java | 974 +-- .../psi/stubs/SerializedStubTree.java | 194 +- .../ChangeSignatureDialogBase.java | 1352 ++-- .../changeSignature/MethodDescriptor.java | 86 +- .../ui/ComboBoxVisibilityPanel.java | 270 +- .../refactoring/ui/VisibilityPanelBase.java | 72 +- .../src/com/intellij/tools/ToolAction.java | 130 +- .../com/intellij/tools/ToolBeforeRunTask.java | 176 +- .../src/com/intellij/tools/ToolsPanel.java | 1082 ++-- .../ChangeTrackingValueContainer.java | 332 +- .../indexing/UpdatableValueContainer.java | 56 +- .../util/indexing/ValueContainerImpl.java | 836 +-- .../util/indexing/ValueContainerMap.java | 258 +- .../history/core/ChangeListStorageImpl.java | 554 +- .../openapi/actionSystem/AnAction.java | 664 +- .../openapi/actionSystem/IdeActions.java | 524 +- .../openapi/editor/EditorFactory.java | 404 +- .../src/com/intellij/openapi/ui/Messages.java | 3126 ++++----- .../intellij/openapi/vfs/JarFileSystem.java | 98 +- .../ui/speedSearch/ListWithFilter.java | 376 +- .../intellij/ui/speedSearch/SpeedSearch.java | 218 +- .../src/com/intellij/ui/table/TableView.java | 506 +- .../src/com/intellij/util/Icons.java | 46 +- .../com/intellij/diagnostic/ITNReporter.java | 504 +- .../com/intellij/ide/ReopenProjectAction.java | 136 +- .../ide/actions/ShowContentAction.java | 156 +- .../ide/startupWizard/SelectPluginsStep.java | 566 +- .../ui/customization/CustomActionsSchema.java | 800 +-- .../notification/EventLogConsole.java | 500 +- .../actions/DeleteToWordStartAction.java | 276 +- .../editor/actions/HungryBackspaceAction.java | 166 +- .../openapi/editor/impl/FoldRegionsTree.java | 692 +- .../updateSettings/impl/PluginDownloader.java | 940 +-- .../src/com/intellij/ui/SpeedSearchBase.java | 1292 ++-- .../ui/mac/MacMainFrameDecorator.java | 494 +- .../com/intellij/util/CompressionUtil.java | 222 +- .../src/messages/DiagnosticBundle.properties | 186 +- .../FeatureStatisticsBundle.properties | 242 +- .../src/messages/KeyMapBundle.properties | 204 +- .../src/messages/RefactoringBundle.properties | 1544 ++--- .../src/tips/TagNameCompletion.html | 32 +- .../src/META-INF/LangExtensionPoints.xml | 1152 ++-- .../src/componentSets/Execution.xml | 66 +- .../src/idea/Keymap_Default.xml | 1900 +++--- ...apApplianceOnDocumentModificationTest.java | 2186 +++---- .../com/intellij/core/CoreModuleManager.java | 162 +- .../com/intellij/core/CoreProjectLoader.java | 192 +- .../roots/impl/ContentFolderBaseImpl.java | 254 +- .../roots/impl/DirectoryIndexImpl.java | 1776 +++--- .../openapi/roots/impl/DirectoryInfo.java | 716 +-- .../mock/MockExecutionTargetManager.java | 102 +- .../testFramework/TestLoggerFactory.java | 192 +- .../com/intellij/openapi/util/Comparing.java | 356 +- .../execution/process/UnixProcessManager.java | 574 +- .../intellij/util/io/PagedFileStorage.java | 1452 ++--- .../com/intellij/util/text/CharArrayUtil.java | 1144 ++-- .../openapi/vcs/ui/SearchFieldAction.java | 198 +- .../CommonIntegrateFileOrDirectoryAction.java | 52 +- .../CommonUpdateFileOrDirectoryAction.java | 58 +- .../xdebugger/impl/actions/ResumeAction.java | 120 +- .../BadExceptionDeclaredInspection.java | 320 +- .../TooBroadThrowsInspection.java | 414 +- .../BadExceptionDeclared.html | 28 +- .../TooBroadThrows.html | 34 +- .../PointlessBooleanExpression.java | 60 +- .../expected.xml | 90 +- ...ntlessBooleanExpressionInspectionTest.java | 58 +- .../inject/InjectLanguageAction.java | 294 +- .../inject/UnInjectLanguageAction.java | 228 +- .../ConstantSubexpressionIntention.java | 288 +- .../ConstantSubexpressionPredicate.java | 202 +- .../siyeh/ipp/psiutils/ExpressionUtils.java | 170 +- .../android-designer/src/META-INF/plugin.xml | 82 +- .../designer/AndroidDesignerBundle.java | 102 +- .../designer/model/AndroidWrapInProvider.java | 94 +- .../android/designer/model/RadFragment.java | 252 +- .../android/designer/model/RadViewLayout.java | 96 +- .../android/AndroidFileTemplateProvider.java | 218 +- .../actions/CreateResourceFileAction.java | 544 +- .../actions/CreateXmlResourceDialog.java | 1110 ++-- .../config/impl/AntBeforeRunTaskProvider.java | 308 +- .../history/wholeTree/BasePopupAction.java | 310 +- .../git4idea/history/wholeTree/Commit.java | 176 +- .../git4idea/history/wholeTree/CommitI.java | 64 +- .../history/wholeTree/GitLogFilters.java | 278 +- .../GitLogShowOnlyStarredCommitsAction.java | 126 +- .../wholeTree/GroupHeaderCommitDecorator.java | 198 +- .../GroupHeaderDatePseudoCommit.java | 188 +- .../history/wholeTree/LoadController.java | 368 +- .../git4idea/history/wholeTree/Mediator.java | 110 +- .../history/wholeTree/MediatorImpl.java | 820 +-- .../MultipleRepositoryCommitDecorator.java | 190 +- .../history/wholeTree/RootsHolder.java | 90 +- .../wholeTree/WireNumberCommitDecoration.java | 190 +- .../GrReassignedInClosureLocalVar.html | 12 +- .../actions/GroovyTemplatesFactory.java | 214 +- ...KeywordAndDeclarationHighlightFactory.java | 88 +- .../GrKeywordAndDeclarationHighlighter.java | 272 +- .../GrReferenceHighlighterFactory.java | 84 +- .../GrReassignedLocalVarsChecker.java | 234 +- ...ReassignedInClosureLocalVarInspection.java | 218 +- .../GrUnresolvedAccessInspection.java | 1096 ++-- .../GroovyUntypedAccessInspection.java | 170 +- .../GrHighlightExitPointHandler.java | 164 +- .../findUsages/GrHighlightHandlerFactory.java | 112 +- .../intentions/style/AddReturnTypeFix.java | 222 +- .../GroovyCompletionContributor.java | 1590 ++--- .../groovy/lang/psi/GrTypeConverter.java | 94 +- .../psi/impl/statements/GrVariableImpl.java | 108 +- .../lang/psi/impl/synthetic/GrLightField.java | 408 +- .../psi/impl/synthetic/GrScriptField.java | 154 +- .../psi/impl/types/GrStringTypeConverter.java | 98 +- .../ClosureParameterEnhancer.java | 626 +- .../groovy/lang/psi/util/GrClassImplUtil.java | 1198 ++-- .../lang/psi/util/GroovyCommonClassNames.java | 132 +- .../method/GroovyExtractMethodDialog.java | 718 +-- .../ui/GroovyComboboxVisibilityPanel.java | 80 +- .../plugins/groovy/LightGroovyTestCase.groovy | 142 +- .../completion/ReferenceCompletionTest.java | 124 +- .../groovy/lang/GppFunctionalTest.groovy | 1232 ++-- .../lang/GroovyStressPerformanceTest.groovy | 512 +- .../lang/resolve/ResolveMethodTest.groovy | 2896 ++++----- .../lang/resolve/ResolvePropertyTest.groovy | 1826 +++--- .../field/GrIntroduceFieldTest.groovy | 384 +- .../stringWithMistakes/idea50496.java | 38 +- .../ClassNameWithMistakesInspectionTest.java | 66 +- .../DocCommentWithMistakesInspectionTest.java | 64 +- .../FieldNameWithMistakesInspectionTest.java | 66 +- .../JavaSpellcheckerInspectionTestCase.java | 72 +- .../LiteralExpressionTokenizerTest.java | 116 +- ...calVariableWithMistakesInspectionTest.java | 64 +- .../MethodNameWithMistakesInspectionTest.java | 64 +- .../StringWithMistakesInspectionTest.java | 76 +- .../execution/junit/JUnitConfiguration.java | 1156 ++-- .../intellij/execution/junit/TestClass.java | 166 +- .../execution/junit/TestDirectory.java | 242 +- .../intellij/execution/junit/TestMethod.java | 316 +- .../intellij/execution/junit/TestMethods.java | 190 +- .../intellij/execution/junit/TestPackage.java | 902 +-- .../execution/junit/TestsPattern.java | 396 +- .../maven3-server-impl/lib/maven3/bin/m2.conf | 14 +- .../maven3-server-impl/lib/maven3/bin/mvn.bat | 394 +- .../lib/maven3/bin/mvnDebug.bat | 400 +- .../MavenBaseModifiableModelsProvider.java | 438 +- .../tasks/MavenBeforeRunTasksProvider.java | 360 +- .../PropertiesCompletionContributor.java | 88 +- .../PropertiesDocumentationProvider.java | 162 +- .../spellchecker/tokenizer/TokenConsumer.java | 82 +- .../tokenizer/XmlTextTokenizer.java | 84 +- .../idea/svn/RepeatSvnActionThroughBusy.java | 120 +- .../org/jetbrains/idea/SvnTestCase.java | 614 +- .../org/jetbrains/idea/svn/Svn17TestCase.java | 44 +- .../idea/svn/SvnTestDirtyScopeStateTest.java | 286 +- .../pivotal/PivotalTrackerRepository.java | 728 +-- .../ui-designer-new/src/META-INF/plugin.xml | 50 +- .../com/intellij/designer/DesignerBundle.java | 102 +- .../designer/actions/DesignerActionPanel.java | 390 +- .../designer/actions/WrapInAction.java | 206 +- .../intellij/designer/model/RadLayout.java | 134 +- .../designer/model/WrapInProvider.java | 68 +- .../xpath/xslt/util/XsltCodeInsightUtil.java | 546 +- resources-en/src/fileTemplates/default.html | 142 +- .../includes/File Header.java.html | 134 +- .../src/fileTemplates/includes/default.html | 136 +- .../description.html | 10 +- .../src/messages/CompletionBundle.properties | 18 +- .../src/tips/CompletionImportStatic.html | 34 +- .../src/ProductivityFeaturesRegistry.xml | 958 +-- .../xml/ElementPresentationManagerImpl.java | 112 +- .../intellij/util/xml/JavaNameStrategy.java | 86 +- .../options/HtmlCodeStyleMainPanel.java | 72 +- .../HtmlCodeStyleSettingsProvider.java | 90 +- .../HtmlLanguageCodeStyleSettings.java | 100 +- .../completion/XmlCompletionContributor.java | 428 +- .../psi/impl/source/xml/XmlTextImpl.java | 1056 +-- 320 files changed, 60697 insertions(+), 60697 deletions(-) diff --git a/.idea/libraries/Ant.xml b/.idea/libraries/Ant.xml index 433bd3b5e5f0..fca1abd1e774 100644 --- a/.idea/libraries/Ant.xml +++ b/.idea/libraries/Ant.xml @@ -1,29 +1,29 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Netty.xml b/.idea/libraries/Netty.xml index ffb479f53fd4..5a8873386c49 100644 --- a/.idea/libraries/Netty.xml +++ b/.idea/libraries/Netty.xml @@ -1,11 +1,11 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Snappy_Java.xml b/.idea/libraries/Snappy_Java.xml index 79efa842173c..0b6f63913b86 100644 --- a/.idea/libraries/Snappy_Java.xml +++ b/.idea/libraries/Snappy_Java.xml @@ -1,14 +1,14 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/proxy_vole.xml b/.idea/libraries/proxy_vole.xml index e59c52e5eb6e..74a709c8cf82 100644 --- a/.idea/libraries/proxy_vole.xml +++ b/.idea/libraries/proxy_vole.xml @@ -1,9 +1,9 @@ - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 3e09124325e9..a8a5f3459c58 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,20 @@ -# IntelliJ IDEA Community Edition - -This is the official GitHub mirror of the [IntelliJ IDEA Community Edition](http://www.jetbrains.com/idea/) source code. - -## Building - -To develop IntelliJ IDEA, you can use either IntelliJ IDEA Community Edition or IntelliJ IDEA Ultimate. To build and run the code: - -* Make sure you have the Groovy plugin enabled. Parts of IntelliJ IDEA are written in Groovy, and you will get compilation errors if you don't have the plugin enabled. -* Make sure you have the UI Designer plugin enabled. Most of IntelliJ IDEA's UI is built using the UI Designer, and the version you build will not run correctly if you don't have the plugin enabled. -* Open the directory with the source code as a directory-based project -* Configure a JSDK named "IDEA jdk", pointing to an installation of JDK 1.6 -* On Windows or Linux, add lib\tools.jar from the JDK installation directory to the classpath of IDEA jdk -* Use Build | Make Project to build the code -* To run the code, use the provided shared run configuration "IDEA". - -## Contributing - -Pull requests are welcome. Please make sure that you follow the [IntelliJ Coding Guidelines](http://www.jetbrains.org/display/IJOS/IntelliJ+Coding+Guidelines). -Note that you'll need to submit a [Contributor Agreement](http://www.jetbrains.org/display/IJOS/Contributor+Agreement) before we can accept your pull request. +# IntelliJ IDEA Community Edition + +This is the official GitHub mirror of the [IntelliJ IDEA Community Edition](http://www.jetbrains.com/idea/) source code. + +## Building + +To develop IntelliJ IDEA, you can use either IntelliJ IDEA Community Edition or IntelliJ IDEA Ultimate. To build and run the code: + +* Make sure you have the Groovy plugin enabled. Parts of IntelliJ IDEA are written in Groovy, and you will get compilation errors if you don't have the plugin enabled. +* Make sure you have the UI Designer plugin enabled. Most of IntelliJ IDEA's UI is built using the UI Designer, and the version you build will not run correctly if you don't have the plugin enabled. +* Open the directory with the source code as a directory-based project +* Configure a JSDK named "IDEA jdk", pointing to an installation of JDK 1.6 +* On Windows or Linux, add lib\tools.jar from the JDK installation directory to the classpath of IDEA jdk +* Use Build | Make Project to build the code +* To run the code, use the provided shared run configuration "IDEA". + +## Contributing + +Pull requests are welcome. Please make sure that you follow the [IntelliJ Coding Guidelines](http://www.jetbrains.org/display/IJOS/IntelliJ+Coding+Guidelines). +Note that you'll need to submit a [Contributor Agreement](http://www.jetbrains.org/display/IJOS/Contributor+Agreement) before we can accept your pull request. diff --git a/RegExpSupport/test/test/MainParseTest.java b/RegExpSupport/test/test/MainParseTest.java index 0c41b1e37653..8f46144f6767 100644 --- a/RegExpSupport/test/test/MainParseTest.java +++ b/RegExpSupport/test/test/MainParseTest.java @@ -1,220 +1,220 @@ -/* - * Copyright 2006 Sascha Weinreuter - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package test; - -import org.intellij.lang.regexp.RegExpFileType; -import org.jdom.Document; -import org.jdom.Element; -import org.jdom.input.SAXBuilder; -import org.jdom.xpath.XPath; - -import java.io.*; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -public class MainParseTest extends BaseParseTestcase { - - private ByteArrayOutputStream myOut; - - enum Result { - OK, ERR - } - - static class Test { - String pattern; - boolean showWarnings = true; - boolean showInfo = false; - Result expectedResult; - - Test(String pattern, Result result, boolean warn, boolean info) { - this.pattern = pattern; - expectedResult = result; - showWarnings = warn; - showInfo = info; - } - } - - private final Map myMap = new LinkedHashMap(); - - @Override - protected void setUp() throws Exception { - final Document document = new SAXBuilder().build(new File(getTestDataRoot(), "/RETest.xml")); - final List list = XPath.selectNodes(document.getRootElement(), "//test"); - - int i = 0; - for (Element element : list) { - final String name; - final Element parent = (Element)element.getParent(); - final String s = parent.getName(); - final String t = parent.getAttribute("id") == null ? "" : parent.getAttribute("id").getValue() + "-"; - if (!"tests".equals(s)) { - name = s + "/test-" + t + ++i + ".regexp"; - } - else { - name = "test-" + t + ++i + ".regexp"; - } - final Result result = Result.valueOf((String)XPath.selectSingleNode(element, "string(expected)")); - final boolean warn = !"false".equals(element.getAttributeValue("warning")); - final boolean info = "true".equals(element.getAttributeValue("info")); - - final String pattern = (String)XPath.selectSingleNode(element, "string(pattern)"); - myMap.put(name, new Test(pattern, result, warn, info)); - if (!"false".equals(element.getAttributeValue("verify"))) { - try { - Pattern.compile(pattern); - if (result == Result.ERR) { - System.out.println("Incorrect FAIL value for " + pattern); - } - } - catch (PatternSyntaxException e) { - if (result == Result.OK) { - System.out.println("Incorrect OK value for " + pattern); - } - } - } - } - - super.setUp(); - - myOut = new ByteArrayOutputStream(); - System.setErr(new PrintStream(myOut)); - } - - @Override - protected String getTestDataPath() { - return super.getTestDataPath() + "/gen/"; - } - - public void testSimple() throws Exception { - doTest("simple/"); - } - - public void testQuantifiers() throws Exception { - doTest("quantifiers/"); - } - - public void testGroups() throws Exception { - doTest("groups/"); - } - - public void testCharclasses() throws Exception { - doTest("charclasses/"); - } - - public void testEscapes() throws Exception { - doTest("escapes/"); - } - - public void testAnchors() throws Exception { - doTest("anchors/"); - } - - public void testNamedchars() throws Exception { - doTest("namedchars/"); - } - - public void testBackrefs() throws Exception { - doTest("backrefs/"); - } - - public void testComplex() throws Exception { - doTest("complex/"); - } - - public void testIncomplete() throws Exception { - doTest("incomplete/"); - } - - public void testRealLife() throws Exception { - doTest("real-life/"); - } - - public void testRegressions() throws Exception { - doTest("regressions/"); - } - - public void testBugs() throws Exception { - doTest("bug/"); - } - - public void testFromXML() throws Exception { - doTest(null); - } - - private void doTest(String prefix) throws IOException { - int n = 0; - int failed = 0; - for (String name : myMap.keySet()) { - if (prefix == null && name.contains("/")) { - continue; - } - if (prefix != null && !name.startsWith(prefix)) { - continue; - } - System.out.print("filename = " + name); - n++; - - final MainParseTest.Test test = myMap.get(name); - try { - myFixture.configureByText(RegExpFileType.INSTANCE, test.pattern); - myFixture.testHighlighting(test.showWarnings, true, test.showInfo); - - if (test.expectedResult == Result.ERR) { - System.out.println(" FAILED. Expression incorrectly parsed OK: " + test.pattern); - failed++; - } - else { - System.out.println(" OK"); - } - } - catch (Throwable e) { - if (test.expectedResult == Result.ERR) { - System.out.println(" OK"); - } - else { - e.printStackTrace(); - System.out.println(" FAILED. Expression = " + test.pattern); - if (myOut.size() > 0) { - String line; - final BufferedReader reader = new BufferedReader(new StringReader(myOut.toString())); - do { - line = reader.readLine(); - } - while (line != null && (line.trim().length() == 0 || line.trim().equals("ERROR:"))); - if (line != null) { - if (line.matches(".*java.lang.Error: junit.framework.AssertionFailedError:.*")) { - System.out.println("ERROR: " + line.replace("java.lang.Error: junit.framework.AssertionFailedError:", "")); - } - } - else { - System.out.println("ERROR: " + myOut.toString()); - } - } - failed++; - } - } - myOut.reset(); - } - - System.out.println(""); - System.out.println(n + " Tests executed, " + failed + " failed"); - - assertFalse(failed > 0); - } -} +/* + * Copyright 2006 Sascha Weinreuter + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package test; + +import org.intellij.lang.regexp.RegExpFileType; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.input.SAXBuilder; +import org.jdom.xpath.XPath; + +import java.io.*; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +public class MainParseTest extends BaseParseTestcase { + + private ByteArrayOutputStream myOut; + + enum Result { + OK, ERR + } + + static class Test { + String pattern; + boolean showWarnings = true; + boolean showInfo = false; + Result expectedResult; + + Test(String pattern, Result result, boolean warn, boolean info) { + this.pattern = pattern; + expectedResult = result; + showWarnings = warn; + showInfo = info; + } + } + + private final Map myMap = new LinkedHashMap(); + + @Override + protected void setUp() throws Exception { + final Document document = new SAXBuilder().build(new File(getTestDataRoot(), "/RETest.xml")); + final List list = XPath.selectNodes(document.getRootElement(), "//test"); + + int i = 0; + for (Element element : list) { + final String name; + final Element parent = (Element)element.getParent(); + final String s = parent.getName(); + final String t = parent.getAttribute("id") == null ? "" : parent.getAttribute("id").getValue() + "-"; + if (!"tests".equals(s)) { + name = s + "/test-" + t + ++i + ".regexp"; + } + else { + name = "test-" + t + ++i + ".regexp"; + } + final Result result = Result.valueOf((String)XPath.selectSingleNode(element, "string(expected)")); + final boolean warn = !"false".equals(element.getAttributeValue("warning")); + final boolean info = "true".equals(element.getAttributeValue("info")); + + final String pattern = (String)XPath.selectSingleNode(element, "string(pattern)"); + myMap.put(name, new Test(pattern, result, warn, info)); + if (!"false".equals(element.getAttributeValue("verify"))) { + try { + Pattern.compile(pattern); + if (result == Result.ERR) { + System.out.println("Incorrect FAIL value for " + pattern); + } + } + catch (PatternSyntaxException e) { + if (result == Result.OK) { + System.out.println("Incorrect OK value for " + pattern); + } + } + } + } + + super.setUp(); + + myOut = new ByteArrayOutputStream(); + System.setErr(new PrintStream(myOut)); + } + + @Override + protected String getTestDataPath() { + return super.getTestDataPath() + "/gen/"; + } + + public void testSimple() throws Exception { + doTest("simple/"); + } + + public void testQuantifiers() throws Exception { + doTest("quantifiers/"); + } + + public void testGroups() throws Exception { + doTest("groups/"); + } + + public void testCharclasses() throws Exception { + doTest("charclasses/"); + } + + public void testEscapes() throws Exception { + doTest("escapes/"); + } + + public void testAnchors() throws Exception { + doTest("anchors/"); + } + + public void testNamedchars() throws Exception { + doTest("namedchars/"); + } + + public void testBackrefs() throws Exception { + doTest("backrefs/"); + } + + public void testComplex() throws Exception { + doTest("complex/"); + } + + public void testIncomplete() throws Exception { + doTest("incomplete/"); + } + + public void testRealLife() throws Exception { + doTest("real-life/"); + } + + public void testRegressions() throws Exception { + doTest("regressions/"); + } + + public void testBugs() throws Exception { + doTest("bug/"); + } + + public void testFromXML() throws Exception { + doTest(null); + } + + private void doTest(String prefix) throws IOException { + int n = 0; + int failed = 0; + for (String name : myMap.keySet()) { + if (prefix == null && name.contains("/")) { + continue; + } + if (prefix != null && !name.startsWith(prefix)) { + continue; + } + System.out.print("filename = " + name); + n++; + + final MainParseTest.Test test = myMap.get(name); + try { + myFixture.configureByText(RegExpFileType.INSTANCE, test.pattern); + myFixture.testHighlighting(test.showWarnings, true, test.showInfo); + + if (test.expectedResult == Result.ERR) { + System.out.println(" FAILED. Expression incorrectly parsed OK: " + test.pattern); + failed++; + } + else { + System.out.println(" OK"); + } + } + catch (Throwable e) { + if (test.expectedResult == Result.ERR) { + System.out.println(" OK"); + } + else { + e.printStackTrace(); + System.out.println(" FAILED. Expression = " + test.pattern); + if (myOut.size() > 0) { + String line; + final BufferedReader reader = new BufferedReader(new StringReader(myOut.toString())); + do { + line = reader.readLine(); + } + while (line != null && (line.trim().length() == 0 || line.trim().equals("ERROR:"))); + if (line != null) { + if (line.matches(".*java.lang.Error: junit.framework.AssertionFailedError:.*")) { + System.out.println("ERROR: " + line.replace("java.lang.Error: junit.framework.AssertionFailedError:", "")); + } + } + else { + System.out.println("ERROR: " + myOut.toString()); + } + } + failed++; + } + } + myOut.reset(); + } + + System.out.println(""); + System.out.println(n + " Tests executed, " + failed + " failed"); + + assertFalse(failed > 0); + } +} diff --git a/build.txt b/build.txt index a52161f1f68b..47a4c6d05781 100644 --- a/build.txt +++ b/build.txt @@ -1 +1 @@ -124.SNAPSHOT +124.SNAPSHOT diff --git a/images/src/META-INF/ImagesPlugin.xml b/images/src/META-INF/ImagesPlugin.xml index 0621d51b6e16..b420cdba3076 100644 --- a/images/src/META-INF/ImagesPlugin.xml +++ b/images/src/META-INF/ImagesPlugin.xml @@ -1,143 +1,143 @@ - - - JetBrains - - - - - - - - - - - - - - - - - org.intellij.images.fileTypes.ImageFileTypeManager - org.intellij.images.fileTypes.impl.ImageFileTypeManagerImpl - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + JetBrains + + + + + + + + + + + + + + + + + org.intellij.images.fileTypes.ImageFileTypeManager + org.intellij.images.fileTypes.impl.ImageFileTypeManagerImpl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java index 3b3b18b95665..0ab10734a505 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java @@ -1,2830 +1,2830 @@ -/* - * 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. - */ - -/** - * @author: Eugene Zhuravlev - * Date: Jan 17, 2003 - * Time: 1:42:26 PM - */ -package com.intellij.compiler.impl; - -import com.intellij.CommonBundle; -import com.intellij.compiler.*; -import com.intellij.compiler.make.CacheCorruptedException; -import com.intellij.compiler.make.CacheUtils; -import com.intellij.compiler.make.ChangedConstantsDependencyProcessor; -import com.intellij.compiler.make.DependencyCache; -import com.intellij.compiler.progress.CompilerTask; -import com.intellij.compiler.server.BuildManager; -import com.intellij.compiler.server.CustomBuilderMessageHandler; -import com.intellij.compiler.server.DefaultMessageHandler; -import com.intellij.diagnostic.IdeErrorsDialog; -import com.intellij.diagnostic.PluginException; -import com.intellij.openapi.application.*; -import com.intellij.openapi.compiler.*; -import com.intellij.openapi.compiler.Compiler; -import com.intellij.openapi.compiler.ex.CompileContextEx; -import com.intellij.openapi.compiler.ex.CompilerPathsEx; -import com.intellij.openapi.compiler.generic.GenericCompiler; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.extensions.PluginId; -import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.module.LanguageLevelUtil; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.project.DumbService; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectBundle; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.roots.*; -import com.intellij.openapi.roots.ex.ProjectRootManagerEx; -import com.intellij.openapi.roots.ui.configuration.CommonContentEntriesEditor; -import com.intellij.openapi.roots.ui.configuration.ProjectSettingsService; -import com.intellij.openapi.ui.MessageType; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.util.*; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.registry.Registry; -import com.intellij.openapi.vfs.*; -import com.intellij.openapi.vfs.newvfs.ManagingFS; -import com.intellij.openapi.vfs.newvfs.RefreshQueue; -import com.intellij.openapi.wm.StatusBar; -import com.intellij.openapi.wm.ToolWindowId; -import com.intellij.openapi.wm.ToolWindowManager; -import com.intellij.openapi.wm.WindowManager; -import com.intellij.packaging.artifacts.Artifact; -import com.intellij.packaging.artifacts.ArtifactManager; -import com.intellij.packaging.impl.artifacts.ArtifactImpl; -import com.intellij.packaging.impl.artifacts.ArtifactUtil; -import com.intellij.packaging.impl.compiler.ArtifactCompileScope; -import com.intellij.packaging.impl.compiler.ArtifactCompilerUtil; -import com.intellij.pom.java.LanguageLevel; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.util.Chunk; -import com.intellij.util.Function; -import com.intellij.util.StringBuilderSpinAllocator; -import com.intellij.util.ThrowableRunnable; -import com.intellij.util.concurrency.Semaphore; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.HashMap; -import com.intellij.util.containers.MultiMap; -import com.intellij.util.containers.OrderedSet; -import com.intellij.util.messages.MessageBus; -import gnu.trove.TIntHashSet; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.TestOnly; -import org.jetbrains.jps.api.CmdlineProtoUtil; -import org.jetbrains.jps.api.CmdlineRemoteProto; -import org.jetbrains.jps.api.RequestFuture; -import org.jetbrains.jps.incremental.Utils; - -import javax.swing.*; -import java.io.*; -import java.util.*; -import java.util.concurrent.TimeUnit; - -import static org.jetbrains.jps.api.CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.TargetTypeBuildScope; - -public class CompileDriver { - - private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.CompileDriver"); - // to be used in tests only for debug output - public static volatile boolean ourDebugMode = false; - - private final Project myProject; - private final Map, Pair> myGenerationCompilerModuleToOutputDirMap; // [IntermediateOutputCompiler, Module] -> [ProductionSources, TestSources] - private final String myCachesDirectoryPath; - private boolean myShouldClearOutputDirectory; - - private final Map myModuleOutputPaths = new HashMap(); - private final Map myModuleTestOutputPaths = new HashMap(); - - @NonNls private static final String VERSION_FILE_NAME = "version.dat"; - @NonNls private static final String LOCK_FILE_NAME = "in_progress.dat"; - - private static final boolean GENERATE_CLASSPATH_INDEX = "true".equals(System.getProperty("generate.classpath.index")); - private static final String PROP_PERFORM_INITIAL_REFRESH = "compiler.perform.outputs.refresh.on.start"; - private static final Key REFRESH_DONE_KEY = Key.create("_compiler.initial.refresh.done_"); - - private static final FileProcessingCompilerAdapterFactory FILE_PROCESSING_COMPILER_ADAPTER_FACTORY = new FileProcessingCompilerAdapterFactory() { - public FileProcessingCompilerAdapter create(CompileContext context, FileProcessingCompiler compiler) { - return new FileProcessingCompilerAdapter(context, compiler); - } - }; - private static final FileProcessingCompilerAdapterFactory FILE_PACKAGING_COMPILER_ADAPTER_FACTORY = new FileProcessingCompilerAdapterFactory() { - public FileProcessingCompilerAdapter create(CompileContext context, FileProcessingCompiler compiler) { - return new PackagingCompilerAdapter(context, (PackagingCompiler)compiler); - } - }; - private CompilerFilter myCompilerFilter = CompilerFilter.ALL; - private static final CompilerFilter SOURCE_PROCESSING_ONLY = new CompilerFilter() { - public boolean acceptCompiler(Compiler compiler) { - return compiler instanceof SourceProcessingCompiler; - } - }; - private static final CompilerFilter ALL_EXCEPT_SOURCE_PROCESSING = new CompilerFilter() { - public boolean acceptCompiler(Compiler compiler) { - return !SOURCE_PROCESSING_ONLY.acceptCompiler(compiler); - } - }; - - private Set myAllOutputDirectories; - private static final long ONE_MINUTE_MS = 60L /*sec*/ * 1000L /*millisec*/; - - public CompileDriver(Project project) { - myProject = project; - myCachesDirectoryPath = CompilerPaths.getCacheStoreDirectory(myProject).getPath().replace('/', File.separatorChar); - myShouldClearOutputDirectory = CompilerWorkspaceConfiguration.getInstance(myProject).CLEAR_OUTPUT_DIRECTORY; - - myGenerationCompilerModuleToOutputDirMap = new HashMap, Pair>(); - - if (!useOutOfProcessBuild()) { - final LocalFileSystem lfs = LocalFileSystem.getInstance(); - final IntermediateOutputCompiler[] generatingCompilers = CompilerManager.getInstance(myProject).getCompilers(IntermediateOutputCompiler.class, myCompilerFilter); - final Module[] allModules = ModuleManager.getInstance(myProject).getModules(); - final CompilerConfiguration config = CompilerConfiguration.getInstance(project); - for (Module module : allModules) { - for (IntermediateOutputCompiler compiler : generatingCompilers) { - final VirtualFile productionOutput = lookupVFile(lfs, CompilerPaths.getGenerationOutputPath(compiler, module, false)); - final VirtualFile testOutput = lookupVFile(lfs, CompilerPaths.getGenerationOutputPath(compiler, module, true)); - final Pair pair = new Pair(compiler, module); - final Pair outputs = new Pair(productionOutput, testOutput); - myGenerationCompilerModuleToOutputDirMap.put(pair, outputs); - } - if (config.getAnnotationProcessingConfiguration(module).isEnabled()) { - final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module); - if (path != null) { - lookupVFile(lfs, path); // ensure the file is created and added to VFS - } - } - } - } - } - - public void setCompilerFilter(CompilerFilter compilerFilter) { - myCompilerFilter = compilerFilter == null? CompilerFilter.ALL : compilerFilter; - } - - public void rebuild(CompileStatusNotification callback) { - final CompileScope compileScope; - ProjectCompileScope projectScope = new ProjectCompileScope(myProject); - if (useOutOfProcessBuild()) { - compileScope = projectScope; - } - else { - CompileScope scopeWithArtifacts = ArtifactCompileScope.createScopeWithArtifacts(projectScope, ArtifactUtil.getArtifactWithOutputPaths(myProject), false); - compileScope = addAdditionalRoots(scopeWithArtifacts, ALL_EXCEPT_SOURCE_PROCESSING); - } - doRebuild(callback, null, true, compileScope); - } - - public void make(CompileScope scope, CompileStatusNotification callback) { - if (!useOutOfProcessBuild()) { - scope = addAdditionalRoots(scope, ALL_EXCEPT_SOURCE_PROCESSING); - } - if (validateCompilerConfiguration(scope, false)) { - startup(scope, false, false, callback, null, true); - } - else { - callback.finished(true, 0, 0, DummyCompileContext.getInstance()); - } - } - - public boolean isUpToDate(CompileScope scope) { - if (LOG.isDebugEnabled()) { - LOG.debug("isUpToDate operation started"); - } - if (!useOutOfProcessBuild()) { - scope = addAdditionalRoots(scope, ALL_EXCEPT_SOURCE_PROCESSING); - } - - final CompilerTask task = new CompilerTask(myProject, "Classes up-to-date check", true, false); - final DependencyCache cache = useOutOfProcessBuild()? null : createDependencyCache(); - final CompileContextImpl compileContext = new CompileContextImpl(myProject, task, scope, cache, true, false); - - if (!useOutOfProcessBuild()) { - checkCachesVersion(compileContext, ManagingFS.getInstance().getCreationTimestamp()); - if (compileContext.isRebuildRequested()) { - if (LOG.isDebugEnabled()) { - LOG.debug("Rebuild requested, up-to-date=false"); - } - return false; - } - - for (Map.Entry, Pair> entry : myGenerationCompilerModuleToOutputDirMap.entrySet()) { - final Pair outputs = entry.getValue(); - final Pair key = entry.getKey(); - final Module module = key.getSecond(); - compileContext.assignModule(outputs.getFirst(), module, false, key.getFirst()); - compileContext.assignModule(outputs.getSecond(), module, true, key.getFirst()); - } - } - - final Ref result = new Ref(); - - final Runnable compileWork; - if (useOutOfProcessBuild()) { - compileWork = new Runnable() { - public void run() { - final ProgressIndicator indicator = compileContext.getProgressIndicator(); - if (indicator.isCanceled() || myProject.isDisposed()) { - return; - } - try { - final Collection paths = CompileScopeUtil.fetchFiles(compileContext); - List scopes = new ArrayList(); - if (paths.isEmpty()) { - if (!compileContext.isRebuild() && !CompileScopeUtil.allProjectModulesAffected(compileContext)) { - CompileScopeUtil.addScopesForModules(Arrays.asList(compileContext.getCompileScope().getAffectedModules()), scopes); - } - else { - scopes.addAll(CmdlineProtoUtil.createAllModulesScopes()); - } - for (BuildTargetScopeProvider provider : BuildTargetScopeProvider.EP_NAME.getExtensions()) { - scopes = CompileScopeUtil.mergeScopes(scopes, provider.getBuildTargetScopes(compileContext.getCompileScope(), myCompilerFilter, myProject)); - } - } - final RequestFuture future = compileInExternalProcess(compileContext, scopes, paths, true); - if (future != null) { - while (!future.waitFor(200L , TimeUnit.MILLISECONDS)) { - if (indicator.isCanceled()) { - future.cancel(false); - } - } - } - } - catch (Throwable e) { - LOG.error(e); - } - finally { - result.set(COMPILE_SERVER_BUILD_STATUS.get(compileContext)); - CompilerCacheManager.getInstance(myProject).flushCaches(); - } - } - }; - } - else { - compileWork = new Runnable() { - public void run() { - try { - myAllOutputDirectories = getAllOutputDirectories(compileContext); - // need this for updating zip archives experiment, uncomment if the feature is turned on - //myOutputFinder = new OutputPathFinder(myAllOutputDirectories); - result.set(doCompile(compileContext, false, false, true)); - } - finally { - CompilerCacheManager.getInstance(myProject).flushCaches(); - } - } - }; - } - task.start(compileWork, null); - - if (LOG.isDebugEnabled()) { - LOG.debug("isUpToDate operation finished"); - } - - return ExitStatus.UP_TO_DATE.equals(result.get()); - } - - private DependencyCache createDependencyCache() { - return new DependencyCache(myCachesDirectoryPath + File.separator + ".dependency-info"); - } - - public void compile(CompileScope scope, CompileStatusNotification callback, boolean clearingOutputDirsPossible) { - myShouldClearOutputDirectory &= clearingOutputDirsPossible; - if (containsFileIndexScopes(scope)) { - scope = addAdditionalRoots(scope, ALL_EXCEPT_SOURCE_PROCESSING); - } - if (validateCompilerConfiguration(scope, false)) { - startup(scope, false, true, callback, null, true); - } - else { - callback.finished(true, 0, 0, DummyCompileContext.getInstance()); - } - } - - private static boolean containsFileIndexScopes(CompileScope scope) { - if (scope instanceof CompositeScope) { - for (CompileScope childScope : ((CompositeScope)scope).getScopes()) { - if (containsFileIndexScopes(childScope)) { - return true; - } - } - } - return scope instanceof FileIndexCompileScope; - } - - private static class CompileStatus { - final int CACHE_FORMAT_VERSION; - final boolean COMPILATION_IN_PROGRESS; - final long VFS_CREATION_STAMP; - - private CompileStatus(int cacheVersion, boolean isCompilationInProgress, long vfsStamp) { - CACHE_FORMAT_VERSION = cacheVersion; - COMPILATION_IN_PROGRESS = isCompilationInProgress; - VFS_CREATION_STAMP = vfsStamp; - } - } - - private CompileStatus readStatus() { - final boolean isInProgress = getLockFile().exists(); - int version = -1; - long vfsStamp = -1L; - try { - final File versionFile = new File(myCachesDirectoryPath, VERSION_FILE_NAME); - DataInputStream in = new DataInputStream(new FileInputStream(versionFile)); - try { - version = in.readInt(); - try { - vfsStamp = in.readLong(); - } - catch (IOException ignored) { - } - } - finally { - in.close(); - } - } - catch (FileNotFoundException e) { - // ignore - } - catch (IOException e) { - LOG.info(e); // may happen in case of IDEA crashed and the file is not written properly - return null; - } - return new CompileStatus(version, isInProgress, vfsStamp); - } - - private void writeStatus(CompileStatus status, CompileContext context) { - final File statusFile = new File(myCachesDirectoryPath, VERSION_FILE_NAME); - - final File lockFile = getLockFile(); - try { - FileUtil.createIfDoesntExist(statusFile); - DataOutputStream out = new DataOutputStream(new FileOutputStream(statusFile)); - try { - out.writeInt(status.CACHE_FORMAT_VERSION); - out.writeLong(status.VFS_CREATION_STAMP); - } - finally { - out.close(); - } - if (status.COMPILATION_IN_PROGRESS) { - FileUtil.createIfDoesntExist(lockFile); - } - else { - deleteFile(lockFile); - } - } - catch (IOException e) { - context.addMessage(CompilerMessageCategory.ERROR, CompilerBundle.message("compiler.error.exception", e.getMessage()), null, -1, -1); - } - } - - private File getLockFile() { - return new File(CompilerPaths.getCompilerSystemDirectory(myProject), LOCK_FILE_NAME); - } - - private void doRebuild(CompileStatusNotification callback, - CompilerMessage message, - final boolean checkCachesVersion, - final CompileScope compileScope) { - if (validateCompilerConfiguration(compileScope, !useOutOfProcessBuild())) { - startup(compileScope, true, false, callback, message, checkCachesVersion); - } - else { - callback.finished(true, 0, 0, DummyCompileContext.getInstance()); - } - } - - private CompileScope addAdditionalRoots(CompileScope originalScope, final CompilerFilter filter) { - CompileScope scope = attachIntermediateOutputDirectories(originalScope, filter); - - final AdditionalCompileScopeProvider[] scopeProviders = Extensions.getExtensions(AdditionalCompileScopeProvider.EXTENSION_POINT_NAME); - CompileScope baseScope = scope; - for (AdditionalCompileScopeProvider scopeProvider : scopeProviders) { - final CompileScope additionalScope = scopeProvider.getAdditionalScope(baseScope, filter, myProject); - if (additionalScope != null) { - scope = new CompositeScope(scope, additionalScope); - } - } - return scope; - } - - private CompileScope attachIntermediateOutputDirectories(CompileScope originalScope, CompilerFilter filter) { - CompileScope scope = originalScope; - final Set affected = new HashSet(Arrays.asList(originalScope.getAffectedModules())); - for (Map.Entry, Pair> entry : myGenerationCompilerModuleToOutputDirMap.entrySet()) { - final Module module = entry.getKey().getSecond(); - if (affected.contains(module) && filter.acceptCompiler(entry.getKey().getFirst())) { - final Pair outputs = entry.getValue(); - scope = new CompositeScope(scope, new FileSetCompileScope(Arrays.asList(outputs.getFirst(), outputs.getSecond()), new Module[]{module})); - } - } - return scope; - } - - private void attachAnnotationProcessorsOutputDirectories(CompileContextEx context) { - final LocalFileSystem lfs = LocalFileSystem.getInstance(); - final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject); - final Set affected = new HashSet(Arrays.asList(context.getCompileScope().getAffectedModules())); - for (Module module : affected) { - if (!config.getAnnotationProcessingConfiguration(module).isEnabled()) { - continue; - } - final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module); - if (path == null) { - continue; - } - final VirtualFile vFile = lfs.findFileByPath(path); - if (vFile == null) { - continue; - } - if (ModuleRootManager.getInstance(module).getFileIndex().isInSourceContent(vFile)) { - // no need to add, is already marked as source - continue; - } - context.addScope(new FileSetCompileScope(Collections.singletonList(vFile), new Module[]{module})); - context.assignModule(vFile, module, false, null); - } - } - - @Nullable - private RequestFuture compileInExternalProcess(final @NotNull CompileContextImpl compileContext, - @NotNull List scopes, - final @NotNull Collection paths, - final boolean onlyCheckUpToDate) - throws Exception { - final CompileScope scope = compileContext.getCompileScope(); - // need to pass scope's user data to server - final Map builderParams; - if (onlyCheckUpToDate) { - builderParams = Collections.emptyMap(); - } - else { - final Map exported = scope.exportUserData(); - if (!exported.isEmpty()) { - builderParams = new HashMap(); - for (Map.Entry entry : exported.entrySet()) { - final String _key = entry.getKey().toString(); - final String _value = entry.getValue().toString(); - builderParams.put(_key, _value); - } - } - else { - builderParams = Collections.emptyMap(); - } - } - - final MessageBus messageBus = myProject.getMessageBus(); - - final BuildManager buildManager = BuildManager.getInstance(); - buildManager.cancelAutoMakeTasks(myProject); - return buildManager.scheduleBuild(myProject, compileContext.isRebuild(), compileContext.isMake(), onlyCheckUpToDate, scopes, paths, builderParams, new DefaultMessageHandler(myProject) { - - @Override - public void buildStarted(UUID sessionId) { - } - - @Override - public void sessionTerminated(final UUID sessionId) { - if (compileContext.shouldUpdateProblemsView()) { - final ProblemsView view = ProblemsViewImpl.SERVICE.getInstance(myProject); - view.clearProgress(); - view.clearOldMessages(compileContext.getCompileScope(), compileContext.getSessionId()); - } - } - - @Override - public void handleFailure(UUID sessionId, CmdlineRemoteProto.Message.Failure failure) { - compileContext.addMessage(CompilerMessageCategory.ERROR, failure.getDescription(), null, -1, -1); - final String trace = failure.getStacktrace(); - if (trace != null) { - LOG.info(trace); - System.out.println(trace); - } - compileContext.putUserData(COMPILE_SERVER_BUILD_STATUS, ExitStatus.ERRORS); - } - - @Override - protected void handleCompileMessage(UUID sessionId, CmdlineRemoteProto.Message.BuilderMessage.CompileMessage message) { - final CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind kind = message.getKind(); - //System.out.println(compilerMessage.getText()); - final String messageText = message.getText(); - if (kind == CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind.PROGRESS) { - final ProgressIndicator indicator = compileContext.getProgressIndicator(); - indicator.setText(messageText); - if (message.hasDone()) { - indicator.setFraction(message.getDone()); - } - } - else { - final CompilerMessageCategory category = kind == CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind.ERROR ? CompilerMessageCategory.ERROR - : kind == CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind.WARNING ? CompilerMessageCategory.WARNING : CompilerMessageCategory.INFORMATION; - - String sourceFilePath = message.hasSourceFilePath() ? message.getSourceFilePath() : null; - if (sourceFilePath != null) { - sourceFilePath = FileUtil.toSystemIndependentName(sourceFilePath); - } - final long line = message.hasLine() ? message.getLine() : -1; - final long column = message.hasColumn() ? message.getColumn() : -1; - final String srcUrl = sourceFilePath != null ? VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, sourceFilePath) : null; - compileContext.addMessage(category, messageText, srcUrl, (int)line, (int)column); - } - } - - @Override - protected void handleBuildEvent(UUID sessionId, CmdlineRemoteProto.Message.BuilderMessage.BuildEvent event) { - final CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Type eventType = event.getEventType(); - switch (eventType) { - case FILES_GENERATED: - final List generated = event.getGeneratedFilesList(); - final CompilationStatusListener publisher = messageBus.syncPublisher(CompilerTopics.COMPILATION_STATUS); - for (CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.GeneratedFile generatedFile : generated) { - final String root = FileUtil.toSystemIndependentName(generatedFile.getOutputRoot()); - final String relativePath = FileUtil.toSystemIndependentName(generatedFile.getRelativePath()); - publisher.fileGenerated(root, relativePath); - } - break; - case BUILD_COMPLETED: - ExitStatus status = ExitStatus.SUCCESS; - if (event.hasCompletionStatus()) { - final CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status completionStatus = event.getCompletionStatus(); - switch (completionStatus) { - case CANCELED: - status = ExitStatus.CANCELLED; - break; - case ERRORS: - status = ExitStatus.ERRORS; - break; - case SUCCESS: - status = ExitStatus.SUCCESS; - break; - case UP_TO_DATE: - status = ExitStatus.UP_TO_DATE; - break; - } - } - compileContext.putUserDataIfAbsent(COMPILE_SERVER_BUILD_STATUS, status); - break; - case CUSTOM_BUILDER_MESSAGE: - if (event.hasCustomBuilderMessage()) { - CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.CustomBuilderMessage message = event.getCustomBuilderMessage(); - messageBus.syncPublisher(CustomBuilderMessageHandler.TOPIC).messageReceived(message.getBuilderId(), message.getMessageType(), - message.getMessageText()); - } - break; - } - } - }); - } - - - private static final Key COMPILE_SERVER_BUILD_STATUS = Key.create("COMPILE_SERVER_BUILD_STATUS"); - - private void startup(final CompileScope scope, - final boolean isRebuild, - final boolean forceCompile, - final CompileStatusNotification callback, - final CompilerMessage message, - final boolean checkCachesVersion) { - ApplicationManager.getApplication().assertIsDispatchThread(); - - final boolean useExtProcessBuild = useOutOfProcessBuild(); - - final String contentName = - forceCompile ? CompilerBundle.message("compiler.content.name.compile") : CompilerBundle.message("compiler.content.name.make"); - final CompilerTask compileTask = new CompilerTask(myProject, contentName, ApplicationManager.getApplication().isUnitTestMode(), true); - - StatusBar.Info.set("", myProject, "Compiler"); - if (useExtProcessBuild) { - // ensure the project model seen by build process is up-to-date - myProject.save(); - } - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - FileDocumentManager.getInstance().saveAllDocuments(); - - final DependencyCache dependencyCache = useExtProcessBuild ? null: createDependencyCache(); - final CompileContextImpl compileContext = - new CompileContextImpl(myProject, compileTask, scope, dependencyCache, !isRebuild && !forceCompile, isRebuild); - - if (!useExtProcessBuild) { - for (Map.Entry, Pair> entry : myGenerationCompilerModuleToOutputDirMap.entrySet()) { - final Pair outputs = entry.getValue(); - final Pair key = entry.getKey(); - final Module module = key.getSecond(); - compileContext.assignModule(outputs.getFirst(), module, false, key.getFirst()); - compileContext.assignModule(outputs.getSecond(), module, true, key.getFirst()); - } - attachAnnotationProcessorsOutputDirectories(compileContext); - } - - final Runnable compileWork; - if (useExtProcessBuild) { - compileWork = new Runnable() { - public void run() { - final ProgressIndicator indicator = compileContext.getProgressIndicator(); - if (indicator.isCanceled() || myProject.isDisposed()) { - if (callback != null) { - callback.finished(true, 0, 0, compileContext); - } - return; - } - try { - LOG.info("COMPILATION STARTED (BUILD PROCESS)"); - if (message != null) { - compileContext.addMessage(message); - } - if (!executeCompileTasks(compileContext, true)) { - COMPILE_SERVER_BUILD_STATUS.set(compileContext, ExitStatus.CANCELLED); - return; - } - - final Collection paths = CompileScopeUtil.fetchFiles(compileContext); - List scopes = new ArrayList(); - if (paths.isEmpty()) { - if (!isRebuild && !CompileScopeUtil.allProjectModulesAffected(compileContext)) { - CompileScopeUtil.addScopesForModules(Arrays.asList(compileContext.getCompileScope().getAffectedModules()), scopes); - } - else { - scopes.addAll(CmdlineProtoUtil.createAllModulesScopes()); - } - for (BuildTargetScopeProvider provider : BuildTargetScopeProvider.EP_NAME.getExtensions()) { - scopes = CompileScopeUtil.mergeScopes(scopes, provider.getBuildTargetScopes(scope, myCompilerFilter, myProject)); - } - } - final RequestFuture future = compileInExternalProcess(compileContext, scopes, paths, false); - if (future != null) { - while (!future.waitFor(200L , TimeUnit.MILLISECONDS)) { - if (indicator.isCanceled()) { - future.cancel(false); - } - } - if (!executeCompileTasks(compileContext, false)) { - COMPILE_SERVER_BUILD_STATUS.set(compileContext, ExitStatus.CANCELLED); - return; - } - } - } - catch (Throwable e) { - LOG.error(e); // todo - } - finally { - CompilerCacheManager.getInstance(myProject).flushCaches(); - - final long duration = notifyCompilationCompleted(compileContext, callback, COMPILE_SERVER_BUILD_STATUS.get(compileContext)); - CompilerUtil.logDuration( - "\tCOMPILATION FINISHED (BUILD PROCESS); Errors: " + - compileContext.getMessageCount(CompilerMessageCategory.ERROR) + - "; warnings: " + - compileContext.getMessageCount(CompilerMessageCategory.WARNING), - duration - ); - - // refresh on output roots is required in order for the order enumerator to see all roots via VFS - final Set outputs = new HashSet(); - for (final String path : CompilerPathsEx.getOutputPaths(ModuleManager.getInstance(myProject).getModules())) { - outputs.add(new File(path)); - } - if (!outputs.isEmpty()) { - LocalFileSystem.getInstance().refreshIoFiles(outputs, true, false, null); - } - } - } - }; - } - else { - compileWork = new Runnable() { - public void run() { - if (compileContext.getProgressIndicator().isCanceled()) { - if (callback != null) { - callback.finished(true, 0, 0, compileContext); - } - return; - } - try { - if (myProject.isDisposed()) { - return; - } - LOG.info("COMPILATION STARTED"); - if (message != null) { - compileContext.addMessage(message); - } - TranslatingCompilerFilesMonitor.getInstance().ensureInitializationCompleted(myProject, compileContext.getProgressIndicator()); - doCompile(compileContext, isRebuild, forceCompile, callback, checkCachesVersion); - } - finally { - FileUtil.delete(CompilerPaths.getRebuildMarkerFile(myProject)); - } - } - }; - } - - compileTask.start(compileWork, new Runnable() { - public void run() { - if (isRebuild) { - final int rv = Messages.showOkCancelDialog( - myProject, "You are about to rebuild the whole project.\nRun 'Make Project' instead?", "Confirm Project Rebuild", - "Make", "Rebuild", Messages.getQuestionIcon() - ); - if (rv == 0 /*yes, please, do run make*/) { - startup(scope, false, false, callback, null, checkCachesVersion); - return; - } - } - startup(scope, isRebuild, forceCompile, callback, message, checkCachesVersion); - } - }); - } - - @Nullable @TestOnly - public static ExitStatus getExternalBuildExitStatus(CompileContext context) { - return context.getUserData(COMPILE_SERVER_BUILD_STATUS); - } - - private void doCompile(final CompileContextImpl compileContext, - final boolean isRebuild, - final boolean forceCompile, - final CompileStatusNotification callback, - final boolean checkCachesVersion) { - ExitStatus status = ExitStatus.ERRORS; - boolean wereExceptions = false; - final long vfsTimestamp = (ManagingFS.getInstance()).getCreationTimestamp(); - try { - if (checkCachesVersion) { - checkCachesVersion(compileContext, vfsTimestamp); - if (compileContext.isRebuildRequested()) { - return; - } - } - writeStatus(new CompileStatus(CompilerConfigurationImpl.DEPENDENCY_FORMAT_VERSION, true, vfsTimestamp), compileContext); - if (compileContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) { - return; - } - - myAllOutputDirectories = getAllOutputDirectories(compileContext); - status = doCompile(compileContext, isRebuild, forceCompile, false); - } - catch (Throwable ex) { - if (ApplicationManager.getApplication().isUnitTestMode()) { - throw new RuntimeException(ex); - } - wereExceptions = true; - final PluginId pluginId = IdeErrorsDialog.findPluginId(ex); - - final StringBuilder message = new StringBuilder(); - message.append("Internal error"); - if (pluginId != null) { - message.append(" (Plugin: ").append(pluginId).append(")"); - } - message.append(": ").append(ex.getMessage()); - compileContext.addMessage(CompilerMessageCategory.ERROR, message.toString(), null, -1, -1); - - if (pluginId != null) { - throw new PluginException(ex, pluginId); - } - throw new RuntimeException(ex); - } - finally { - dropDependencyCache(compileContext); - CompilerCacheManager.getInstance(myProject).flushCaches(); - if (compileContext.isRebuildRequested()) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - public void run() { - final CompilerMessageImpl msg = new CompilerMessageImpl(myProject, CompilerMessageCategory.INFORMATION, compileContext.getRebuildReason()); - doRebuild(callback, msg, false, compileContext.getCompileScope()); - } - }, ModalityState.NON_MODAL); - } - else { - if (!myProject.isDisposed()) { - writeStatus(new CompileStatus(CompilerConfigurationImpl.DEPENDENCY_FORMAT_VERSION, wereExceptions, vfsTimestamp), compileContext); - } - final long duration = notifyCompilationCompleted(compileContext, callback, status); - CompilerUtil.logDuration( - "\tCOMPILATION FINISHED; Errors: " + - compileContext.getMessageCount(CompilerMessageCategory.ERROR) + - "; warnings: " + - compileContext.getMessageCount(CompilerMessageCategory.WARNING), - duration - ); - } - } - } - - /** @noinspection SSBasedInspection*/ - private long notifyCompilationCompleted(final CompileContextImpl compileContext, final CompileStatusNotification callback, final ExitStatus _status) { - final long duration = System.currentTimeMillis() - compileContext.getStartCompilationStamp(); - SwingUtilities.invokeLater(new Runnable() { - public void run() { - int errorCount = 0; - int warningCount = 0; - try { - errorCount = compileContext.getMessageCount(CompilerMessageCategory.ERROR); - warningCount = compileContext.getMessageCount(CompilerMessageCategory.WARNING); - if (!myProject.isDisposed()) { - final String statusMessage = createStatusMessage(_status, warningCount, errorCount, duration); - final MessageType messageType = errorCount > 0 ? MessageType.ERROR : warningCount > 0 ? MessageType.WARNING : MessageType.INFO; - if (duration > ONE_MINUTE_MS) { - ToolWindowManager.getInstance(myProject).notifyByBalloon(ToolWindowId.MESSAGES_WINDOW, messageType, statusMessage); - } - CompilerManager.NOTIFICATION_GROUP.createNotification(statusMessage, messageType).notify(myProject); - if (_status != ExitStatus.UP_TO_DATE && compileContext.getMessageCount(null) > 0) { - compileContext.addMessage(CompilerMessageCategory.INFORMATION, statusMessage, null, -1, -1); - } - } - } - finally { - if (callback != null) { - callback.finished(_status == ExitStatus.CANCELLED, errorCount, warningCount, compileContext); - } - } - } - }); - return duration; - } - - private void checkCachesVersion(final CompileContextImpl compileContext, final long currentVFSTimestamp) { - if (CompilerPaths.getRebuildMarkerFile(compileContext.getProject()).exists()) { - compileContext.requestRebuildNextTime("Compiler caches are out of date, project rebuild is required"); - return; - } - final CompileStatus compileStatus = readStatus(); - if (compileStatus == null) { - compileContext.requestRebuildNextTime(CompilerBundle.message("error.compiler.caches.corrupted")); - } - else if (compileStatus.CACHE_FORMAT_VERSION != -1 && - compileStatus.CACHE_FORMAT_VERSION != CompilerConfigurationImpl.DEPENDENCY_FORMAT_VERSION) { - compileContext.requestRebuildNextTime(CompilerBundle.message("error.caches.old.format")); - } - else if (compileStatus.COMPILATION_IN_PROGRESS) { - compileContext.requestRebuildNextTime(CompilerBundle.message("error.previous.compilation.failed")); - } - else if (compileStatus.VFS_CREATION_STAMP >= 0L){ - if (currentVFSTimestamp != compileStatus.VFS_CREATION_STAMP) { - compileContext.requestRebuildNextTime(CompilerBundle.message("error.vfs.was.rebuilt")); - } - } - } - - private static String createStatusMessage(final ExitStatus status, final int warningCount, final int errorCount, long duration) { - String message; - if (status == ExitStatus.CANCELLED) { - message = CompilerBundle.message("status.compilation.aborted"); - } - else if (status == ExitStatus.UP_TO_DATE) { - message = CompilerBundle.message("status.all.up.to.date"); - } - else { - if (status == ExitStatus.SUCCESS) { - message = warningCount > 0 - ? CompilerBundle.message("status.compilation.completed.successfully.with.warnings", warningCount) - : CompilerBundle.message("status.compilation.completed.successfully"); - } - else { - message = CompilerBundle.message("status.compilation.completed.successfully.with.warnings.and.errors", errorCount, warningCount); - } - message = message + " in " + Utils.formatDuration(duration); - } - return message; - } - - private ExitStatus doCompile(final CompileContextEx context, boolean isRebuild, final boolean forceCompile, final boolean onlyCheckStatus) { - try { - if (isRebuild) { - deleteAll(context); - } - else if (forceCompile) { - if (myShouldClearOutputDirectory) { - clearAffectedOutputPathsIfPossible(context); - } - } - if (context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { - if (LOG.isDebugEnabled()) { - logErrorMessages(context); - } - return ExitStatus.ERRORS; - } - - if (!onlyCheckStatus) { - if (!executeCompileTasks(context, true)) { - if (LOG.isDebugEnabled()) { - LOG.debug("Compilation cancelled"); - } - return ExitStatus.CANCELLED; - } - } - - if (context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { - if (LOG.isDebugEnabled()) { - logErrorMessages(context); - } - return ExitStatus.ERRORS; - } - - boolean needRecalcOutputDirs = false; - if (Registry.is(PROP_PERFORM_INITIAL_REFRESH) || !Boolean.valueOf(REFRESH_DONE_KEY.get(myProject, Boolean.FALSE))) { - REFRESH_DONE_KEY.set(myProject, Boolean.TRUE); - final long refreshStart = System.currentTimeMillis(); - - //need this to make sure the VFS is built - final List outputsToRefresh = new ArrayList(); - - final VirtualFile[] all = context.getAllOutputDirectories(); - - final ProgressIndicator progressIndicator = context.getProgressIndicator(); - - //final int totalCount = all.length + myGenerationCompilerModuleToOutputDirMap.size() * 2; - progressIndicator.pushState(); - progressIndicator.setText("Inspecting output directories..."); - try { - for (VirtualFile output : all) { - if (output.isValid()) { - walkChildren(output, context); - } - else { - needRecalcOutputDirs = true; - final File file = new File(output.getPath()); - if (!file.exists()) { - final boolean created = file.mkdirs(); - if (!created) { - context.addMessage(CompilerMessageCategory.ERROR, "Failed to create output directory " + file.getPath(), null, 0, 0); - return ExitStatus.ERRORS; - } - } - output = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); - if (output == null) { - context.addMessage(CompilerMessageCategory.ERROR, "Failed to locate output directory " + file.getPath(), null, 0, 0); - return ExitStatus.ERRORS; - } - } - outputsToRefresh.add(output); - } - for (Pair pair : myGenerationCompilerModuleToOutputDirMap.keySet()) { - final Pair generated = myGenerationCompilerModuleToOutputDirMap.get(pair); - walkChildren(generated.getFirst(), context); - outputsToRefresh.add(generated.getFirst()); - walkChildren(generated.getSecond(), context); - outputsToRefresh.add(generated.getSecond()); - } - - RefreshQueue.getInstance().refresh(false, true, null, outputsToRefresh); - if (progressIndicator.isCanceled()) { - return ExitStatus.CANCELLED; - } - } - finally { - progressIndicator.popState(); - } - - final long initialRefreshTime = System.currentTimeMillis() - refreshStart; - CompilerUtil.logDuration("Initial VFS refresh", initialRefreshTime); - } - - //DumbService.getInstance(myProject).waitForSmartMode(); - final Semaphore semaphore = new Semaphore(); - semaphore.down(); - DumbService.getInstance(myProject).runWhenSmart(new Runnable() { - public void run() { - semaphore.up(); - } - }); - while (!semaphore.waitFor(500)) { - if (context.getProgressIndicator().isCanceled()) { - return ExitStatus.CANCELLED; - } - } - - if (needRecalcOutputDirs) { - context.recalculateOutputDirs(); - } - - boolean didSomething = false; - - final CompilerManager compilerManager = CompilerManager.getInstance(myProject); - GenericCompilerRunner runner = new GenericCompilerRunner(context, isRebuild, onlyCheckStatus, - compilerManager.getCompilers(GenericCompiler.class, myCompilerFilter)); - try { - didSomething |= generateSources(compilerManager, context, forceCompile, onlyCheckStatus); - - didSomething |= invokeFileProcessingCompilers(compilerManager, context, SourceInstrumentingCompiler.class, - FILE_PROCESSING_COMPILER_ADAPTER_FACTORY, forceCompile, true, onlyCheckStatus); - - didSomething |= invokeFileProcessingCompilers(compilerManager, context, SourceProcessingCompiler.class, - FILE_PROCESSING_COMPILER_ADAPTER_FACTORY, forceCompile, true, onlyCheckStatus); - - final CompileScope intermediateSources = attachIntermediateOutputDirectories(new CompositeScope(CompileScope.EMPTY_ARRAY) { - @NotNull - public Module[] getAffectedModules() { - return context.getCompileScope().getAffectedModules(); - } - }, SOURCE_PROCESSING_ONLY); - context.addScope(intermediateSources); - - didSomething |= translate(context, compilerManager, forceCompile, isRebuild, onlyCheckStatus); - - didSomething |= invokeFileProcessingCompilers(compilerManager, context, ClassInstrumentingCompiler.class, - FILE_PROCESSING_COMPILER_ADAPTER_FACTORY, isRebuild, false, onlyCheckStatus); - didSomething |= runner.invokeCompilers(GenericCompiler.CompileOrderPlace.CLASS_INSTRUMENTING); - - // explicitly passing forceCompile = false because in scopes that is narrower than ProjectScope it is impossible - // to understand whether the class to be processed is in scope or not. Otherwise compiler may process its items even if - // there were changes in completely independent files. - didSomething |= invokeFileProcessingCompilers(compilerManager, context, ClassPostProcessingCompiler.class, - FILE_PROCESSING_COMPILER_ADAPTER_FACTORY, isRebuild, false, onlyCheckStatus); - didSomething |= runner.invokeCompilers(GenericCompiler.CompileOrderPlace.CLASS_POST_PROCESSING); - - didSomething |= invokeFileProcessingCompilers(compilerManager, context, PackagingCompiler.class, - FILE_PACKAGING_COMPILER_ADAPTER_FACTORY, - isRebuild, false, onlyCheckStatus); - didSomething |= runner.invokeCompilers(GenericCompiler.CompileOrderPlace.PACKAGING); - - didSomething |= invokeFileProcessingCompilers(compilerManager, context, Validator.class, FILE_PROCESSING_COMPILER_ADAPTER_FACTORY, - forceCompile, true, onlyCheckStatus); - didSomething |= runner.invokeCompilers(GenericCompiler.CompileOrderPlace.VALIDATING); - } - catch (ExitException e) { - if (LOG.isDebugEnabled()) { - LOG.debug(e); - logErrorMessages(context); - } - return e.getExitStatus(); - } - finally { - // drop in case it has not been dropped yet. - dropDependencyCache(context); - final VirtualFile[] allOutputDirs = context.getAllOutputDirectories(); - - if (didSomething && GENERATE_CLASSPATH_INDEX) { - CompilerUtil.runInContext(context, "Generating classpath index...", new ThrowableRunnable(){ - public void run() { - int count = 0; - for (VirtualFile file : allOutputDirs) { - context.getProgressIndicator().setFraction((double)++count / allOutputDirs.length); - createClasspathIndex(file); - } - } - }); - } - - } - - if (!onlyCheckStatus) { - if (!executeCompileTasks(context, false)) { - return ExitStatus.CANCELLED; - } - final int constantSearchesCount = ChangedConstantsDependencyProcessor.getConstantSearchesCount(context); - LOG.debug("Constants searches: " + constantSearchesCount); - } - - if (context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { - if (LOG.isDebugEnabled()) { - logErrorMessages(context); - } - return ExitStatus.ERRORS; - } - if (!didSomething) { - return ExitStatus.UP_TO_DATE; - } - return ExitStatus.SUCCESS; - } - catch (ProcessCanceledException e) { - return ExitStatus.CANCELLED; - } - } - - private void clearAffectedOutputPathsIfPossible(final CompileContextEx context) { - final List scopeOutputs = new ReadAction>() { - protected void run(final Result> result) { - final MultiMap outputToModulesMap = new MultiMap(); - for (Module module : ModuleManager.getInstance(myProject).getModules()) { - final CompilerModuleExtension compilerModuleExtension = CompilerModuleExtension.getInstance(module); - if (compilerModuleExtension == null) { - continue; - } - final String outputPathUrl = compilerModuleExtension.getCompilerOutputUrl(); - if (outputPathUrl != null) { - final String path = VirtualFileManager.extractPath(outputPathUrl); - outputToModulesMap.putValue(new File(path), module); - } - - final String outputPathForTestsUrl = compilerModuleExtension.getCompilerOutputUrlForTests(); - if (outputPathForTestsUrl != null) { - final String path = VirtualFileManager.extractPath(outputPathForTestsUrl); - outputToModulesMap.putValue(new File(path), module); - } - } - final Set affectedModules = new HashSet(Arrays.asList(context.getCompileScope().getAffectedModules())); - List scopeOutputs = new ArrayList(affectedModules.size() * 2); - for (File output : outputToModulesMap.keySet()) { - if (affectedModules.containsAll(outputToModulesMap.get(output))) { - scopeOutputs.add(output); - } - } - - final Set artifactsToBuild = ArtifactCompileScope.getArtifactsToBuild(myProject, context.getCompileScope(), true); - for (Artifact artifact : artifactsToBuild) { - final String outputFilePath = ((ArtifactImpl)artifact).getOutputDirectoryPathToCleanOnRebuild(); - if (outputFilePath != null) { - scopeOutputs.add(new File(FileUtil.toSystemDependentName(outputFilePath))); - } - } - result.setResult(scopeOutputs); - } - }.execute().getResultObject(); - if (scopeOutputs.size() > 0) { - CompilerUtil.runInContext(context, CompilerBundle.message("progress.clearing.output"), new ThrowableRunnable() { - public void run() { - CompilerUtil.clearOutputDirectories(scopeOutputs); - } - }); - } - } - - private static void logErrorMessages(final CompileContext context) { - final CompilerMessage[] errors = context.getMessages(CompilerMessageCategory.ERROR); - if (errors.length > 0) { - LOG.debug("Errors reported: "); - for (CompilerMessage error : errors) { - LOG.debug("\t" + error.getMessage()); - } - } - } - - private static void walkChildren(VirtualFile from, final CompileContext context) { - VfsUtilCore.visitChildrenRecursively(from, new VirtualFileVisitor() { - @Override - public boolean visitFile(@NotNull VirtualFile file) { - if (file.isDirectory()) { - context.getProgressIndicator().checkCanceled(); - context.getProgressIndicator().setText2(file.getPresentableUrl()); - } - return true; - } - }); - } - - private static void createClasspathIndex(final VirtualFile file) { - try { - BufferedWriter writer = new BufferedWriter(new FileWriter(new File(VfsUtilCore.virtualToIoFile(file), "classpath.index"))); - try { - writeIndex(writer, file, file); - } - finally { - writer.close(); - } - } - catch (IOException e) { - // Ignore. Failed to create optional classpath index - } - } - - private static void writeIndex(final BufferedWriter writer, final VirtualFile root, final VirtualFile file) throws IOException { - VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() { - @Override - public boolean visitFile(@NotNull VirtualFile file) { - try { - writer.write(VfsUtilCore.getRelativePath(file, root, '/')); - writer.write('\n'); - return true; - } - catch (IOException e) { - throw new VisitorException(e); - } - } - }, IOException.class); - } - - private static void dropDependencyCache(final CompileContextEx context) { - CompilerUtil.runInContext(context, CompilerBundle.message("progress.saving.caches"), new ThrowableRunnable(){ - public void run() { - context.getDependencyCache().resetState(); - } - }); - } - - private boolean generateSources(final CompilerManager compilerManager, - CompileContextEx context, - final boolean forceCompile, - final boolean onlyCheckStatus) throws ExitException { - boolean didSomething = false; - - final SourceGeneratingCompiler[] sourceGenerators = compilerManager.getCompilers(SourceGeneratingCompiler.class, myCompilerFilter); - for (final SourceGeneratingCompiler sourceGenerator : sourceGenerators) { - if (context.getProgressIndicator().isCanceled()) { - throw new ExitException(ExitStatus.CANCELLED); - } - - final boolean generatedSomething = generateOutput(context, sourceGenerator, forceCompile, onlyCheckStatus); - - if (context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { - throw new ExitException(ExitStatus.ERRORS); - } - didSomething |= generatedSomething; - } - return didSomething; - } - - private boolean translate(final CompileContextEx context, - final CompilerManager compilerManager, - final boolean forceCompile, - boolean isRebuild, - final boolean onlyCheckStatus) throws ExitException { - - boolean didSomething = false; - - final TranslatingCompiler[] translators = compilerManager.getCompilers(TranslatingCompiler.class, myCompilerFilter); - - - final List> sortedChunks = Collections.unmodifiableList(ApplicationManager.getApplication().runReadAction(new Computable>>() { - public List> compute() { - final ModuleManager moduleManager = ModuleManager.getInstance(myProject); - return ModuleCompilerUtil.getSortedModuleChunks(myProject, Arrays.asList(moduleManager.getModules())); - } - })); - - final DumbService dumbService = DumbService.getInstance(myProject); - try { - final Set processedModules = new HashSet(); - VirtualFile[] snapshot = null; - final Map, Collection> chunkMap = new HashMap, Collection>(); - int total = 0; - int processed = 0; - for (final Chunk currentChunk : sortedChunks) { - final TranslatorsOutputSink sink = new TranslatorsOutputSink(context, translators); - final Set generatedTypes = new HashSet(); - Collection chunkFiles = chunkMap.get(currentChunk); - final Set filesToRecompile = new HashSet(); - final Set allDependent = new HashSet(); - try { - int round = 0; - boolean compiledSomethingForThisChunk = false; - Collection dependentFiles = Collections.emptyList(); - final Function>, Pair>> dependencyFilter = new DependentClassesCumulativeFilter(); - - do { - for (int currentCompiler = 0, translatorsLength = translators.length; currentCompiler < translatorsLength; currentCompiler++) { - sink.setCurrentCompilerIndex(currentCompiler); - final TranslatingCompiler compiler = translators[currentCompiler]; - if (context.getProgressIndicator().isCanceled()) { - throw new ExitException(ExitStatus.CANCELLED); - } - - dumbService.waitForSmartMode(); - - if (snapshot == null || ContainerUtil.intersects(generatedTypes, compilerManager.getRegisteredInputTypes(compiler))) { - // rescan snapshot if previously generated files may influence the input of this compiler - final Set prevSnapshot = round > 0 && snapshot != null? new HashSet(Arrays.asList(snapshot)) : Collections.emptySet(); - snapshot = ApplicationManager.getApplication().runReadAction(new Computable() { - public VirtualFile[] compute() { - return context.getCompileScope().getFiles(null, true); - } - }); - recalculateChunkToFilesMap(context, sortedChunks, snapshot, chunkMap); - if (round == 0) { - chunkFiles = chunkMap.get(currentChunk); - } - else { - final Set newFiles = new HashSet(chunkMap.get(currentChunk)); - newFiles.removeAll(prevSnapshot); - newFiles.removeAll(chunkFiles); - if (!newFiles.isEmpty()) { - final ArrayList merged = new ArrayList(chunkFiles.size() + newFiles.size()); - merged.addAll(chunkFiles); - merged.addAll(newFiles); - chunkFiles = merged; - } - } - total = snapshot.length * translatorsLength; - } - - final CompileContextEx _context; - if (compiler instanceof IntermediateOutputCompiler) { - // wrap compile context so that output goes into intermediate directories - final IntermediateOutputCompiler _compiler = (IntermediateOutputCompiler)compiler; - _context = new CompileContextExProxy(context) { - public VirtualFile getModuleOutputDirectory(final Module module) { - return getGenerationOutputDir(_compiler, module, false); - } - - public VirtualFile getModuleOutputDirectoryForTests(final Module module) { - return getGenerationOutputDir(_compiler, module, true); - } - }; - } - else { - _context = context; - } - final boolean compiledSomething = - compileSources(_context, currentChunk, compiler, chunkFiles, round == 0? forceCompile : true, isRebuild, onlyCheckStatus, sink); - - processed += chunkFiles.size(); - _context.getProgressIndicator().setFraction(((double)processed) / total); - - if (compiledSomething) { - generatedTypes.addAll(compilerManager.getRegisteredOutputTypes(compiler)); - } - - didSomething |= compiledSomething; - compiledSomethingForThisChunk |= didSomething; - - if (_context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { - break; // break the loop over compilers - } - } - - final boolean hasUnprocessedTraverseRoots = context.getDependencyCache().hasUnprocessedTraverseRoots(); - if (!isRebuild && (compiledSomethingForThisChunk || hasUnprocessedTraverseRoots)) { - final Set compiledWithErrors = CacheUtils.getFilesCompiledWithErrors(context); - filesToRecompile.removeAll(sink.getCompiledSources()); - filesToRecompile.addAll(compiledWithErrors); - - dependentFiles = CacheUtils.findDependentFiles(context, compiledWithErrors, dependencyFilter); - if (!processedModules.isEmpty()) { - for (Iterator it = dependentFiles.iterator(); it.hasNext();) { - final VirtualFile next = it.next(); - final Module module = context.getModuleByFile(next); - if (module != null && processedModules.contains(module)) { - it.remove(); - } - } - } - - if (ourDebugMode) { - if (!dependentFiles.isEmpty()) { - for (VirtualFile dependentFile : dependentFiles) { - System.out.println("FOUND TO RECOMPILE: " + dependentFile.getPresentableUrl()); - } - } - else { - System.out.println("NO FILES TO RECOMPILE"); - } - } - - if (!dependentFiles.isEmpty()) { - filesToRecompile.addAll(dependentFiles); - allDependent.addAll(dependentFiles); - if (context.getProgressIndicator().isCanceled() || context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { - break; - } - final List filesInScope = getFilesInScope(context, currentChunk, dependentFiles); - if (filesInScope.isEmpty()) { - break; - } - context.getDependencyCache().clearTraverseRoots(); - chunkFiles = filesInScope; - total += chunkFiles.size() * translators.length; - } - - didSomething |= (hasUnprocessedTraverseRoots != context.getDependencyCache().hasUnprocessedTraverseRoots()); - } - - round++; - } - while (!dependentFiles.isEmpty() && context.getMessageCount(CompilerMessageCategory.ERROR) == 0); - - if (CompilerConfiguration.MAKE_ENABLED) { - if (!context.getProgressIndicator().isCanceled()) { - // when cancelled pretend nothing was compiled and next compile will compile everything from the scratch - final ProgressIndicator indicator = context.getProgressIndicator(); - final DependencyCache cache = context.getDependencyCache(); - - indicator.pushState(); - indicator.setText(CompilerBundle.message("progress.updating.caches")); - indicator.setText2(""); - - cache.update(); - - indicator.setText(CompilerBundle.message("progress.saving.caches")); - cache.resetState(); - processedModules.addAll(currentChunk.getNodes()); - indicator.popState(); - } - } - - if (context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { - throw new ExitException(ExitStatus.ERRORS); - } - - } - catch (CacheCorruptedException e) { - LOG.info(e); - context.requestRebuildNextTime(e.getMessage()); - } - finally { - final int errorCount = context.getMessageCount(CompilerMessageCategory.ERROR); - if (errorCount != 0) { - filesToRecompile.addAll(allDependent); - } - if (filesToRecompile.size() > 0) { - sink.add(null, Collections.emptyList(), VfsUtilCore.toVirtualFileArray(filesToRecompile)); - } - if (errorCount == 0) { - // perform update only if there were no errors, so it is guaranteed that the file was processd by all neccesary compilers - sink.flushPostponedItems(); - } - } - } - } - catch (ProcessCanceledException e) { - ProgressManager.getInstance().executeNonCancelableSection(new Runnable() { - public void run() { - try { - final Collection deps = CacheUtils.findDependentFiles(context, Collections.emptySet(), null); - if (deps.size() > 0) { - TranslatingCompilerFilesMonitor.getInstance().update(context, null, Collections.emptyList(), - VfsUtilCore.toVirtualFileArray(deps)); - } - } - catch (IOException ignored) { - LOG.info(ignored); - } - catch (CacheCorruptedException ignored) { - LOG.info(ignored); - } - catch (ExitException e1) { - LOG.info(e1); - } - } - }); - throw e; - } - finally { - dropDependencyCache(context); - if (didSomething) { - TranslatingCompilerFilesMonitor.getInstance().updateOutputRootsLayout(myProject); - } - } - return didSomething; - } - - private static List getFilesInScope(final CompileContextEx context, final Chunk chunk, final Collection files) { - final List filesInScope = new ArrayList(files.size()); - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - for (VirtualFile file : files) { - if (context.getCompileScope().belongs(file.getUrl())) { - final Module module = context.getModuleByFile(file); - if (chunk.getNodes().contains(module)) { - filesInScope.add(file); - } - } - } - } - }); - return filesInScope; - } - - private static void recalculateChunkToFilesMap(CompileContextEx context, List> allChunks, VirtualFile[] snapshot, Map, Collection> chunkMap) { - final Map> moduleToFilesMap = CompilerUtil.buildModuleToFilesMap(context, snapshot); - for (Chunk moduleChunk : allChunks) { - List files = Collections.emptyList(); - for (Module module : moduleChunk.getNodes()) { - final List moduleFiles = moduleToFilesMap.get(module); - if (moduleFiles != null) { - files = ContainerUtil.concat(files, moduleFiles); - } - } - chunkMap.put(moduleChunk, files); - } - } - - private interface FileProcessingCompilerAdapterFactory { - FileProcessingCompilerAdapter create(CompileContext context, FileProcessingCompiler compiler); - } - - private boolean invokeFileProcessingCompilers(final CompilerManager compilerManager, - CompileContextEx context, - Class fileProcessingCompilerClass, - FileProcessingCompilerAdapterFactory factory, - boolean forceCompile, - final boolean checkScope, - final boolean onlyCheckStatus) throws ExitException { - boolean didSomething = false; - final FileProcessingCompiler[] compilers = compilerManager.getCompilers(fileProcessingCompilerClass, myCompilerFilter); - if (compilers.length > 0) { - try { - CacheDeferredUpdater cacheUpdater = new CacheDeferredUpdater(); - try { - for (final FileProcessingCompiler compiler : compilers) { - if (context.getProgressIndicator().isCanceled()) { - throw new ExitException(ExitStatus.CANCELLED); - } - - CompileContextEx _context = context; - if (compiler instanceof IntermediateOutputCompiler) { - final IntermediateOutputCompiler _compiler = (IntermediateOutputCompiler)compiler; - _context = new CompileContextExProxy(context) { - public VirtualFile getModuleOutputDirectory(final Module module) { - return getGenerationOutputDir(_compiler, module, false); - } - - public VirtualFile getModuleOutputDirectoryForTests(final Module module) { - return getGenerationOutputDir(_compiler, module, true); - } - }; - } - - final boolean processedSomething = processFiles(factory.create(_context, compiler), forceCompile, checkScope, onlyCheckStatus, cacheUpdater); - - if (context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { - throw new ExitException(ExitStatus.ERRORS); - } - - didSomething |= processedSomething; - } - } - finally { - cacheUpdater.doUpdate(); - } - } - catch (IOException e) { - LOG.info(e); - context.requestRebuildNextTime(e.getMessage()); - throw new ExitException(ExitStatus.ERRORS); - } - catch (ProcessCanceledException e) { - throw e; - } - catch (ExitException e) { - throw e; - } - catch (Exception e) { - context.addMessage(CompilerMessageCategory.ERROR, CompilerBundle.message("compiler.error.exception", e.getMessage()), null, -1, -1); - LOG.error(e); - } - } - - return didSomething; - } - - private static Map> buildModuleToGenerationItemMap(GeneratingCompiler.GenerationItem[] items) { - final Map> map = new HashMap>(); - for (GeneratingCompiler.GenerationItem item : items) { - Module module = item.getModule(); - LOG.assertTrue(module != null); - Set itemSet = map.get(module); - if (itemSet == null) { - itemSet = new HashSet(); - map.put(module, itemSet); - } - itemSet.add(item); - } - return map; - } - - private void deleteAll(final CompileContextEx context) { - CompilerUtil.runInContext(context, CompilerBundle.message("progress.clearing.output"), new ThrowableRunnable() { - public void run() { - final boolean isTestMode = ApplicationManager.getApplication().isUnitTestMode(); - final VirtualFile[] allSources = context.getProjectCompileScope().getFiles(null, true); - if (myShouldClearOutputDirectory) { - CompilerUtil.clearOutputDirectories(myAllOutputDirectories); - } - else { // refresh is still required - try { - for (final Compiler compiler : CompilerManager.getInstance(myProject).getCompilers(Compiler.class)) { - try { - if (compiler instanceof GeneratingCompiler) { - final StateCache cache = getGeneratingCompilerCache((GeneratingCompiler)compiler); - final Iterator urlIterator = cache.getUrlsIterator(); - while (urlIterator.hasNext()) { - context.getProgressIndicator().checkCanceled(); - deleteFile(new File(VirtualFileManager.extractPath(urlIterator.next()))); - } - } - else if (compiler instanceof TranslatingCompiler) { - final ArrayList> toDelete = new ArrayList>(); - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - TranslatingCompilerFilesMonitor.getInstance().collectFiles( - context, - (TranslatingCompiler)compiler, Arrays.asList(allSources).iterator(), - true /*pass true to make sure that every source in scope file is processed*/, - false /*important! should pass false to enable collection of files to delete*/, - new ArrayList(), - toDelete - ); - } - }); - for (Trinity trinity : toDelete) { - context.getProgressIndicator().checkCanceled(); - final File file = trinity.getFirst(); - deleteFile(file); - if (isTestMode) { - CompilerManagerImpl.addDeletedPath(file.getPath()); - } - } - } - } - catch (IOException e) { - LOG.info(e); - } - } - pruneEmptyDirectories(context.getProgressIndicator(), myAllOutputDirectories); // to avoid too much files deleted events - } - finally { - CompilerUtil.refreshIODirectories(myAllOutputDirectories); - } - } - dropScopesCaches(); - - clearCompilerSystemDirectory(context); - } - }); - } - - private void dropScopesCaches() { - // hack to be sure the classpath will include the output directories - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - ((ProjectRootManagerEx)ProjectRootManager.getInstance(myProject)).clearScopesCachesForModules(); - } - }); - } - - private static void pruneEmptyDirectories(ProgressIndicator progress, final Set directories) { - for (File directory : directories) { - doPrune(progress, directory, directories); - } - } - - private static boolean doPrune(ProgressIndicator progress, final File directory, final Set outPutDirectories) { - progress.checkCanceled(); - final File[] files = directory.listFiles(); - boolean isEmpty = true; - if (files != null) { - for (File file : files) { - if (!outPutDirectories.contains(file)) { - if (doPrune(progress, file, outPutDirectories)) { - deleteFile(file); - } - else { - isEmpty = false; - } - } - else { - isEmpty = false; - } - } - } - else { - isEmpty = false; - } - - return isEmpty; - } - - private Set getAllOutputDirectories(CompileContext context) { - final Set outputDirs = new OrderedSet(); - final Module[] modules = ModuleManager.getInstance(myProject).getModules(); - for (final String path : CompilerPathsEx.getOutputPaths(modules)) { - outputDirs.add(new File(path)); - } - for (Pair pair : myGenerationCompilerModuleToOutputDirMap.keySet()) { - outputDirs.add(new File(CompilerPaths.getGenerationOutputPath(pair.getFirst(), pair.getSecond(), false))); - outputDirs.add(new File(CompilerPaths.getGenerationOutputPath(pair.getFirst(), pair.getSecond(), true))); - } - final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject); - if (context.isAnnotationProcessorsEnabled()) { - for (Module module : modules) { - if (config.getAnnotationProcessingConfiguration(module).isEnabled()) { - final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module); - if (path != null) { - outputDirs.add(new File(path)); - } - } - } - } - for (Artifact artifact : ArtifactManager.getInstance(myProject).getArtifacts()) { - final String path = ((ArtifactImpl)artifact).getOutputDirectoryPathToCleanOnRebuild(); - if (path != null) { - outputDirs.add(new File(FileUtil.toSystemDependentName(path))); - } - } - return outputDirs; - } - - private void clearCompilerSystemDirectory(final CompileContextEx context) { - CompilerCacheManager.getInstance(myProject).clearCaches(context); - FileUtil.delete(CompilerPathsEx.getZipStoreDirectory(myProject)); - dropDependencyCache(context); - - for (Pair pair : myGenerationCompilerModuleToOutputDirMap.keySet()) { - final File[] outputs = { - new File(CompilerPaths.getGenerationOutputPath(pair.getFirst(), pair.getSecond(), false)), - new File(CompilerPaths.getGenerationOutputPath(pair.getFirst(), pair.getSecond(), true)) - }; - for (File output : outputs) { - final File[] files = output.listFiles(); - if (files != null) { - for (final File file : files) { - final boolean deleteOk = deleteFile(file); - if (!deleteOk) { - context.addMessage(CompilerMessageCategory.ERROR, CompilerBundle.message("compiler.error.failed.to.delete", file.getPath()), - null, -1, -1); - } - } - } - } - } - } - - /** - * @param file a file to delete - * @return true if and only if the file existed and was successfully deleted - * Note: the behaviour is different from FileUtil.delete() which returns true if the file absent on the disk - */ - private static boolean deleteFile(final File file) { - File[] files = file.listFiles(); - if (files != null) { - for (File file1 : files) { - deleteFile(file1); - } - } - - for (int i = 0; i < 10; i++){ - if (file.delete()) { - return true; - } - if (!file.exists()) { - return false; - } - try { - Thread.sleep(50); - } - catch (InterruptedException ignored) { - } - } - return false; - } - - private VirtualFile getGenerationOutputDir(final IntermediateOutputCompiler compiler, final Module module, final boolean forTestSources) { - final Pair outputs = - myGenerationCompilerModuleToOutputDirMap.get(new Pair(compiler, module)); - return forTestSources? outputs.getSecond() : outputs.getFirst(); - } - - private boolean generateOutput(final CompileContextEx context, - final GeneratingCompiler compiler, - final boolean forceGenerate, - final boolean onlyCheckStatus) throws ExitException { - final GeneratingCompiler.GenerationItem[] allItems = compiler.getGenerationItems(context); - final List toGenerate = new ArrayList(); - final List filesToRefresh = new ArrayList(); - final List generatedFiles = new ArrayList(); - final List affectedModules = new ArrayList(); - try { - final StateCache cache = getGeneratingCompilerCache(compiler); - final Set pathsToRemove = new HashSet(cache.getUrls()); - - final Map itemToOutputPathMap = new HashMap(); - final IOException[] ex = {null}; - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - for (final GeneratingCompiler.GenerationItem item : allItems) { - final Module itemModule = item.getModule(); - final String outputDirPath = CompilerPaths.getGenerationOutputPath(compiler, itemModule, item.isTestSource()); - final String outputPath = outputDirPath + "/" + item.getPath(); - itemToOutputPathMap.put(item, outputPath); - - try { - final ValidityState savedState = cache.getState(outputPath); - - if (forceGenerate || savedState == null || !savedState.equalsTo(item.getValidityState())) { - final String outputPathUrl = VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, outputPath); - if (context.getCompileScope().belongs(outputPathUrl)) { - toGenerate.add(item); - } - else { - pathsToRemove.remove(outputPath); - } - } - else { - pathsToRemove.remove(outputPath); - } - } - catch (IOException e) { - ex[0] = e; - } - } - } - }); - if (ex[0] != null) { - throw ex[0]; - } - - if (onlyCheckStatus) { - if (toGenerate.isEmpty() && pathsToRemove.isEmpty()) { - return false; - } - if (LOG.isDebugEnabled()) { - if (!toGenerate.isEmpty()) { - LOG.debug("Found items to generate, compiler " + compiler.getDescription()); - } - if (!pathsToRemove.isEmpty()) { - LOG.debug("Found paths to remove, compiler " + compiler.getDescription()); - } - } - throw new ExitException(ExitStatus.CANCELLED); - } - - if (!pathsToRemove.isEmpty()) { - CompilerUtil.runInContext(context, CompilerBundle.message("progress.synchronizing.output.directory"), new ThrowableRunnable(){ - public void run() throws IOException { - for (final String path : pathsToRemove) { - final File file = new File(path); - final boolean deleted = deleteFile(file); - if (deleted) { - cache.remove(path); - filesToRefresh.add(file); - } - } - } - }); - } - - final Map> moduleToItemMap = - buildModuleToGenerationItemMap(toGenerate.toArray(new GeneratingCompiler.GenerationItem[toGenerate.size()])); - List modules = new ArrayList(moduleToItemMap.size()); - for (final Module module : moduleToItemMap.keySet()) { - modules.add(module); - } - ModuleCompilerUtil.sortModules(myProject, modules); - - for (final Module module : modules) { - CompilerUtil.runInContext(context, "Generating output from "+compiler.getDescription(),new ThrowableRunnable(){ - public void run() throws IOException { - final Set items = moduleToItemMap.get(module); - if (items != null && !items.isEmpty()) { - final GeneratingCompiler.GenerationItem[][] productionAndTestItems = splitGenerationItems(items); - for (GeneratingCompiler.GenerationItem[] _items : productionAndTestItems) { - if (_items.length == 0) continue; - final VirtualFile outputDir = getGenerationOutputDir(compiler, module, _items[0].isTestSource()); - final GeneratingCompiler.GenerationItem[] successfullyGenerated = compiler.generate(context, _items, outputDir); - - CompilerUtil.runInContext(context, CompilerBundle.message("progress.updating.caches"), new ThrowableRunnable() { - public void run() throws IOException { - if (successfullyGenerated.length > 0) { - affectedModules.add(module); - } - for (final GeneratingCompiler.GenerationItem item : successfullyGenerated) { - final String fullOutputPath = itemToOutputPathMap.get(item); - cache.update(fullOutputPath, item.getValidityState()); - final File file = new File(fullOutputPath); - filesToRefresh.add(file); - generatedFiles.add(file); - context.getProgressIndicator().setText2(file.getPath()); - } - } - }); - } - } - } - }); - } - } - catch (IOException e) { - LOG.info(e); - context.requestRebuildNextTime(e.getMessage()); - throw new ExitException(ExitStatus.ERRORS); - } - finally { - CompilerUtil.refreshIOFiles(filesToRefresh); - if (!generatedFiles.isEmpty()) { - DumbService.getInstance(myProject).waitForSmartMode(); - List vFiles = ApplicationManager.getApplication().runReadAction(new Computable>() { - public List compute() { - final ArrayList vFiles = new ArrayList(generatedFiles.size()); - for (File generatedFile : generatedFiles) { - final VirtualFile vFile = LocalFileSystem.getInstance().findFileByIoFile(generatedFile); - if (vFile != null) { - vFiles.add(vFile); - } - } - return vFiles; - } - }); - if (forceGenerate) { - context.addScope(new FileSetCompileScope(vFiles, affectedModules.toArray(new Module[affectedModules.size()]))); - } - context.markGenerated(vFiles); - } - } - return !toGenerate.isEmpty() || !filesToRefresh.isEmpty(); - } - - private static GeneratingCompiler.GenerationItem[][] splitGenerationItems(final Set items) { - final List production = new ArrayList(); - final List tests = new ArrayList(); - for (GeneratingCompiler.GenerationItem item : items) { - if (item.isTestSource()) { - tests.add(item); - } - else { - production.add(item); - } - } - return new GeneratingCompiler.GenerationItem[][]{ - production.toArray(new GeneratingCompiler.GenerationItem[production.size()]), - tests.toArray(new GeneratingCompiler.GenerationItem[tests.size()]) - }; - } - - private boolean compileSources(final CompileContextEx context, - final Chunk moduleChunk, - final TranslatingCompiler compiler, - final Collection srcSnapshot, - final boolean forceCompile, - final boolean isRebuild, - final boolean onlyCheckStatus, - TranslatingCompiler.OutputSink sink) throws ExitException { - - final Set toCompile = new HashSet(); - final List> toDelete = new ArrayList>(); - context.getProgressIndicator().pushState(); - - final boolean[] wereFilesDeleted = {false}; - try { - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - TranslatingCompilerFilesMonitor.getInstance().collectFiles( - context, compiler, srcSnapshot.iterator(), forceCompile, isRebuild, toCompile, toDelete - ); - } - }); - - if (onlyCheckStatus) { - if (toDelete.isEmpty() && toCompile.isEmpty()) { - return false; - } - if (LOG.isDebugEnabled() || ourDebugMode) { - if (!toDelete.isEmpty()) { - final StringBuilder message = new StringBuilder(); - message.append("Found items to delete, compiler ").append(compiler.getDescription()); - for (Trinity trinity : toDelete) { - message.append("\n").append(trinity.getFirst()); - } - LOG.debug(message.toString()); - if (ourDebugMode) { - System.out.println(message); - } - } - if (!toCompile.isEmpty()) { - final String message = "Found items to compile, compiler " + compiler.getDescription(); - LOG.debug(message); - if (ourDebugMode) { - System.out.println(message); - } - } - } - throw new ExitException(ExitStatus.CANCELLED); - } - - if (!toDelete.isEmpty()) { - try { - wereFilesDeleted[0] = syncOutputDir(context, toDelete); - } - catch (CacheCorruptedException e) { - LOG.info(e); - context.requestRebuildNextTime(e.getMessage()); - } - } - - if ((wereFilesDeleted[0] || !toCompile.isEmpty()) && context.getMessageCount(CompilerMessageCategory.ERROR) == 0) { - compiler.compile(context, moduleChunk, VfsUtilCore.toVirtualFileArray(toCompile), sink); - } - } - finally { - context.getProgressIndicator().popState(); - } - return !toCompile.isEmpty() || wereFilesDeleted[0]; - } - - private static boolean syncOutputDir(final CompileContextEx context, final Collection> toDelete) throws CacheCorruptedException { - final DependencyCache dependencyCache = context.getDependencyCache(); - final boolean isTestMode = ApplicationManager.getApplication().isUnitTestMode(); - - final List filesToRefresh = new ArrayList(); - final boolean[] wereFilesDeleted = {false}; - CompilerUtil.runInContext(context, CompilerBundle.message("progress.synchronizing.output.directory"), new ThrowableRunnable(){ - public void run() throws CacheCorruptedException { - final long start = System.currentTimeMillis(); - try { - for (final Trinity trinity : toDelete) { - final File outputPath = trinity.getFirst(); - context.getProgressIndicator().checkCanceled(); - context.getProgressIndicator().setText2(outputPath.getPath()); - filesToRefresh.add(outputPath); - if (isTestMode) { - LOG.assertTrue(outputPath.exists()); - } - if (!deleteFile(outputPath)) { - if (isTestMode) { - if (outputPath.exists()) { - LOG.error("Was not able to delete output file: " + outputPath.getPath()); - } - else { - CompilerManagerImpl.addDeletedPath(outputPath.getPath()); - } - } - continue; - } - wereFilesDeleted[0] = true; - - // update zip here - //final String outputDir = myOutputFinder.lookupOutputPath(outputPath); - //if (outputDir != null) { - // try { - // context.updateZippedOuput(outputDir, FileUtil.toSystemIndependentName(outputPath.getPath()).substring(outputDir.length() + 1)); - // } - // catch (IOException e) { - // LOG.info(e); - // } - //} - - final String className = trinity.getSecond(); - if (className != null) { - final int id = dependencyCache.getSymbolTable().getId(className); - dependencyCache.addTraverseRoot(id); - final boolean sourcePresent = trinity.getThird().booleanValue(); - if (!sourcePresent) { - dependencyCache.markSourceRemoved(id); - } - } - if (isTestMode) { - CompilerManagerImpl.addDeletedPath(outputPath.getPath()); - } - } - } - finally { - CompilerUtil.logDuration("Sync output directory", System.currentTimeMillis() - start); - CompilerUtil.refreshIOFiles(filesToRefresh); - } - } - }); - return wereFilesDeleted[0]; - } - - // [mike] performance optimization - this method is accessed > 15,000 times in Aurora - private String getModuleOutputPath(final Module module, boolean inTestSourceContent) { - final Map map = inTestSourceContent ? myModuleTestOutputPaths : myModuleOutputPaths; - String path = map.get(module); - if (path == null) { - path = CompilerPaths.getModuleOutputPath(module, inTestSourceContent); - map.put(module, path); - } - - return path; - } - - private boolean processFiles(final FileProcessingCompilerAdapter adapter, - final boolean forceCompile, - final boolean checkScope, - final boolean onlyCheckStatus, final CacheDeferredUpdater cacheUpdater) throws ExitException, IOException { - final CompileContextEx context = (CompileContextEx)adapter.getCompileContext(); - final FileProcessingCompilerStateCache cache = getFileProcessingCompilerCache(adapter.getCompiler()); - final FileProcessingCompiler.ProcessingItem[] items = adapter.getProcessingItems(); - if (context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { - return false; - } - if (LOG.isDebugEnabled() && items.length > 0) { - LOG.debug("Start processing files by " + adapter.getCompiler().getDescription()); - } - final CompileScope scope = context.getCompileScope(); - final List toProcess = new ArrayList(); - final Set allUrls = new HashSet(); - final IOException[] ex = {null}; - DumbService.getInstance(myProject).waitForSmartMode(); - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - try { - for (FileProcessingCompiler.ProcessingItem item : items) { - final VirtualFile file = item.getFile(); - final String url = file.getUrl(); - allUrls.add(url); - if (!forceCompile && cache.getTimestamp(url) == file.getTimeStamp()) { - final ValidityState state = cache.getExtState(url); - final ValidityState itemState = item.getValidityState(); - if (state != null ? state.equalsTo(itemState) : itemState == null) { - continue; - } - } - if (LOG.isDebugEnabled()) { - LOG.debug("Adding item to process: " + url + "; saved ts= " + cache.getTimestamp(url) + "; VFS ts=" + file.getTimeStamp()); - } - toProcess.add(item); - } - } - catch (IOException e) { - ex[0] = e; - } - } - }); - - if (ex[0] != null) { - throw ex[0]; - } - - final Collection urls = cache.getUrls(); - final List urlsToRemove = new ArrayList(); - if (!urls.isEmpty()) { - CompilerUtil.runInContext(context, CompilerBundle.message("progress.processing.outdated.files"), new ThrowableRunnable(){ - public void run() throws IOException { - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - for (final String url : urls) { - if (!allUrls.contains(url)) { - if (!checkScope || scope.belongs(url)) { - urlsToRemove.add(url); - } - } - } - } - }); - if (!onlyCheckStatus && !urlsToRemove.isEmpty()) { - for (final String url : urlsToRemove) { - adapter.processOutdatedItem(context, url, cache.getExtState(url)); - cache.remove(url); - } - } - } - }); - } - - if (onlyCheckStatus) { - if (urlsToRemove.isEmpty() && toProcess.isEmpty()) { - return false; - } - if (LOG.isDebugEnabled()) { - if (!urlsToRemove.isEmpty()) { - LOG.debug("Found urls to remove, compiler " + adapter.getCompiler().getDescription()); - for (String url : urlsToRemove) { - LOG.debug("\t" + url); - } - } - if (!toProcess.isEmpty()) { - LOG.debug("Found items to compile, compiler " + adapter.getCompiler().getDescription()); - for (FileProcessingCompiler.ProcessingItem item : toProcess) { - LOG.debug("\t" + item.getFile().getPresentableUrl()); - } - } - } - throw new ExitException(ExitStatus.CANCELLED); - } - - if (toProcess.isEmpty()) { - return false; - } - - final FileProcessingCompiler.ProcessingItem[] processed = - adapter.process(toProcess.toArray(new FileProcessingCompiler.ProcessingItem[toProcess.size()])); - - if (processed.length == 0) { - return true; - } - CompilerUtil.runInContext(context, CompilerBundle.message("progress.updating.caches"), new ThrowableRunnable() { - public void run() { - final List vFiles = new ArrayList(processed.length); - for (FileProcessingCompiler.ProcessingItem aProcessed : processed) { - final VirtualFile file = aProcessed.getFile(); - vFiles.add(file); - if (LOG.isDebugEnabled()) { - LOG.debug("\tFile processed " + file.getPresentableUrl() + "; ts=" + file.getTimeStamp()); - } - - //final String path = file.getPath(); - //final String outputDir = myOutputFinder.lookupOutputPath(path); - //if (outputDir != null) { - // context.updateZippedOuput(outputDir, path.substring(outputDir.length() + 1)); - //} - } - LocalFileSystem.getInstance().refreshFiles(vFiles); - if (LOG.isDebugEnabled()) { - LOG.debug("Files after VFS refresh:"); - for (VirtualFile file : vFiles) { - LOG.debug("\t" + file.getPresentableUrl() + "; ts=" + file.getTimeStamp()); - } - } - for (FileProcessingCompiler.ProcessingItem item : processed) { - cacheUpdater.addFileForUpdate(item, cache); - } - } - }); - return true; - } - - private FileProcessingCompilerStateCache getFileProcessingCompilerCache(FileProcessingCompiler compiler) throws IOException { - return CompilerCacheManager.getInstance(myProject).getFileProcessingCompilerCache(compiler); - } - - private StateCache getGeneratingCompilerCache(final GeneratingCompiler compiler) throws IOException { - return CompilerCacheManager.getInstance(myProject).getGeneratingCompilerCache(compiler); - } - - public void executeCompileTask(final CompileTask task, final CompileScope scope, final String contentName, final Runnable onTaskFinished) { - final CompilerTask progressManagerTask = - new CompilerTask(myProject, contentName, false, false); - final CompileContextImpl compileContext = new CompileContextImpl(myProject, progressManagerTask, scope, null, false, false); - - FileDocumentManager.getInstance().saveAllDocuments(); - - progressManagerTask.start(new Runnable() { - public void run() { - try { - task.execute(compileContext); - } - catch (ProcessCanceledException ex) { - // suppressed - } - finally { - if (onTaskFinished != null) { - onTaskFinished.run(); - } - } - } - }, null); - } - - private boolean executeCompileTasks(final CompileContext context, final boolean beforeTasks) { - final CompilerManager manager = CompilerManager.getInstance(myProject); - final ProgressIndicator progressIndicator = context.getProgressIndicator(); - progressIndicator.pushState(); - try { - CompileTask[] tasks = beforeTasks ? manager.getBeforeTasks() : manager.getAfterTasks(); - if (tasks.length > 0) { - progressIndicator.setText(beforeTasks - ? CompilerBundle.message("progress.executing.precompile.tasks") - : CompilerBundle.message("progress.executing.postcompile.tasks")); - for (CompileTask task : tasks) { - if (!task.execute(context)) { - return false; - } - } - } - } - finally { - progressIndicator.popState(); - WindowManager.getInstance().getStatusBar(myProject).setInfo(""); - if (progressIndicator instanceof CompilerTask) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - public void run() { - ((CompilerTask)progressIndicator).showCompilerContent(); - } - }); - } - } - return true; - } - - private boolean validateCompilerConfiguration(final CompileScope scope, boolean checkOutputAndSourceIntersection) { - try { - final Module[] scopeModules = scope.getAffectedModules()/*ModuleManager.getInstance(myProject).getModules()*/; - final List modulesWithoutOutputPathSpecified = new ArrayList(); - boolean isProjectCompilePathSpecified = true; - final List modulesWithoutJdkAssigned = new ArrayList(); - final Set nonExistingOutputPaths = new HashSet(); - final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject); - final CompilerManager compilerManager = CompilerManager.getInstance(myProject); - for (final Module module : scopeModules) { - if (!compilerManager.isValidationEnabled(module)) { - continue; - } - final boolean hasSources = hasSources(module, false); - final boolean hasTestSources = hasSources(module, true); - if (!hasSources && !hasTestSources) { - // If module contains no sources, shouldn't have to select JDK or output directory (SCR #19333) - // todo still there may be problems with this approach if some generated files are attributed by this module - continue; - } - final Sdk jdk = ModuleRootManager.getInstance(module).getSdk(); - if (jdk == null) { - modulesWithoutJdkAssigned.add(module.getName()); - } - final String outputPath = getModuleOutputPath(module, false); - final String testsOutputPath = getModuleOutputPath(module, true); - if (outputPath == null && testsOutputPath == null) { - modulesWithoutOutputPathSpecified.add(module.getName()); - } - else { - if (outputPath != null) { - final File file = new File(outputPath.replace('/', File.separatorChar)); - if (!file.exists()) { - nonExistingOutputPaths.add(file); - } - } - else { - if (hasSources) { - modulesWithoutOutputPathSpecified.add(module.getName()); - } - } - if (testsOutputPath != null) { - final File f = new File(testsOutputPath.replace('/', File.separatorChar)); - if (!f.exists()) { - nonExistingOutputPaths.add(f); - } - } - else { - if (hasTestSources) { - modulesWithoutOutputPathSpecified.add(module.getName()); - } - } - if (!useOutOfProcessBuild()) { - if (config.getAnnotationProcessingConfiguration(module).isEnabled()) { - final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module); - if (path == null) { - final CompilerProjectExtension extension = CompilerProjectExtension.getInstance(module.getProject()); - if (extension == null || extension.getCompilerOutputUrl() == null) { - isProjectCompilePathSpecified = false; - } - else { - modulesWithoutOutputPathSpecified.add(module.getName()); - } - } - else { - final File file = new File(path); - if (!file.exists()) { - nonExistingOutputPaths.add(file); - } - } - } - } - } - } - if (!modulesWithoutJdkAssigned.isEmpty()) { - showNotSpecifiedError("error.jdk.not.specified", modulesWithoutJdkAssigned, ProjectBundle.message("modules.classpath.title")); - return false; - } - - if (!isProjectCompilePathSpecified) { - final String message = CompilerBundle.message("error.project.output.not.specified"); - if (ApplicationManager.getApplication().isUnitTestMode()) { - LOG.error(message); - } - - Messages.showMessageDialog(myProject, message, CommonBundle.getErrorTitle(), Messages.getErrorIcon()); - ProjectSettingsService.getInstance(myProject).openProjectSettings(); - return false; - } - - if (!modulesWithoutOutputPathSpecified.isEmpty()) { - showNotSpecifiedError("error.output.not.specified", modulesWithoutOutputPathSpecified, CommonContentEntriesEditor.NAME); - return false; - } - - if (!nonExistingOutputPaths.isEmpty()) { - for (File file : nonExistingOutputPaths) { - final boolean succeeded = file.mkdirs(); - if (!succeeded) { - if (file.exists()) { - // for overlapping paths, this one might have been created as an intermediate path on a previous iteration - continue; - } - Messages.showMessageDialog(myProject, CompilerBundle.message("error.failed.to.create.directory", file.getPath()), - CommonBundle.getErrorTitle(), Messages.getErrorIcon()); - return false; - } - } - final Boolean refreshSuccess = - new WriteAction() { - @Override - protected void run(Result result) throws Throwable { - LocalFileSystem.getInstance().refreshIoFiles(nonExistingOutputPaths); - Boolean res = Boolean.TRUE; - for (File file : nonExistingOutputPaths) { - if (LocalFileSystem.getInstance().findFileByIoFile(file) == null) { - res = Boolean.FALSE; - break; - } - } - result.setResult(res); - } - }.execute().getResultObject(); - - if (!refreshSuccess.booleanValue()) { - return false; - } - dropScopesCaches(); - } - - if (checkOutputAndSourceIntersection && myShouldClearOutputDirectory) { - if (!validateOutputAndSourcePathsIntersection()) { - return false; - } - // myShouldClearOutputDirectory may change in validateOutputAndSourcePathsIntersection() - CompilerPathsEx.CLEAR_ALL_OUTPUTS_KEY.set(scope, myShouldClearOutputDirectory); - } - else { - CompilerPathsEx.CLEAR_ALL_OUTPUTS_KEY.set(scope, false); - } - final List> chunks = ModuleCompilerUtil.getSortedModuleChunks(myProject, Arrays.asList(scopeModules)); - for (final Chunk chunk : chunks) { - final Set chunkModules = chunk.getNodes(); - if (chunkModules.size() <= 1) { - continue; // no need to check one-module chunks - } - for (Module chunkModule : chunkModules) { - if (config.getAnnotationProcessingConfiguration(chunkModule).isEnabled()) { - showCyclesNotSupportedForAnnotationProcessors(chunkModules.toArray(new Module[chunkModules.size()])); - return false; - } - } - Sdk jdk = null; - LanguageLevel languageLevel = null; - for (final Module module : chunkModules) { - final Sdk moduleJdk = ModuleRootManager.getInstance(module).getSdk(); - if (jdk == null) { - jdk = moduleJdk; - } - else { - if (!jdk.equals(moduleJdk)) { - showCyclicModulesHaveDifferentJdksError(chunkModules.toArray(new Module[chunkModules.size()])); - return false; - } - } - - LanguageLevel moduleLanguageLevel = LanguageLevelUtil.getEffectiveLanguageLevel(module); - if (languageLevel == null) { - languageLevel = moduleLanguageLevel; - } - else { - if (!languageLevel.equals(moduleLanguageLevel)) { - showCyclicModulesHaveDifferentLanguageLevel(chunkModules.toArray(new Module[chunkModules.size()])); - return false; - } - } - } - } - if (!useOutOfProcessBuild()) { - final Compiler[] allCompilers = compilerManager.getCompilers(Compiler.class); - for (Compiler compiler : allCompilers) { - if (!compiler.validateConfiguration(scope)) { - return false; - } - } - } - return true; - } - catch (Throwable e) { - LOG.info(e); - return false; - } - } - - private boolean useOutOfProcessBuild() { - return CompilerWorkspaceConfiguration.getInstance(myProject).useOutOfProcessBuild(); - } - - private void showCyclicModulesHaveDifferentLanguageLevel(Module[] modulesInChunk) { - LOG.assertTrue(modulesInChunk.length > 0); - String moduleNameToSelect = modulesInChunk[0].getName(); - final String moduleNames = getModulesString(modulesInChunk); - Messages.showMessageDialog(myProject, CompilerBundle.message("error.chunk.modules.must.have.same.language.level", moduleNames), - CommonBundle.getErrorTitle(), Messages.getErrorIcon()); - showConfigurationDialog(moduleNameToSelect, null); - } - - private void showCyclicModulesHaveDifferentJdksError(Module[] modulesInChunk) { - LOG.assertTrue(modulesInChunk.length > 0); - String moduleNameToSelect = modulesInChunk[0].getName(); - final String moduleNames = getModulesString(modulesInChunk); - Messages.showMessageDialog(myProject, CompilerBundle.message("error.chunk.modules.must.have.same.jdk", moduleNames), - CommonBundle.getErrorTitle(), Messages.getErrorIcon()); - showConfigurationDialog(moduleNameToSelect, null); - } - - private void showCyclesNotSupportedForAnnotationProcessors(Module[] modulesInChunk) { - LOG.assertTrue(modulesInChunk.length > 0); - String moduleNameToSelect = modulesInChunk[0].getName(); - final String moduleNames = getModulesString(modulesInChunk); - Messages.showMessageDialog(myProject, CompilerBundle.message("error.annotation.processing.not.supported.for.module.cycles", moduleNames), - CommonBundle.getErrorTitle(), Messages.getErrorIcon()); - showConfigurationDialog(moduleNameToSelect, null); - } - - private static String getModulesString(Module[] modulesInChunk) { - final StringBuilder moduleNames = StringBuilderSpinAllocator.alloc(); - try { - for (Module module : modulesInChunk) { - if (moduleNames.length() > 0) { - moduleNames.append("\n"); - } - moduleNames.append("\"").append(module.getName()).append("\""); - } - return moduleNames.toString(); - } - finally { - StringBuilderSpinAllocator.dispose(moduleNames); - } - } - - private static boolean hasSources(Module module, boolean checkTestSources) { - final ContentEntry[] contentEntries = ModuleRootManager.getInstance(module).getContentEntries(); - for (final ContentEntry contentEntry : contentEntries) { - final SourceFolder[] sourceFolders = contentEntry.getSourceFolders(); - for (final SourceFolder sourceFolder : sourceFolders) { - if (sourceFolder.getFile() == null) { - continue; // skip invalid source folders - } - if (checkTestSources) { - if (sourceFolder.isTestSource()) { - return true; - } - } - else { - if (!sourceFolder.isTestSource()) { - return true; - } - } - } - } - return false; - } - - private void showNotSpecifiedError(@NonNls final String resourceId, List modules, String editorNameToSelect) { - String nameToSelect = null; - final StringBuilder names = StringBuilderSpinAllocator.alloc(); - final String message; - try { - final int maxModulesToShow = 10; - for (String name : modules.size() > maxModulesToShow ? modules.subList(0, maxModulesToShow) : modules) { - if (nameToSelect == null) { - nameToSelect = name; - } - if (names.length() > 0) { - names.append(",\n"); - } - names.append("\""); - names.append(name); - names.append("\""); - } - if (modules.size() > maxModulesToShow) { - names.append(",\n..."); - } - message = CompilerBundle.message(resourceId, modules.size(), names.toString()); - } - finally { - StringBuilderSpinAllocator.dispose(names); - } - - if (ApplicationManager.getApplication().isUnitTestMode()) { - LOG.error(message); - } - - Messages.showMessageDialog(myProject, message, CommonBundle.getErrorTitle(), Messages.getErrorIcon()); - showConfigurationDialog(nameToSelect, editorNameToSelect); - } - - private boolean validateOutputAndSourcePathsIntersection() { - final Module[] allModules = ModuleManager.getInstance(myProject).getModules(); - List allOutputs = new ArrayList(); - ContainerUtil.addAll(allOutputs, CompilerPathsEx.getOutputDirectories(allModules)); - for (Artifact artifact : ArtifactManager.getInstance(myProject).getArtifacts()) { - ContainerUtil.addIfNotNull(artifact.getOutputFile(), allOutputs); - } - final Set affectedOutputPaths = new HashSet(); - CompilerUtil.computeIntersectingPaths(myProject, allOutputs, affectedOutputPaths); - affectedOutputPaths.addAll(ArtifactCompilerUtil.getArtifactOutputsContainingSourceFiles(myProject)); - - if (!affectedOutputPaths.isEmpty()) { - if (CompilerUtil.askUserToContinueWithNoClearing(myProject, affectedOutputPaths)) { - myShouldClearOutputDirectory = false; - return true; - } - else { - return false; - } - } - return true; - } - - private void showConfigurationDialog(String moduleNameToSelect, String tabNameToSelect) { - ProjectSettingsService.getInstance(myProject).showModuleConfigurationDialog(moduleNameToSelect, tabNameToSelect); - } - - private static VirtualFile lookupVFile(final LocalFileSystem lfs, final String path) { - final File file = new File(path); - - VirtualFile vFile = lfs.findFileByIoFile(file); - if (vFile != null) { - return vFile; - } - - final boolean justCreated = file.mkdirs(); - vFile = lfs.refreshAndFindFileByIoFile(file); - - if (vFile == null) { - assert false: "Virtual file not found for " + file.getPath() + "; mkdirs() exit code is " + justCreated + "; file exists()? " + file.exists(); - } - - return vFile; - } - - private static class CacheDeferredUpdater { - private final Map>> myData = new java.util.HashMap>>(); - - public void addFileForUpdate(final FileProcessingCompiler.ProcessingItem item, FileProcessingCompilerStateCache cache) { - final VirtualFile file = item.getFile(); - List> list = myData.get(file); - if (list == null) { - list = new ArrayList>(); - myData.put(file, list); - } - list.add(new Pair(cache, item)); - } - - public void doUpdate() throws IOException{ - final IOException[] ex = {null}; - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - try { - for (Map.Entry>> entry : myData.entrySet()) { - for (Pair pair : entry.getValue()) { - final FileProcessingCompiler.ProcessingItem item = pair.getSecond(); - pair.getFirst().update(entry.getKey(), item.getValidityState()); - } - } - } - catch (IOException e) { - ex[0] = e; - } - } - }); - if (ex[0] != null) { - throw ex[0]; - } - } - } - - private static class TranslatorsOutputSink implements TranslatingCompiler.OutputSink { - final Map> myPostponedItems = new HashMap>(); - private final CompileContextEx myContext; - private final TranslatingCompiler[] myCompilers; - private int myCurrentCompilerIdx; - private final Set myCompiledSources = new HashSet(); - //private LinkedBlockingQueue myFutures = new LinkedBlockingQueue(); - - private TranslatorsOutputSink(CompileContextEx context, TranslatingCompiler[] compilers) { - myContext = context; - myCompilers = compilers; - } - - public void setCurrentCompilerIndex(int index) { - myCurrentCompilerIdx = index; - } - - public Set getCompiledSources() { - return Collections.unmodifiableSet(myCompiledSources); - } - - public void add(final String outputRoot, final Collection items, final VirtualFile[] filesToRecompile) { - for (TranslatingCompiler.OutputItem item : items) { - final VirtualFile file = item.getSourceFile(); - if (file != null) { - myCompiledSources.add(file); - } - } - final TranslatingCompiler compiler = myCompilers[myCurrentCompilerIdx]; - if (compiler instanceof IntermediateOutputCompiler) { - final LocalFileSystem lfs = LocalFileSystem.getInstance(); - final List outputs = new ArrayList(); - for (TranslatingCompiler.OutputItem item : items) { - final VirtualFile vFile = lfs.findFileByPath(item.getOutputPath()); - if (vFile != null) { - outputs.add(vFile); - } - } - myContext.markGenerated(outputs); - } - final int nextCompilerIdx = myCurrentCompilerIdx + 1; - try { - if (nextCompilerIdx < myCompilers.length ) { - final Map> updateNow = new java.util.HashMap>(); - // process postponed - for (Map.Entry> entry : myPostponedItems.entrySet()) { - final String outputDir = entry.getKey(); - final Collection postponed = entry.getValue(); - for (Iterator it = postponed.iterator(); it.hasNext();) { - TranslatingCompiler.OutputItem item = it.next(); - boolean shouldPostpone = false; - for (int idx = nextCompilerIdx; idx < myCompilers.length; idx++) { - shouldPostpone = myCompilers[idx].isCompilableFile(item.getSourceFile(), myContext); - if (shouldPostpone) { - break; - } - } - if (!shouldPostpone) { - // the file is not compilable by the rest of compilers, so it is safe to update it now - it.remove(); - addItemToMap(updateNow, outputDir, item); - } - } - } - // process items from current compilation - for (TranslatingCompiler.OutputItem item : items) { - boolean shouldPostpone = false; - for (int idx = nextCompilerIdx; idx < myCompilers.length; idx++) { - shouldPostpone = myCompilers[idx].isCompilableFile(item.getSourceFile(), myContext); - if (shouldPostpone) { - break; - } - } - if (shouldPostpone) { - // the file is compilable by the next compiler in row, update should be postponed - addItemToMap(myPostponedItems, outputRoot, item); - } - else { - addItemToMap(updateNow, outputRoot, item); - } - } - - if (updateNow.size() == 1) { - final Map.Entry> entry = updateNow.entrySet().iterator().next(); - final String outputDir = entry.getKey(); - final Collection itemsToUpdate = entry.getValue(); - TranslatingCompilerFilesMonitor.getInstance().update(myContext, outputDir, itemsToUpdate, filesToRecompile); - } - else { - for (Map.Entry> entry : updateNow.entrySet()) { - final String outputDir = entry.getKey(); - final Collection itemsToUpdate = entry.getValue(); - TranslatingCompilerFilesMonitor.getInstance().update(myContext, outputDir, itemsToUpdate, VirtualFile.EMPTY_ARRAY); - } - if (filesToRecompile.length > 0) { - TranslatingCompilerFilesMonitor.getInstance().update(myContext, null, Collections.emptyList(), filesToRecompile); - } - } - } - else { - TranslatingCompilerFilesMonitor.getInstance().update(myContext, outputRoot, items, filesToRecompile); - } - } - catch (IOException e) { - LOG.info(e); - myContext.requestRebuildNextTime(e.getMessage()); - } - } - - private static void addItemToMap(Map> map, String outputDir, TranslatingCompiler.OutputItem item) { - Collection collection = map.get(outputDir); - if (collection == null) { - collection = new ArrayList(); - map.put(outputDir, collection); - } - collection.add(item); - } - - public void flushPostponedItems() { - final TranslatingCompilerFilesMonitor filesMonitor = TranslatingCompilerFilesMonitor.getInstance(); - try { - for (Map.Entry> entry : myPostponedItems.entrySet()) { - final String outputDir = entry.getKey(); - final Collection items = entry.getValue(); - filesMonitor.update(myContext, outputDir, items, VirtualFile.EMPTY_ARRAY); - } - } - catch (IOException e) { - LOG.info(e); - myContext.requestRebuildNextTime(e.getMessage()); - } - } - } - - private static class DependentClassesCumulativeFilter implements Function>, Pair>> { - - private final TIntHashSet myProcessedNames = new TIntHashSet(); - private final Set myProcessedFiles = new HashSet(); - - public Pair> fun(Pair> deps) { - final TIntHashSet currentDeps = new TIntHashSet(deps.getFirst()); - currentDeps.removeAll(myProcessedNames.toArray()); - myProcessedNames.addAll(deps.getFirst()); - - final Set depFiles = new HashSet(deps.getSecond()); - depFiles.removeAll(myProcessedFiles); - myProcessedFiles.addAll(deps.getSecond()); - return new Pair>(currentDeps.toArray(), depFiles); - } - } -} +/* + * 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. + */ + +/** + * @author: Eugene Zhuravlev + * Date: Jan 17, 2003 + * Time: 1:42:26 PM + */ +package com.intellij.compiler.impl; + +import com.intellij.CommonBundle; +import com.intellij.compiler.*; +import com.intellij.compiler.make.CacheCorruptedException; +import com.intellij.compiler.make.CacheUtils; +import com.intellij.compiler.make.ChangedConstantsDependencyProcessor; +import com.intellij.compiler.make.DependencyCache; +import com.intellij.compiler.progress.CompilerTask; +import com.intellij.compiler.server.BuildManager; +import com.intellij.compiler.server.CustomBuilderMessageHandler; +import com.intellij.compiler.server.DefaultMessageHandler; +import com.intellij.diagnostic.IdeErrorsDialog; +import com.intellij.diagnostic.PluginException; +import com.intellij.openapi.application.*; +import com.intellij.openapi.compiler.*; +import com.intellij.openapi.compiler.Compiler; +import com.intellij.openapi.compiler.ex.CompileContextEx; +import com.intellij.openapi.compiler.ex.CompilerPathsEx; +import com.intellij.openapi.compiler.generic.GenericCompiler; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.extensions.PluginId; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.module.LanguageLevelUtil; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectBundle; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.*; +import com.intellij.openapi.roots.ex.ProjectRootManagerEx; +import com.intellij.openapi.roots.ui.configuration.CommonContentEntriesEditor; +import com.intellij.openapi.roots.ui.configuration.ProjectSettingsService; +import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.*; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.vfs.*; +import com.intellij.openapi.vfs.newvfs.ManagingFS; +import com.intellij.openapi.vfs.newvfs.RefreshQueue; +import com.intellij.openapi.wm.StatusBar; +import com.intellij.openapi.wm.ToolWindowId; +import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.packaging.artifacts.Artifact; +import com.intellij.packaging.artifacts.ArtifactManager; +import com.intellij.packaging.impl.artifacts.ArtifactImpl; +import com.intellij.packaging.impl.artifacts.ArtifactUtil; +import com.intellij.packaging.impl.compiler.ArtifactCompileScope; +import com.intellij.packaging.impl.compiler.ArtifactCompilerUtil; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.util.Chunk; +import com.intellij.util.Function; +import com.intellij.util.StringBuilderSpinAllocator; +import com.intellij.util.ThrowableRunnable; +import com.intellij.util.concurrency.Semaphore; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.HashMap; +import com.intellij.util.containers.MultiMap; +import com.intellij.util.containers.OrderedSet; +import com.intellij.util.messages.MessageBus; +import gnu.trove.TIntHashSet; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; +import org.jetbrains.jps.api.CmdlineProtoUtil; +import org.jetbrains.jps.api.CmdlineRemoteProto; +import org.jetbrains.jps.api.RequestFuture; +import org.jetbrains.jps.incremental.Utils; + +import javax.swing.*; +import java.io.*; +import java.util.*; +import java.util.concurrent.TimeUnit; + +import static org.jetbrains.jps.api.CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.TargetTypeBuildScope; + +public class CompileDriver { + + private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.CompileDriver"); + // to be used in tests only for debug output + public static volatile boolean ourDebugMode = false; + + private final Project myProject; + private final Map, Pair> myGenerationCompilerModuleToOutputDirMap; // [IntermediateOutputCompiler, Module] -> [ProductionSources, TestSources] + private final String myCachesDirectoryPath; + private boolean myShouldClearOutputDirectory; + + private final Map myModuleOutputPaths = new HashMap(); + private final Map myModuleTestOutputPaths = new HashMap(); + + @NonNls private static final String VERSION_FILE_NAME = "version.dat"; + @NonNls private static final String LOCK_FILE_NAME = "in_progress.dat"; + + private static final boolean GENERATE_CLASSPATH_INDEX = "true".equals(System.getProperty("generate.classpath.index")); + private static final String PROP_PERFORM_INITIAL_REFRESH = "compiler.perform.outputs.refresh.on.start"; + private static final Key REFRESH_DONE_KEY = Key.create("_compiler.initial.refresh.done_"); + + private static final FileProcessingCompilerAdapterFactory FILE_PROCESSING_COMPILER_ADAPTER_FACTORY = new FileProcessingCompilerAdapterFactory() { + public FileProcessingCompilerAdapter create(CompileContext context, FileProcessingCompiler compiler) { + return new FileProcessingCompilerAdapter(context, compiler); + } + }; + private static final FileProcessingCompilerAdapterFactory FILE_PACKAGING_COMPILER_ADAPTER_FACTORY = new FileProcessingCompilerAdapterFactory() { + public FileProcessingCompilerAdapter create(CompileContext context, FileProcessingCompiler compiler) { + return new PackagingCompilerAdapter(context, (PackagingCompiler)compiler); + } + }; + private CompilerFilter myCompilerFilter = CompilerFilter.ALL; + private static final CompilerFilter SOURCE_PROCESSING_ONLY = new CompilerFilter() { + public boolean acceptCompiler(Compiler compiler) { + return compiler instanceof SourceProcessingCompiler; + } + }; + private static final CompilerFilter ALL_EXCEPT_SOURCE_PROCESSING = new CompilerFilter() { + public boolean acceptCompiler(Compiler compiler) { + return !SOURCE_PROCESSING_ONLY.acceptCompiler(compiler); + } + }; + + private Set myAllOutputDirectories; + private static final long ONE_MINUTE_MS = 60L /*sec*/ * 1000L /*millisec*/; + + public CompileDriver(Project project) { + myProject = project; + myCachesDirectoryPath = CompilerPaths.getCacheStoreDirectory(myProject).getPath().replace('/', File.separatorChar); + myShouldClearOutputDirectory = CompilerWorkspaceConfiguration.getInstance(myProject).CLEAR_OUTPUT_DIRECTORY; + + myGenerationCompilerModuleToOutputDirMap = new HashMap, Pair>(); + + if (!useOutOfProcessBuild()) { + final LocalFileSystem lfs = LocalFileSystem.getInstance(); + final IntermediateOutputCompiler[] generatingCompilers = CompilerManager.getInstance(myProject).getCompilers(IntermediateOutputCompiler.class, myCompilerFilter); + final Module[] allModules = ModuleManager.getInstance(myProject).getModules(); + final CompilerConfiguration config = CompilerConfiguration.getInstance(project); + for (Module module : allModules) { + for (IntermediateOutputCompiler compiler : generatingCompilers) { + final VirtualFile productionOutput = lookupVFile(lfs, CompilerPaths.getGenerationOutputPath(compiler, module, false)); + final VirtualFile testOutput = lookupVFile(lfs, CompilerPaths.getGenerationOutputPath(compiler, module, true)); + final Pair pair = new Pair(compiler, module); + final Pair outputs = new Pair(productionOutput, testOutput); + myGenerationCompilerModuleToOutputDirMap.put(pair, outputs); + } + if (config.getAnnotationProcessingConfiguration(module).isEnabled()) { + final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module); + if (path != null) { + lookupVFile(lfs, path); // ensure the file is created and added to VFS + } + } + } + } + } + + public void setCompilerFilter(CompilerFilter compilerFilter) { + myCompilerFilter = compilerFilter == null? CompilerFilter.ALL : compilerFilter; + } + + public void rebuild(CompileStatusNotification callback) { + final CompileScope compileScope; + ProjectCompileScope projectScope = new ProjectCompileScope(myProject); + if (useOutOfProcessBuild()) { + compileScope = projectScope; + } + else { + CompileScope scopeWithArtifacts = ArtifactCompileScope.createScopeWithArtifacts(projectScope, ArtifactUtil.getArtifactWithOutputPaths(myProject), false); + compileScope = addAdditionalRoots(scopeWithArtifacts, ALL_EXCEPT_SOURCE_PROCESSING); + } + doRebuild(callback, null, true, compileScope); + } + + public void make(CompileScope scope, CompileStatusNotification callback) { + if (!useOutOfProcessBuild()) { + scope = addAdditionalRoots(scope, ALL_EXCEPT_SOURCE_PROCESSING); + } + if (validateCompilerConfiguration(scope, false)) { + startup(scope, false, false, callback, null, true); + } + else { + callback.finished(true, 0, 0, DummyCompileContext.getInstance()); + } + } + + public boolean isUpToDate(CompileScope scope) { + if (LOG.isDebugEnabled()) { + LOG.debug("isUpToDate operation started"); + } + if (!useOutOfProcessBuild()) { + scope = addAdditionalRoots(scope, ALL_EXCEPT_SOURCE_PROCESSING); + } + + final CompilerTask task = new CompilerTask(myProject, "Classes up-to-date check", true, false); + final DependencyCache cache = useOutOfProcessBuild()? null : createDependencyCache(); + final CompileContextImpl compileContext = new CompileContextImpl(myProject, task, scope, cache, true, false); + + if (!useOutOfProcessBuild()) { + checkCachesVersion(compileContext, ManagingFS.getInstance().getCreationTimestamp()); + if (compileContext.isRebuildRequested()) { + if (LOG.isDebugEnabled()) { + LOG.debug("Rebuild requested, up-to-date=false"); + } + return false; + } + + for (Map.Entry, Pair> entry : myGenerationCompilerModuleToOutputDirMap.entrySet()) { + final Pair outputs = entry.getValue(); + final Pair key = entry.getKey(); + final Module module = key.getSecond(); + compileContext.assignModule(outputs.getFirst(), module, false, key.getFirst()); + compileContext.assignModule(outputs.getSecond(), module, true, key.getFirst()); + } + } + + final Ref result = new Ref(); + + final Runnable compileWork; + if (useOutOfProcessBuild()) { + compileWork = new Runnable() { + public void run() { + final ProgressIndicator indicator = compileContext.getProgressIndicator(); + if (indicator.isCanceled() || myProject.isDisposed()) { + return; + } + try { + final Collection paths = CompileScopeUtil.fetchFiles(compileContext); + List scopes = new ArrayList(); + if (paths.isEmpty()) { + if (!compileContext.isRebuild() && !CompileScopeUtil.allProjectModulesAffected(compileContext)) { + CompileScopeUtil.addScopesForModules(Arrays.asList(compileContext.getCompileScope().getAffectedModules()), scopes); + } + else { + scopes.addAll(CmdlineProtoUtil.createAllModulesScopes()); + } + for (BuildTargetScopeProvider provider : BuildTargetScopeProvider.EP_NAME.getExtensions()) { + scopes = CompileScopeUtil.mergeScopes(scopes, provider.getBuildTargetScopes(compileContext.getCompileScope(), myCompilerFilter, myProject)); + } + } + final RequestFuture future = compileInExternalProcess(compileContext, scopes, paths, true); + if (future != null) { + while (!future.waitFor(200L , TimeUnit.MILLISECONDS)) { + if (indicator.isCanceled()) { + future.cancel(false); + } + } + } + } + catch (Throwable e) { + LOG.error(e); + } + finally { + result.set(COMPILE_SERVER_BUILD_STATUS.get(compileContext)); + CompilerCacheManager.getInstance(myProject).flushCaches(); + } + } + }; + } + else { + compileWork = new Runnable() { + public void run() { + try { + myAllOutputDirectories = getAllOutputDirectories(compileContext); + // need this for updating zip archives experiment, uncomment if the feature is turned on + //myOutputFinder = new OutputPathFinder(myAllOutputDirectories); + result.set(doCompile(compileContext, false, false, true)); + } + finally { + CompilerCacheManager.getInstance(myProject).flushCaches(); + } + } + }; + } + task.start(compileWork, null); + + if (LOG.isDebugEnabled()) { + LOG.debug("isUpToDate operation finished"); + } + + return ExitStatus.UP_TO_DATE.equals(result.get()); + } + + private DependencyCache createDependencyCache() { + return new DependencyCache(myCachesDirectoryPath + File.separator + ".dependency-info"); + } + + public void compile(CompileScope scope, CompileStatusNotification callback, boolean clearingOutputDirsPossible) { + myShouldClearOutputDirectory &= clearingOutputDirsPossible; + if (containsFileIndexScopes(scope)) { + scope = addAdditionalRoots(scope, ALL_EXCEPT_SOURCE_PROCESSING); + } + if (validateCompilerConfiguration(scope, false)) { + startup(scope, false, true, callback, null, true); + } + else { + callback.finished(true, 0, 0, DummyCompileContext.getInstance()); + } + } + + private static boolean containsFileIndexScopes(CompileScope scope) { + if (scope instanceof CompositeScope) { + for (CompileScope childScope : ((CompositeScope)scope).getScopes()) { + if (containsFileIndexScopes(childScope)) { + return true; + } + } + } + return scope instanceof FileIndexCompileScope; + } + + private static class CompileStatus { + final int CACHE_FORMAT_VERSION; + final boolean COMPILATION_IN_PROGRESS; + final long VFS_CREATION_STAMP; + + private CompileStatus(int cacheVersion, boolean isCompilationInProgress, long vfsStamp) { + CACHE_FORMAT_VERSION = cacheVersion; + COMPILATION_IN_PROGRESS = isCompilationInProgress; + VFS_CREATION_STAMP = vfsStamp; + } + } + + private CompileStatus readStatus() { + final boolean isInProgress = getLockFile().exists(); + int version = -1; + long vfsStamp = -1L; + try { + final File versionFile = new File(myCachesDirectoryPath, VERSION_FILE_NAME); + DataInputStream in = new DataInputStream(new FileInputStream(versionFile)); + try { + version = in.readInt(); + try { + vfsStamp = in.readLong(); + } + catch (IOException ignored) { + } + } + finally { + in.close(); + } + } + catch (FileNotFoundException e) { + // ignore + } + catch (IOException e) { + LOG.info(e); // may happen in case of IDEA crashed and the file is not written properly + return null; + } + return new CompileStatus(version, isInProgress, vfsStamp); + } + + private void writeStatus(CompileStatus status, CompileContext context) { + final File statusFile = new File(myCachesDirectoryPath, VERSION_FILE_NAME); + + final File lockFile = getLockFile(); + try { + FileUtil.createIfDoesntExist(statusFile); + DataOutputStream out = new DataOutputStream(new FileOutputStream(statusFile)); + try { + out.writeInt(status.CACHE_FORMAT_VERSION); + out.writeLong(status.VFS_CREATION_STAMP); + } + finally { + out.close(); + } + if (status.COMPILATION_IN_PROGRESS) { + FileUtil.createIfDoesntExist(lockFile); + } + else { + deleteFile(lockFile); + } + } + catch (IOException e) { + context.addMessage(CompilerMessageCategory.ERROR, CompilerBundle.message("compiler.error.exception", e.getMessage()), null, -1, -1); + } + } + + private File getLockFile() { + return new File(CompilerPaths.getCompilerSystemDirectory(myProject), LOCK_FILE_NAME); + } + + private void doRebuild(CompileStatusNotification callback, + CompilerMessage message, + final boolean checkCachesVersion, + final CompileScope compileScope) { + if (validateCompilerConfiguration(compileScope, !useOutOfProcessBuild())) { + startup(compileScope, true, false, callback, message, checkCachesVersion); + } + else { + callback.finished(true, 0, 0, DummyCompileContext.getInstance()); + } + } + + private CompileScope addAdditionalRoots(CompileScope originalScope, final CompilerFilter filter) { + CompileScope scope = attachIntermediateOutputDirectories(originalScope, filter); + + final AdditionalCompileScopeProvider[] scopeProviders = Extensions.getExtensions(AdditionalCompileScopeProvider.EXTENSION_POINT_NAME); + CompileScope baseScope = scope; + for (AdditionalCompileScopeProvider scopeProvider : scopeProviders) { + final CompileScope additionalScope = scopeProvider.getAdditionalScope(baseScope, filter, myProject); + if (additionalScope != null) { + scope = new CompositeScope(scope, additionalScope); + } + } + return scope; + } + + private CompileScope attachIntermediateOutputDirectories(CompileScope originalScope, CompilerFilter filter) { + CompileScope scope = originalScope; + final Set affected = new HashSet(Arrays.asList(originalScope.getAffectedModules())); + for (Map.Entry, Pair> entry : myGenerationCompilerModuleToOutputDirMap.entrySet()) { + final Module module = entry.getKey().getSecond(); + if (affected.contains(module) && filter.acceptCompiler(entry.getKey().getFirst())) { + final Pair outputs = entry.getValue(); + scope = new CompositeScope(scope, new FileSetCompileScope(Arrays.asList(outputs.getFirst(), outputs.getSecond()), new Module[]{module})); + } + } + return scope; + } + + private void attachAnnotationProcessorsOutputDirectories(CompileContextEx context) { + final LocalFileSystem lfs = LocalFileSystem.getInstance(); + final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject); + final Set affected = new HashSet(Arrays.asList(context.getCompileScope().getAffectedModules())); + for (Module module : affected) { + if (!config.getAnnotationProcessingConfiguration(module).isEnabled()) { + continue; + } + final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module); + if (path == null) { + continue; + } + final VirtualFile vFile = lfs.findFileByPath(path); + if (vFile == null) { + continue; + } + if (ModuleRootManager.getInstance(module).getFileIndex().isInSourceContent(vFile)) { + // no need to add, is already marked as source + continue; + } + context.addScope(new FileSetCompileScope(Collections.singletonList(vFile), new Module[]{module})); + context.assignModule(vFile, module, false, null); + } + } + + @Nullable + private RequestFuture compileInExternalProcess(final @NotNull CompileContextImpl compileContext, + @NotNull List scopes, + final @NotNull Collection paths, + final boolean onlyCheckUpToDate) + throws Exception { + final CompileScope scope = compileContext.getCompileScope(); + // need to pass scope's user data to server + final Map builderParams; + if (onlyCheckUpToDate) { + builderParams = Collections.emptyMap(); + } + else { + final Map exported = scope.exportUserData(); + if (!exported.isEmpty()) { + builderParams = new HashMap(); + for (Map.Entry entry : exported.entrySet()) { + final String _key = entry.getKey().toString(); + final String _value = entry.getValue().toString(); + builderParams.put(_key, _value); + } + } + else { + builderParams = Collections.emptyMap(); + } + } + + final MessageBus messageBus = myProject.getMessageBus(); + + final BuildManager buildManager = BuildManager.getInstance(); + buildManager.cancelAutoMakeTasks(myProject); + return buildManager.scheduleBuild(myProject, compileContext.isRebuild(), compileContext.isMake(), onlyCheckUpToDate, scopes, paths, builderParams, new DefaultMessageHandler(myProject) { + + @Override + public void buildStarted(UUID sessionId) { + } + + @Override + public void sessionTerminated(final UUID sessionId) { + if (compileContext.shouldUpdateProblemsView()) { + final ProblemsView view = ProblemsViewImpl.SERVICE.getInstance(myProject); + view.clearProgress(); + view.clearOldMessages(compileContext.getCompileScope(), compileContext.getSessionId()); + } + } + + @Override + public void handleFailure(UUID sessionId, CmdlineRemoteProto.Message.Failure failure) { + compileContext.addMessage(CompilerMessageCategory.ERROR, failure.getDescription(), null, -1, -1); + final String trace = failure.getStacktrace(); + if (trace != null) { + LOG.info(trace); + System.out.println(trace); + } + compileContext.putUserData(COMPILE_SERVER_BUILD_STATUS, ExitStatus.ERRORS); + } + + @Override + protected void handleCompileMessage(UUID sessionId, CmdlineRemoteProto.Message.BuilderMessage.CompileMessage message) { + final CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind kind = message.getKind(); + //System.out.println(compilerMessage.getText()); + final String messageText = message.getText(); + if (kind == CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind.PROGRESS) { + final ProgressIndicator indicator = compileContext.getProgressIndicator(); + indicator.setText(messageText); + if (message.hasDone()) { + indicator.setFraction(message.getDone()); + } + } + else { + final CompilerMessageCategory category = kind == CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind.ERROR ? CompilerMessageCategory.ERROR + : kind == CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind.WARNING ? CompilerMessageCategory.WARNING : CompilerMessageCategory.INFORMATION; + + String sourceFilePath = message.hasSourceFilePath() ? message.getSourceFilePath() : null; + if (sourceFilePath != null) { + sourceFilePath = FileUtil.toSystemIndependentName(sourceFilePath); + } + final long line = message.hasLine() ? message.getLine() : -1; + final long column = message.hasColumn() ? message.getColumn() : -1; + final String srcUrl = sourceFilePath != null ? VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, sourceFilePath) : null; + compileContext.addMessage(category, messageText, srcUrl, (int)line, (int)column); + } + } + + @Override + protected void handleBuildEvent(UUID sessionId, CmdlineRemoteProto.Message.BuilderMessage.BuildEvent event) { + final CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Type eventType = event.getEventType(); + switch (eventType) { + case FILES_GENERATED: + final List generated = event.getGeneratedFilesList(); + final CompilationStatusListener publisher = messageBus.syncPublisher(CompilerTopics.COMPILATION_STATUS); + for (CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.GeneratedFile generatedFile : generated) { + final String root = FileUtil.toSystemIndependentName(generatedFile.getOutputRoot()); + final String relativePath = FileUtil.toSystemIndependentName(generatedFile.getRelativePath()); + publisher.fileGenerated(root, relativePath); + } + break; + case BUILD_COMPLETED: + ExitStatus status = ExitStatus.SUCCESS; + if (event.hasCompletionStatus()) { + final CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status completionStatus = event.getCompletionStatus(); + switch (completionStatus) { + case CANCELED: + status = ExitStatus.CANCELLED; + break; + case ERRORS: + status = ExitStatus.ERRORS; + break; + case SUCCESS: + status = ExitStatus.SUCCESS; + break; + case UP_TO_DATE: + status = ExitStatus.UP_TO_DATE; + break; + } + } + compileContext.putUserDataIfAbsent(COMPILE_SERVER_BUILD_STATUS, status); + break; + case CUSTOM_BUILDER_MESSAGE: + if (event.hasCustomBuilderMessage()) { + CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.CustomBuilderMessage message = event.getCustomBuilderMessage(); + messageBus.syncPublisher(CustomBuilderMessageHandler.TOPIC).messageReceived(message.getBuilderId(), message.getMessageType(), + message.getMessageText()); + } + break; + } + } + }); + } + + + private static final Key COMPILE_SERVER_BUILD_STATUS = Key.create("COMPILE_SERVER_BUILD_STATUS"); + + private void startup(final CompileScope scope, + final boolean isRebuild, + final boolean forceCompile, + final CompileStatusNotification callback, + final CompilerMessage message, + final boolean checkCachesVersion) { + ApplicationManager.getApplication().assertIsDispatchThread(); + + final boolean useExtProcessBuild = useOutOfProcessBuild(); + + final String contentName = + forceCompile ? CompilerBundle.message("compiler.content.name.compile") : CompilerBundle.message("compiler.content.name.make"); + final CompilerTask compileTask = new CompilerTask(myProject, contentName, ApplicationManager.getApplication().isUnitTestMode(), true); + + StatusBar.Info.set("", myProject, "Compiler"); + if (useExtProcessBuild) { + // ensure the project model seen by build process is up-to-date + myProject.save(); + } + PsiDocumentManager.getInstance(myProject).commitAllDocuments(); + FileDocumentManager.getInstance().saveAllDocuments(); + + final DependencyCache dependencyCache = useExtProcessBuild ? null: createDependencyCache(); + final CompileContextImpl compileContext = + new CompileContextImpl(myProject, compileTask, scope, dependencyCache, !isRebuild && !forceCompile, isRebuild); + + if (!useExtProcessBuild) { + for (Map.Entry, Pair> entry : myGenerationCompilerModuleToOutputDirMap.entrySet()) { + final Pair outputs = entry.getValue(); + final Pair key = entry.getKey(); + final Module module = key.getSecond(); + compileContext.assignModule(outputs.getFirst(), module, false, key.getFirst()); + compileContext.assignModule(outputs.getSecond(), module, true, key.getFirst()); + } + attachAnnotationProcessorsOutputDirectories(compileContext); + } + + final Runnable compileWork; + if (useExtProcessBuild) { + compileWork = new Runnable() { + public void run() { + final ProgressIndicator indicator = compileContext.getProgressIndicator(); + if (indicator.isCanceled() || myProject.isDisposed()) { + if (callback != null) { + callback.finished(true, 0, 0, compileContext); + } + return; + } + try { + LOG.info("COMPILATION STARTED (BUILD PROCESS)"); + if (message != null) { + compileContext.addMessage(message); + } + if (!executeCompileTasks(compileContext, true)) { + COMPILE_SERVER_BUILD_STATUS.set(compileContext, ExitStatus.CANCELLED); + return; + } + + final Collection paths = CompileScopeUtil.fetchFiles(compileContext); + List scopes = new ArrayList(); + if (paths.isEmpty()) { + if (!isRebuild && !CompileScopeUtil.allProjectModulesAffected(compileContext)) { + CompileScopeUtil.addScopesForModules(Arrays.asList(compileContext.getCompileScope().getAffectedModules()), scopes); + } + else { + scopes.addAll(CmdlineProtoUtil.createAllModulesScopes()); + } + for (BuildTargetScopeProvider provider : BuildTargetScopeProvider.EP_NAME.getExtensions()) { + scopes = CompileScopeUtil.mergeScopes(scopes, provider.getBuildTargetScopes(scope, myCompilerFilter, myProject)); + } + } + final RequestFuture future = compileInExternalProcess(compileContext, scopes, paths, false); + if (future != null) { + while (!future.waitFor(200L , TimeUnit.MILLISECONDS)) { + if (indicator.isCanceled()) { + future.cancel(false); + } + } + if (!executeCompileTasks(compileContext, false)) { + COMPILE_SERVER_BUILD_STATUS.set(compileContext, ExitStatus.CANCELLED); + return; + } + } + } + catch (Throwable e) { + LOG.error(e); // todo + } + finally { + CompilerCacheManager.getInstance(myProject).flushCaches(); + + final long duration = notifyCompilationCompleted(compileContext, callback, COMPILE_SERVER_BUILD_STATUS.get(compileContext)); + CompilerUtil.logDuration( + "\tCOMPILATION FINISHED (BUILD PROCESS); Errors: " + + compileContext.getMessageCount(CompilerMessageCategory.ERROR) + + "; warnings: " + + compileContext.getMessageCount(CompilerMessageCategory.WARNING), + duration + ); + + // refresh on output roots is required in order for the order enumerator to see all roots via VFS + final Set outputs = new HashSet(); + for (final String path : CompilerPathsEx.getOutputPaths(ModuleManager.getInstance(myProject).getModules())) { + outputs.add(new File(path)); + } + if (!outputs.isEmpty()) { + LocalFileSystem.getInstance().refreshIoFiles(outputs, true, false, null); + } + } + } + }; + } + else { + compileWork = new Runnable() { + public void run() { + if (compileContext.getProgressIndicator().isCanceled()) { + if (callback != null) { + callback.finished(true, 0, 0, compileContext); + } + return; + } + try { + if (myProject.isDisposed()) { + return; + } + LOG.info("COMPILATION STARTED"); + if (message != null) { + compileContext.addMessage(message); + } + TranslatingCompilerFilesMonitor.getInstance().ensureInitializationCompleted(myProject, compileContext.getProgressIndicator()); + doCompile(compileContext, isRebuild, forceCompile, callback, checkCachesVersion); + } + finally { + FileUtil.delete(CompilerPaths.getRebuildMarkerFile(myProject)); + } + } + }; + } + + compileTask.start(compileWork, new Runnable() { + public void run() { + if (isRebuild) { + final int rv = Messages.showOkCancelDialog( + myProject, "You are about to rebuild the whole project.\nRun 'Make Project' instead?", "Confirm Project Rebuild", + "Make", "Rebuild", Messages.getQuestionIcon() + ); + if (rv == 0 /*yes, please, do run make*/) { + startup(scope, false, false, callback, null, checkCachesVersion); + return; + } + } + startup(scope, isRebuild, forceCompile, callback, message, checkCachesVersion); + } + }); + } + + @Nullable @TestOnly + public static ExitStatus getExternalBuildExitStatus(CompileContext context) { + return context.getUserData(COMPILE_SERVER_BUILD_STATUS); + } + + private void doCompile(final CompileContextImpl compileContext, + final boolean isRebuild, + final boolean forceCompile, + final CompileStatusNotification callback, + final boolean checkCachesVersion) { + ExitStatus status = ExitStatus.ERRORS; + boolean wereExceptions = false; + final long vfsTimestamp = (ManagingFS.getInstance()).getCreationTimestamp(); + try { + if (checkCachesVersion) { + checkCachesVersion(compileContext, vfsTimestamp); + if (compileContext.isRebuildRequested()) { + return; + } + } + writeStatus(new CompileStatus(CompilerConfigurationImpl.DEPENDENCY_FORMAT_VERSION, true, vfsTimestamp), compileContext); + if (compileContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) { + return; + } + + myAllOutputDirectories = getAllOutputDirectories(compileContext); + status = doCompile(compileContext, isRebuild, forceCompile, false); + } + catch (Throwable ex) { + if (ApplicationManager.getApplication().isUnitTestMode()) { + throw new RuntimeException(ex); + } + wereExceptions = true; + final PluginId pluginId = IdeErrorsDialog.findPluginId(ex); + + final StringBuilder message = new StringBuilder(); + message.append("Internal error"); + if (pluginId != null) { + message.append(" (Plugin: ").append(pluginId).append(")"); + } + message.append(": ").append(ex.getMessage()); + compileContext.addMessage(CompilerMessageCategory.ERROR, message.toString(), null, -1, -1); + + if (pluginId != null) { + throw new PluginException(ex, pluginId); + } + throw new RuntimeException(ex); + } + finally { + dropDependencyCache(compileContext); + CompilerCacheManager.getInstance(myProject).flushCaches(); + if (compileContext.isRebuildRequested()) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + final CompilerMessageImpl msg = new CompilerMessageImpl(myProject, CompilerMessageCategory.INFORMATION, compileContext.getRebuildReason()); + doRebuild(callback, msg, false, compileContext.getCompileScope()); + } + }, ModalityState.NON_MODAL); + } + else { + if (!myProject.isDisposed()) { + writeStatus(new CompileStatus(CompilerConfigurationImpl.DEPENDENCY_FORMAT_VERSION, wereExceptions, vfsTimestamp), compileContext); + } + final long duration = notifyCompilationCompleted(compileContext, callback, status); + CompilerUtil.logDuration( + "\tCOMPILATION FINISHED; Errors: " + + compileContext.getMessageCount(CompilerMessageCategory.ERROR) + + "; warnings: " + + compileContext.getMessageCount(CompilerMessageCategory.WARNING), + duration + ); + } + } + } + + /** @noinspection SSBasedInspection*/ + private long notifyCompilationCompleted(final CompileContextImpl compileContext, final CompileStatusNotification callback, final ExitStatus _status) { + final long duration = System.currentTimeMillis() - compileContext.getStartCompilationStamp(); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + int errorCount = 0; + int warningCount = 0; + try { + errorCount = compileContext.getMessageCount(CompilerMessageCategory.ERROR); + warningCount = compileContext.getMessageCount(CompilerMessageCategory.WARNING); + if (!myProject.isDisposed()) { + final String statusMessage = createStatusMessage(_status, warningCount, errorCount, duration); + final MessageType messageType = errorCount > 0 ? MessageType.ERROR : warningCount > 0 ? MessageType.WARNING : MessageType.INFO; + if (duration > ONE_MINUTE_MS) { + ToolWindowManager.getInstance(myProject).notifyByBalloon(ToolWindowId.MESSAGES_WINDOW, messageType, statusMessage); + } + CompilerManager.NOTIFICATION_GROUP.createNotification(statusMessage, messageType).notify(myProject); + if (_status != ExitStatus.UP_TO_DATE && compileContext.getMessageCount(null) > 0) { + compileContext.addMessage(CompilerMessageCategory.INFORMATION, statusMessage, null, -1, -1); + } + } + } + finally { + if (callback != null) { + callback.finished(_status == ExitStatus.CANCELLED, errorCount, warningCount, compileContext); + } + } + } + }); + return duration; + } + + private void checkCachesVersion(final CompileContextImpl compileContext, final long currentVFSTimestamp) { + if (CompilerPaths.getRebuildMarkerFile(compileContext.getProject()).exists()) { + compileContext.requestRebuildNextTime("Compiler caches are out of date, project rebuild is required"); + return; + } + final CompileStatus compileStatus = readStatus(); + if (compileStatus == null) { + compileContext.requestRebuildNextTime(CompilerBundle.message("error.compiler.caches.corrupted")); + } + else if (compileStatus.CACHE_FORMAT_VERSION != -1 && + compileStatus.CACHE_FORMAT_VERSION != CompilerConfigurationImpl.DEPENDENCY_FORMAT_VERSION) { + compileContext.requestRebuildNextTime(CompilerBundle.message("error.caches.old.format")); + } + else if (compileStatus.COMPILATION_IN_PROGRESS) { + compileContext.requestRebuildNextTime(CompilerBundle.message("error.previous.compilation.failed")); + } + else if (compileStatus.VFS_CREATION_STAMP >= 0L){ + if (currentVFSTimestamp != compileStatus.VFS_CREATION_STAMP) { + compileContext.requestRebuildNextTime(CompilerBundle.message("error.vfs.was.rebuilt")); + } + } + } + + private static String createStatusMessage(final ExitStatus status, final int warningCount, final int errorCount, long duration) { + String message; + if (status == ExitStatus.CANCELLED) { + message = CompilerBundle.message("status.compilation.aborted"); + } + else if (status == ExitStatus.UP_TO_DATE) { + message = CompilerBundle.message("status.all.up.to.date"); + } + else { + if (status == ExitStatus.SUCCESS) { + message = warningCount > 0 + ? CompilerBundle.message("status.compilation.completed.successfully.with.warnings", warningCount) + : CompilerBundle.message("status.compilation.completed.successfully"); + } + else { + message = CompilerBundle.message("status.compilation.completed.successfully.with.warnings.and.errors", errorCount, warningCount); + } + message = message + " in " + Utils.formatDuration(duration); + } + return message; + } + + private ExitStatus doCompile(final CompileContextEx context, boolean isRebuild, final boolean forceCompile, final boolean onlyCheckStatus) { + try { + if (isRebuild) { + deleteAll(context); + } + else if (forceCompile) { + if (myShouldClearOutputDirectory) { + clearAffectedOutputPathsIfPossible(context); + } + } + if (context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { + if (LOG.isDebugEnabled()) { + logErrorMessages(context); + } + return ExitStatus.ERRORS; + } + + if (!onlyCheckStatus) { + if (!executeCompileTasks(context, true)) { + if (LOG.isDebugEnabled()) { + LOG.debug("Compilation cancelled"); + } + return ExitStatus.CANCELLED; + } + } + + if (context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { + if (LOG.isDebugEnabled()) { + logErrorMessages(context); + } + return ExitStatus.ERRORS; + } + + boolean needRecalcOutputDirs = false; + if (Registry.is(PROP_PERFORM_INITIAL_REFRESH) || !Boolean.valueOf(REFRESH_DONE_KEY.get(myProject, Boolean.FALSE))) { + REFRESH_DONE_KEY.set(myProject, Boolean.TRUE); + final long refreshStart = System.currentTimeMillis(); + + //need this to make sure the VFS is built + final List outputsToRefresh = new ArrayList(); + + final VirtualFile[] all = context.getAllOutputDirectories(); + + final ProgressIndicator progressIndicator = context.getProgressIndicator(); + + //final int totalCount = all.length + myGenerationCompilerModuleToOutputDirMap.size() * 2; + progressIndicator.pushState(); + progressIndicator.setText("Inspecting output directories..."); + try { + for (VirtualFile output : all) { + if (output.isValid()) { + walkChildren(output, context); + } + else { + needRecalcOutputDirs = true; + final File file = new File(output.getPath()); + if (!file.exists()) { + final boolean created = file.mkdirs(); + if (!created) { + context.addMessage(CompilerMessageCategory.ERROR, "Failed to create output directory " + file.getPath(), null, 0, 0); + return ExitStatus.ERRORS; + } + } + output = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); + if (output == null) { + context.addMessage(CompilerMessageCategory.ERROR, "Failed to locate output directory " + file.getPath(), null, 0, 0); + return ExitStatus.ERRORS; + } + } + outputsToRefresh.add(output); + } + for (Pair pair : myGenerationCompilerModuleToOutputDirMap.keySet()) { + final Pair generated = myGenerationCompilerModuleToOutputDirMap.get(pair); + walkChildren(generated.getFirst(), context); + outputsToRefresh.add(generated.getFirst()); + walkChildren(generated.getSecond(), context); + outputsToRefresh.add(generated.getSecond()); + } + + RefreshQueue.getInstance().refresh(false, true, null, outputsToRefresh); + if (progressIndicator.isCanceled()) { + return ExitStatus.CANCELLED; + } + } + finally { + progressIndicator.popState(); + } + + final long initialRefreshTime = System.currentTimeMillis() - refreshStart; + CompilerUtil.logDuration("Initial VFS refresh", initialRefreshTime); + } + + //DumbService.getInstance(myProject).waitForSmartMode(); + final Semaphore semaphore = new Semaphore(); + semaphore.down(); + DumbService.getInstance(myProject).runWhenSmart(new Runnable() { + public void run() { + semaphore.up(); + } + }); + while (!semaphore.waitFor(500)) { + if (context.getProgressIndicator().isCanceled()) { + return ExitStatus.CANCELLED; + } + } + + if (needRecalcOutputDirs) { + context.recalculateOutputDirs(); + } + + boolean didSomething = false; + + final CompilerManager compilerManager = CompilerManager.getInstance(myProject); + GenericCompilerRunner runner = new GenericCompilerRunner(context, isRebuild, onlyCheckStatus, + compilerManager.getCompilers(GenericCompiler.class, myCompilerFilter)); + try { + didSomething |= generateSources(compilerManager, context, forceCompile, onlyCheckStatus); + + didSomething |= invokeFileProcessingCompilers(compilerManager, context, SourceInstrumentingCompiler.class, + FILE_PROCESSING_COMPILER_ADAPTER_FACTORY, forceCompile, true, onlyCheckStatus); + + didSomething |= invokeFileProcessingCompilers(compilerManager, context, SourceProcessingCompiler.class, + FILE_PROCESSING_COMPILER_ADAPTER_FACTORY, forceCompile, true, onlyCheckStatus); + + final CompileScope intermediateSources = attachIntermediateOutputDirectories(new CompositeScope(CompileScope.EMPTY_ARRAY) { + @NotNull + public Module[] getAffectedModules() { + return context.getCompileScope().getAffectedModules(); + } + }, SOURCE_PROCESSING_ONLY); + context.addScope(intermediateSources); + + didSomething |= translate(context, compilerManager, forceCompile, isRebuild, onlyCheckStatus); + + didSomething |= invokeFileProcessingCompilers(compilerManager, context, ClassInstrumentingCompiler.class, + FILE_PROCESSING_COMPILER_ADAPTER_FACTORY, isRebuild, false, onlyCheckStatus); + didSomething |= runner.invokeCompilers(GenericCompiler.CompileOrderPlace.CLASS_INSTRUMENTING); + + // explicitly passing forceCompile = false because in scopes that is narrower than ProjectScope it is impossible + // to understand whether the class to be processed is in scope or not. Otherwise compiler may process its items even if + // there were changes in completely independent files. + didSomething |= invokeFileProcessingCompilers(compilerManager, context, ClassPostProcessingCompiler.class, + FILE_PROCESSING_COMPILER_ADAPTER_FACTORY, isRebuild, false, onlyCheckStatus); + didSomething |= runner.invokeCompilers(GenericCompiler.CompileOrderPlace.CLASS_POST_PROCESSING); + + didSomething |= invokeFileProcessingCompilers(compilerManager, context, PackagingCompiler.class, + FILE_PACKAGING_COMPILER_ADAPTER_FACTORY, + isRebuild, false, onlyCheckStatus); + didSomething |= runner.invokeCompilers(GenericCompiler.CompileOrderPlace.PACKAGING); + + didSomething |= invokeFileProcessingCompilers(compilerManager, context, Validator.class, FILE_PROCESSING_COMPILER_ADAPTER_FACTORY, + forceCompile, true, onlyCheckStatus); + didSomething |= runner.invokeCompilers(GenericCompiler.CompileOrderPlace.VALIDATING); + } + catch (ExitException e) { + if (LOG.isDebugEnabled()) { + LOG.debug(e); + logErrorMessages(context); + } + return e.getExitStatus(); + } + finally { + // drop in case it has not been dropped yet. + dropDependencyCache(context); + final VirtualFile[] allOutputDirs = context.getAllOutputDirectories(); + + if (didSomething && GENERATE_CLASSPATH_INDEX) { + CompilerUtil.runInContext(context, "Generating classpath index...", new ThrowableRunnable(){ + public void run() { + int count = 0; + for (VirtualFile file : allOutputDirs) { + context.getProgressIndicator().setFraction((double)++count / allOutputDirs.length); + createClasspathIndex(file); + } + } + }); + } + + } + + if (!onlyCheckStatus) { + if (!executeCompileTasks(context, false)) { + return ExitStatus.CANCELLED; + } + final int constantSearchesCount = ChangedConstantsDependencyProcessor.getConstantSearchesCount(context); + LOG.debug("Constants searches: " + constantSearchesCount); + } + + if (context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { + if (LOG.isDebugEnabled()) { + logErrorMessages(context); + } + return ExitStatus.ERRORS; + } + if (!didSomething) { + return ExitStatus.UP_TO_DATE; + } + return ExitStatus.SUCCESS; + } + catch (ProcessCanceledException e) { + return ExitStatus.CANCELLED; + } + } + + private void clearAffectedOutputPathsIfPossible(final CompileContextEx context) { + final List scopeOutputs = new ReadAction>() { + protected void run(final Result> result) { + final MultiMap outputToModulesMap = new MultiMap(); + for (Module module : ModuleManager.getInstance(myProject).getModules()) { + final CompilerModuleExtension compilerModuleExtension = CompilerModuleExtension.getInstance(module); + if (compilerModuleExtension == null) { + continue; + } + final String outputPathUrl = compilerModuleExtension.getCompilerOutputUrl(); + if (outputPathUrl != null) { + final String path = VirtualFileManager.extractPath(outputPathUrl); + outputToModulesMap.putValue(new File(path), module); + } + + final String outputPathForTestsUrl = compilerModuleExtension.getCompilerOutputUrlForTests(); + if (outputPathForTestsUrl != null) { + final String path = VirtualFileManager.extractPath(outputPathForTestsUrl); + outputToModulesMap.putValue(new File(path), module); + } + } + final Set affectedModules = new HashSet(Arrays.asList(context.getCompileScope().getAffectedModules())); + List scopeOutputs = new ArrayList(affectedModules.size() * 2); + for (File output : outputToModulesMap.keySet()) { + if (affectedModules.containsAll(outputToModulesMap.get(output))) { + scopeOutputs.add(output); + } + } + + final Set artifactsToBuild = ArtifactCompileScope.getArtifactsToBuild(myProject, context.getCompileScope(), true); + for (Artifact artifact : artifactsToBuild) { + final String outputFilePath = ((ArtifactImpl)artifact).getOutputDirectoryPathToCleanOnRebuild(); + if (outputFilePath != null) { + scopeOutputs.add(new File(FileUtil.toSystemDependentName(outputFilePath))); + } + } + result.setResult(scopeOutputs); + } + }.execute().getResultObject(); + if (scopeOutputs.size() > 0) { + CompilerUtil.runInContext(context, CompilerBundle.message("progress.clearing.output"), new ThrowableRunnable() { + public void run() { + CompilerUtil.clearOutputDirectories(scopeOutputs); + } + }); + } + } + + private static void logErrorMessages(final CompileContext context) { + final CompilerMessage[] errors = context.getMessages(CompilerMessageCategory.ERROR); + if (errors.length > 0) { + LOG.debug("Errors reported: "); + for (CompilerMessage error : errors) { + LOG.debug("\t" + error.getMessage()); + } + } + } + + private static void walkChildren(VirtualFile from, final CompileContext context) { + VfsUtilCore.visitChildrenRecursively(from, new VirtualFileVisitor() { + @Override + public boolean visitFile(@NotNull VirtualFile file) { + if (file.isDirectory()) { + context.getProgressIndicator().checkCanceled(); + context.getProgressIndicator().setText2(file.getPresentableUrl()); + } + return true; + } + }); + } + + private static void createClasspathIndex(final VirtualFile file) { + try { + BufferedWriter writer = new BufferedWriter(new FileWriter(new File(VfsUtilCore.virtualToIoFile(file), "classpath.index"))); + try { + writeIndex(writer, file, file); + } + finally { + writer.close(); + } + } + catch (IOException e) { + // Ignore. Failed to create optional classpath index + } + } + + private static void writeIndex(final BufferedWriter writer, final VirtualFile root, final VirtualFile file) throws IOException { + VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() { + @Override + public boolean visitFile(@NotNull VirtualFile file) { + try { + writer.write(VfsUtilCore.getRelativePath(file, root, '/')); + writer.write('\n'); + return true; + } + catch (IOException e) { + throw new VisitorException(e); + } + } + }, IOException.class); + } + + private static void dropDependencyCache(final CompileContextEx context) { + CompilerUtil.runInContext(context, CompilerBundle.message("progress.saving.caches"), new ThrowableRunnable(){ + public void run() { + context.getDependencyCache().resetState(); + } + }); + } + + private boolean generateSources(final CompilerManager compilerManager, + CompileContextEx context, + final boolean forceCompile, + final boolean onlyCheckStatus) throws ExitException { + boolean didSomething = false; + + final SourceGeneratingCompiler[] sourceGenerators = compilerManager.getCompilers(SourceGeneratingCompiler.class, myCompilerFilter); + for (final SourceGeneratingCompiler sourceGenerator : sourceGenerators) { + if (context.getProgressIndicator().isCanceled()) { + throw new ExitException(ExitStatus.CANCELLED); + } + + final boolean generatedSomething = generateOutput(context, sourceGenerator, forceCompile, onlyCheckStatus); + + if (context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { + throw new ExitException(ExitStatus.ERRORS); + } + didSomething |= generatedSomething; + } + return didSomething; + } + + private boolean translate(final CompileContextEx context, + final CompilerManager compilerManager, + final boolean forceCompile, + boolean isRebuild, + final boolean onlyCheckStatus) throws ExitException { + + boolean didSomething = false; + + final TranslatingCompiler[] translators = compilerManager.getCompilers(TranslatingCompiler.class, myCompilerFilter); + + + final List> sortedChunks = Collections.unmodifiableList(ApplicationManager.getApplication().runReadAction(new Computable>>() { + public List> compute() { + final ModuleManager moduleManager = ModuleManager.getInstance(myProject); + return ModuleCompilerUtil.getSortedModuleChunks(myProject, Arrays.asList(moduleManager.getModules())); + } + })); + + final DumbService dumbService = DumbService.getInstance(myProject); + try { + final Set processedModules = new HashSet(); + VirtualFile[] snapshot = null; + final Map, Collection> chunkMap = new HashMap, Collection>(); + int total = 0; + int processed = 0; + for (final Chunk currentChunk : sortedChunks) { + final TranslatorsOutputSink sink = new TranslatorsOutputSink(context, translators); + final Set generatedTypes = new HashSet(); + Collection chunkFiles = chunkMap.get(currentChunk); + final Set filesToRecompile = new HashSet(); + final Set allDependent = new HashSet(); + try { + int round = 0; + boolean compiledSomethingForThisChunk = false; + Collection dependentFiles = Collections.emptyList(); + final Function>, Pair>> dependencyFilter = new DependentClassesCumulativeFilter(); + + do { + for (int currentCompiler = 0, translatorsLength = translators.length; currentCompiler < translatorsLength; currentCompiler++) { + sink.setCurrentCompilerIndex(currentCompiler); + final TranslatingCompiler compiler = translators[currentCompiler]; + if (context.getProgressIndicator().isCanceled()) { + throw new ExitException(ExitStatus.CANCELLED); + } + + dumbService.waitForSmartMode(); + + if (snapshot == null || ContainerUtil.intersects(generatedTypes, compilerManager.getRegisteredInputTypes(compiler))) { + // rescan snapshot if previously generated files may influence the input of this compiler + final Set prevSnapshot = round > 0 && snapshot != null? new HashSet(Arrays.asList(snapshot)) : Collections.emptySet(); + snapshot = ApplicationManager.getApplication().runReadAction(new Computable() { + public VirtualFile[] compute() { + return context.getCompileScope().getFiles(null, true); + } + }); + recalculateChunkToFilesMap(context, sortedChunks, snapshot, chunkMap); + if (round == 0) { + chunkFiles = chunkMap.get(currentChunk); + } + else { + final Set newFiles = new HashSet(chunkMap.get(currentChunk)); + newFiles.removeAll(prevSnapshot); + newFiles.removeAll(chunkFiles); + if (!newFiles.isEmpty()) { + final ArrayList merged = new ArrayList(chunkFiles.size() + newFiles.size()); + merged.addAll(chunkFiles); + merged.addAll(newFiles); + chunkFiles = merged; + } + } + total = snapshot.length * translatorsLength; + } + + final CompileContextEx _context; + if (compiler instanceof IntermediateOutputCompiler) { + // wrap compile context so that output goes into intermediate directories + final IntermediateOutputCompiler _compiler = (IntermediateOutputCompiler)compiler; + _context = new CompileContextExProxy(context) { + public VirtualFile getModuleOutputDirectory(final Module module) { + return getGenerationOutputDir(_compiler, module, false); + } + + public VirtualFile getModuleOutputDirectoryForTests(final Module module) { + return getGenerationOutputDir(_compiler, module, true); + } + }; + } + else { + _context = context; + } + final boolean compiledSomething = + compileSources(_context, currentChunk, compiler, chunkFiles, round == 0? forceCompile : true, isRebuild, onlyCheckStatus, sink); + + processed += chunkFiles.size(); + _context.getProgressIndicator().setFraction(((double)processed) / total); + + if (compiledSomething) { + generatedTypes.addAll(compilerManager.getRegisteredOutputTypes(compiler)); + } + + didSomething |= compiledSomething; + compiledSomethingForThisChunk |= didSomething; + + if (_context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { + break; // break the loop over compilers + } + } + + final boolean hasUnprocessedTraverseRoots = context.getDependencyCache().hasUnprocessedTraverseRoots(); + if (!isRebuild && (compiledSomethingForThisChunk || hasUnprocessedTraverseRoots)) { + final Set compiledWithErrors = CacheUtils.getFilesCompiledWithErrors(context); + filesToRecompile.removeAll(sink.getCompiledSources()); + filesToRecompile.addAll(compiledWithErrors); + + dependentFiles = CacheUtils.findDependentFiles(context, compiledWithErrors, dependencyFilter); + if (!processedModules.isEmpty()) { + for (Iterator it = dependentFiles.iterator(); it.hasNext();) { + final VirtualFile next = it.next(); + final Module module = context.getModuleByFile(next); + if (module != null && processedModules.contains(module)) { + it.remove(); + } + } + } + + if (ourDebugMode) { + if (!dependentFiles.isEmpty()) { + for (VirtualFile dependentFile : dependentFiles) { + System.out.println("FOUND TO RECOMPILE: " + dependentFile.getPresentableUrl()); + } + } + else { + System.out.println("NO FILES TO RECOMPILE"); + } + } + + if (!dependentFiles.isEmpty()) { + filesToRecompile.addAll(dependentFiles); + allDependent.addAll(dependentFiles); + if (context.getProgressIndicator().isCanceled() || context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { + break; + } + final List filesInScope = getFilesInScope(context, currentChunk, dependentFiles); + if (filesInScope.isEmpty()) { + break; + } + context.getDependencyCache().clearTraverseRoots(); + chunkFiles = filesInScope; + total += chunkFiles.size() * translators.length; + } + + didSomething |= (hasUnprocessedTraverseRoots != context.getDependencyCache().hasUnprocessedTraverseRoots()); + } + + round++; + } + while (!dependentFiles.isEmpty() && context.getMessageCount(CompilerMessageCategory.ERROR) == 0); + + if (CompilerConfiguration.MAKE_ENABLED) { + if (!context.getProgressIndicator().isCanceled()) { + // when cancelled pretend nothing was compiled and next compile will compile everything from the scratch + final ProgressIndicator indicator = context.getProgressIndicator(); + final DependencyCache cache = context.getDependencyCache(); + + indicator.pushState(); + indicator.setText(CompilerBundle.message("progress.updating.caches")); + indicator.setText2(""); + + cache.update(); + + indicator.setText(CompilerBundle.message("progress.saving.caches")); + cache.resetState(); + processedModules.addAll(currentChunk.getNodes()); + indicator.popState(); + } + } + + if (context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { + throw new ExitException(ExitStatus.ERRORS); + } + + } + catch (CacheCorruptedException e) { + LOG.info(e); + context.requestRebuildNextTime(e.getMessage()); + } + finally { + final int errorCount = context.getMessageCount(CompilerMessageCategory.ERROR); + if (errorCount != 0) { + filesToRecompile.addAll(allDependent); + } + if (filesToRecompile.size() > 0) { + sink.add(null, Collections.emptyList(), VfsUtilCore.toVirtualFileArray(filesToRecompile)); + } + if (errorCount == 0) { + // perform update only if there were no errors, so it is guaranteed that the file was processd by all neccesary compilers + sink.flushPostponedItems(); + } + } + } + } + catch (ProcessCanceledException e) { + ProgressManager.getInstance().executeNonCancelableSection(new Runnable() { + public void run() { + try { + final Collection deps = CacheUtils.findDependentFiles(context, Collections.emptySet(), null); + if (deps.size() > 0) { + TranslatingCompilerFilesMonitor.getInstance().update(context, null, Collections.emptyList(), + VfsUtilCore.toVirtualFileArray(deps)); + } + } + catch (IOException ignored) { + LOG.info(ignored); + } + catch (CacheCorruptedException ignored) { + LOG.info(ignored); + } + catch (ExitException e1) { + LOG.info(e1); + } + } + }); + throw e; + } + finally { + dropDependencyCache(context); + if (didSomething) { + TranslatingCompilerFilesMonitor.getInstance().updateOutputRootsLayout(myProject); + } + } + return didSomething; + } + + private static List getFilesInScope(final CompileContextEx context, final Chunk chunk, final Collection files) { + final List filesInScope = new ArrayList(files.size()); + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + for (VirtualFile file : files) { + if (context.getCompileScope().belongs(file.getUrl())) { + final Module module = context.getModuleByFile(file); + if (chunk.getNodes().contains(module)) { + filesInScope.add(file); + } + } + } + } + }); + return filesInScope; + } + + private static void recalculateChunkToFilesMap(CompileContextEx context, List> allChunks, VirtualFile[] snapshot, Map, Collection> chunkMap) { + final Map> moduleToFilesMap = CompilerUtil.buildModuleToFilesMap(context, snapshot); + for (Chunk moduleChunk : allChunks) { + List files = Collections.emptyList(); + for (Module module : moduleChunk.getNodes()) { + final List moduleFiles = moduleToFilesMap.get(module); + if (moduleFiles != null) { + files = ContainerUtil.concat(files, moduleFiles); + } + } + chunkMap.put(moduleChunk, files); + } + } + + private interface FileProcessingCompilerAdapterFactory { + FileProcessingCompilerAdapter create(CompileContext context, FileProcessingCompiler compiler); + } + + private boolean invokeFileProcessingCompilers(final CompilerManager compilerManager, + CompileContextEx context, + Class fileProcessingCompilerClass, + FileProcessingCompilerAdapterFactory factory, + boolean forceCompile, + final boolean checkScope, + final boolean onlyCheckStatus) throws ExitException { + boolean didSomething = false; + final FileProcessingCompiler[] compilers = compilerManager.getCompilers(fileProcessingCompilerClass, myCompilerFilter); + if (compilers.length > 0) { + try { + CacheDeferredUpdater cacheUpdater = new CacheDeferredUpdater(); + try { + for (final FileProcessingCompiler compiler : compilers) { + if (context.getProgressIndicator().isCanceled()) { + throw new ExitException(ExitStatus.CANCELLED); + } + + CompileContextEx _context = context; + if (compiler instanceof IntermediateOutputCompiler) { + final IntermediateOutputCompiler _compiler = (IntermediateOutputCompiler)compiler; + _context = new CompileContextExProxy(context) { + public VirtualFile getModuleOutputDirectory(final Module module) { + return getGenerationOutputDir(_compiler, module, false); + } + + public VirtualFile getModuleOutputDirectoryForTests(final Module module) { + return getGenerationOutputDir(_compiler, module, true); + } + }; + } + + final boolean processedSomething = processFiles(factory.create(_context, compiler), forceCompile, checkScope, onlyCheckStatus, cacheUpdater); + + if (context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { + throw new ExitException(ExitStatus.ERRORS); + } + + didSomething |= processedSomething; + } + } + finally { + cacheUpdater.doUpdate(); + } + } + catch (IOException e) { + LOG.info(e); + context.requestRebuildNextTime(e.getMessage()); + throw new ExitException(ExitStatus.ERRORS); + } + catch (ProcessCanceledException e) { + throw e; + } + catch (ExitException e) { + throw e; + } + catch (Exception e) { + context.addMessage(CompilerMessageCategory.ERROR, CompilerBundle.message("compiler.error.exception", e.getMessage()), null, -1, -1); + LOG.error(e); + } + } + + return didSomething; + } + + private static Map> buildModuleToGenerationItemMap(GeneratingCompiler.GenerationItem[] items) { + final Map> map = new HashMap>(); + for (GeneratingCompiler.GenerationItem item : items) { + Module module = item.getModule(); + LOG.assertTrue(module != null); + Set itemSet = map.get(module); + if (itemSet == null) { + itemSet = new HashSet(); + map.put(module, itemSet); + } + itemSet.add(item); + } + return map; + } + + private void deleteAll(final CompileContextEx context) { + CompilerUtil.runInContext(context, CompilerBundle.message("progress.clearing.output"), new ThrowableRunnable() { + public void run() { + final boolean isTestMode = ApplicationManager.getApplication().isUnitTestMode(); + final VirtualFile[] allSources = context.getProjectCompileScope().getFiles(null, true); + if (myShouldClearOutputDirectory) { + CompilerUtil.clearOutputDirectories(myAllOutputDirectories); + } + else { // refresh is still required + try { + for (final Compiler compiler : CompilerManager.getInstance(myProject).getCompilers(Compiler.class)) { + try { + if (compiler instanceof GeneratingCompiler) { + final StateCache cache = getGeneratingCompilerCache((GeneratingCompiler)compiler); + final Iterator urlIterator = cache.getUrlsIterator(); + while (urlIterator.hasNext()) { + context.getProgressIndicator().checkCanceled(); + deleteFile(new File(VirtualFileManager.extractPath(urlIterator.next()))); + } + } + else if (compiler instanceof TranslatingCompiler) { + final ArrayList> toDelete = new ArrayList>(); + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + TranslatingCompilerFilesMonitor.getInstance().collectFiles( + context, + (TranslatingCompiler)compiler, Arrays.asList(allSources).iterator(), + true /*pass true to make sure that every source in scope file is processed*/, + false /*important! should pass false to enable collection of files to delete*/, + new ArrayList(), + toDelete + ); + } + }); + for (Trinity trinity : toDelete) { + context.getProgressIndicator().checkCanceled(); + final File file = trinity.getFirst(); + deleteFile(file); + if (isTestMode) { + CompilerManagerImpl.addDeletedPath(file.getPath()); + } + } + } + } + catch (IOException e) { + LOG.info(e); + } + } + pruneEmptyDirectories(context.getProgressIndicator(), myAllOutputDirectories); // to avoid too much files deleted events + } + finally { + CompilerUtil.refreshIODirectories(myAllOutputDirectories); + } + } + dropScopesCaches(); + + clearCompilerSystemDirectory(context); + } + }); + } + + private void dropScopesCaches() { + // hack to be sure the classpath will include the output directories + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + ((ProjectRootManagerEx)ProjectRootManager.getInstance(myProject)).clearScopesCachesForModules(); + } + }); + } + + private static void pruneEmptyDirectories(ProgressIndicator progress, final Set directories) { + for (File directory : directories) { + doPrune(progress, directory, directories); + } + } + + private static boolean doPrune(ProgressIndicator progress, final File directory, final Set outPutDirectories) { + progress.checkCanceled(); + final File[] files = directory.listFiles(); + boolean isEmpty = true; + if (files != null) { + for (File file : files) { + if (!outPutDirectories.contains(file)) { + if (doPrune(progress, file, outPutDirectories)) { + deleteFile(file); + } + else { + isEmpty = false; + } + } + else { + isEmpty = false; + } + } + } + else { + isEmpty = false; + } + + return isEmpty; + } + + private Set getAllOutputDirectories(CompileContext context) { + final Set outputDirs = new OrderedSet(); + final Module[] modules = ModuleManager.getInstance(myProject).getModules(); + for (final String path : CompilerPathsEx.getOutputPaths(modules)) { + outputDirs.add(new File(path)); + } + for (Pair pair : myGenerationCompilerModuleToOutputDirMap.keySet()) { + outputDirs.add(new File(CompilerPaths.getGenerationOutputPath(pair.getFirst(), pair.getSecond(), false))); + outputDirs.add(new File(CompilerPaths.getGenerationOutputPath(pair.getFirst(), pair.getSecond(), true))); + } + final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject); + if (context.isAnnotationProcessorsEnabled()) { + for (Module module : modules) { + if (config.getAnnotationProcessingConfiguration(module).isEnabled()) { + final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module); + if (path != null) { + outputDirs.add(new File(path)); + } + } + } + } + for (Artifact artifact : ArtifactManager.getInstance(myProject).getArtifacts()) { + final String path = ((ArtifactImpl)artifact).getOutputDirectoryPathToCleanOnRebuild(); + if (path != null) { + outputDirs.add(new File(FileUtil.toSystemDependentName(path))); + } + } + return outputDirs; + } + + private void clearCompilerSystemDirectory(final CompileContextEx context) { + CompilerCacheManager.getInstance(myProject).clearCaches(context); + FileUtil.delete(CompilerPathsEx.getZipStoreDirectory(myProject)); + dropDependencyCache(context); + + for (Pair pair : myGenerationCompilerModuleToOutputDirMap.keySet()) { + final File[] outputs = { + new File(CompilerPaths.getGenerationOutputPath(pair.getFirst(), pair.getSecond(), false)), + new File(CompilerPaths.getGenerationOutputPath(pair.getFirst(), pair.getSecond(), true)) + }; + for (File output : outputs) { + final File[] files = output.listFiles(); + if (files != null) { + for (final File file : files) { + final boolean deleteOk = deleteFile(file); + if (!deleteOk) { + context.addMessage(CompilerMessageCategory.ERROR, CompilerBundle.message("compiler.error.failed.to.delete", file.getPath()), + null, -1, -1); + } + } + } + } + } + } + + /** + * @param file a file to delete + * @return true if and only if the file existed and was successfully deleted + * Note: the behaviour is different from FileUtil.delete() which returns true if the file absent on the disk + */ + private static boolean deleteFile(final File file) { + File[] files = file.listFiles(); + if (files != null) { + for (File file1 : files) { + deleteFile(file1); + } + } + + for (int i = 0; i < 10; i++){ + if (file.delete()) { + return true; + } + if (!file.exists()) { + return false; + } + try { + Thread.sleep(50); + } + catch (InterruptedException ignored) { + } + } + return false; + } + + private VirtualFile getGenerationOutputDir(final IntermediateOutputCompiler compiler, final Module module, final boolean forTestSources) { + final Pair outputs = + myGenerationCompilerModuleToOutputDirMap.get(new Pair(compiler, module)); + return forTestSources? outputs.getSecond() : outputs.getFirst(); + } + + private boolean generateOutput(final CompileContextEx context, + final GeneratingCompiler compiler, + final boolean forceGenerate, + final boolean onlyCheckStatus) throws ExitException { + final GeneratingCompiler.GenerationItem[] allItems = compiler.getGenerationItems(context); + final List toGenerate = new ArrayList(); + final List filesToRefresh = new ArrayList(); + final List generatedFiles = new ArrayList(); + final List affectedModules = new ArrayList(); + try { + final StateCache cache = getGeneratingCompilerCache(compiler); + final Set pathsToRemove = new HashSet(cache.getUrls()); + + final Map itemToOutputPathMap = new HashMap(); + final IOException[] ex = {null}; + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + for (final GeneratingCompiler.GenerationItem item : allItems) { + final Module itemModule = item.getModule(); + final String outputDirPath = CompilerPaths.getGenerationOutputPath(compiler, itemModule, item.isTestSource()); + final String outputPath = outputDirPath + "/" + item.getPath(); + itemToOutputPathMap.put(item, outputPath); + + try { + final ValidityState savedState = cache.getState(outputPath); + + if (forceGenerate || savedState == null || !savedState.equalsTo(item.getValidityState())) { + final String outputPathUrl = VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, outputPath); + if (context.getCompileScope().belongs(outputPathUrl)) { + toGenerate.add(item); + } + else { + pathsToRemove.remove(outputPath); + } + } + else { + pathsToRemove.remove(outputPath); + } + } + catch (IOException e) { + ex[0] = e; + } + } + } + }); + if (ex[0] != null) { + throw ex[0]; + } + + if (onlyCheckStatus) { + if (toGenerate.isEmpty() && pathsToRemove.isEmpty()) { + return false; + } + if (LOG.isDebugEnabled()) { + if (!toGenerate.isEmpty()) { + LOG.debug("Found items to generate, compiler " + compiler.getDescription()); + } + if (!pathsToRemove.isEmpty()) { + LOG.debug("Found paths to remove, compiler " + compiler.getDescription()); + } + } + throw new ExitException(ExitStatus.CANCELLED); + } + + if (!pathsToRemove.isEmpty()) { + CompilerUtil.runInContext(context, CompilerBundle.message("progress.synchronizing.output.directory"), new ThrowableRunnable(){ + public void run() throws IOException { + for (final String path : pathsToRemove) { + final File file = new File(path); + final boolean deleted = deleteFile(file); + if (deleted) { + cache.remove(path); + filesToRefresh.add(file); + } + } + } + }); + } + + final Map> moduleToItemMap = + buildModuleToGenerationItemMap(toGenerate.toArray(new GeneratingCompiler.GenerationItem[toGenerate.size()])); + List modules = new ArrayList(moduleToItemMap.size()); + for (final Module module : moduleToItemMap.keySet()) { + modules.add(module); + } + ModuleCompilerUtil.sortModules(myProject, modules); + + for (final Module module : modules) { + CompilerUtil.runInContext(context, "Generating output from "+compiler.getDescription(),new ThrowableRunnable(){ + public void run() throws IOException { + final Set items = moduleToItemMap.get(module); + if (items != null && !items.isEmpty()) { + final GeneratingCompiler.GenerationItem[][] productionAndTestItems = splitGenerationItems(items); + for (GeneratingCompiler.GenerationItem[] _items : productionAndTestItems) { + if (_items.length == 0) continue; + final VirtualFile outputDir = getGenerationOutputDir(compiler, module, _items[0].isTestSource()); + final GeneratingCompiler.GenerationItem[] successfullyGenerated = compiler.generate(context, _items, outputDir); + + CompilerUtil.runInContext(context, CompilerBundle.message("progress.updating.caches"), new ThrowableRunnable() { + public void run() throws IOException { + if (successfullyGenerated.length > 0) { + affectedModules.add(module); + } + for (final GeneratingCompiler.GenerationItem item : successfullyGenerated) { + final String fullOutputPath = itemToOutputPathMap.get(item); + cache.update(fullOutputPath, item.getValidityState()); + final File file = new File(fullOutputPath); + filesToRefresh.add(file); + generatedFiles.add(file); + context.getProgressIndicator().setText2(file.getPath()); + } + } + }); + } + } + } + }); + } + } + catch (IOException e) { + LOG.info(e); + context.requestRebuildNextTime(e.getMessage()); + throw new ExitException(ExitStatus.ERRORS); + } + finally { + CompilerUtil.refreshIOFiles(filesToRefresh); + if (!generatedFiles.isEmpty()) { + DumbService.getInstance(myProject).waitForSmartMode(); + List vFiles = ApplicationManager.getApplication().runReadAction(new Computable>() { + public List compute() { + final ArrayList vFiles = new ArrayList(generatedFiles.size()); + for (File generatedFile : generatedFiles) { + final VirtualFile vFile = LocalFileSystem.getInstance().findFileByIoFile(generatedFile); + if (vFile != null) { + vFiles.add(vFile); + } + } + return vFiles; + } + }); + if (forceGenerate) { + context.addScope(new FileSetCompileScope(vFiles, affectedModules.toArray(new Module[affectedModules.size()]))); + } + context.markGenerated(vFiles); + } + } + return !toGenerate.isEmpty() || !filesToRefresh.isEmpty(); + } + + private static GeneratingCompiler.GenerationItem[][] splitGenerationItems(final Set items) { + final List production = new ArrayList(); + final List tests = new ArrayList(); + for (GeneratingCompiler.GenerationItem item : items) { + if (item.isTestSource()) { + tests.add(item); + } + else { + production.add(item); + } + } + return new GeneratingCompiler.GenerationItem[][]{ + production.toArray(new GeneratingCompiler.GenerationItem[production.size()]), + tests.toArray(new GeneratingCompiler.GenerationItem[tests.size()]) + }; + } + + private boolean compileSources(final CompileContextEx context, + final Chunk moduleChunk, + final TranslatingCompiler compiler, + final Collection srcSnapshot, + final boolean forceCompile, + final boolean isRebuild, + final boolean onlyCheckStatus, + TranslatingCompiler.OutputSink sink) throws ExitException { + + final Set toCompile = new HashSet(); + final List> toDelete = new ArrayList>(); + context.getProgressIndicator().pushState(); + + final boolean[] wereFilesDeleted = {false}; + try { + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + TranslatingCompilerFilesMonitor.getInstance().collectFiles( + context, compiler, srcSnapshot.iterator(), forceCompile, isRebuild, toCompile, toDelete + ); + } + }); + + if (onlyCheckStatus) { + if (toDelete.isEmpty() && toCompile.isEmpty()) { + return false; + } + if (LOG.isDebugEnabled() || ourDebugMode) { + if (!toDelete.isEmpty()) { + final StringBuilder message = new StringBuilder(); + message.append("Found items to delete, compiler ").append(compiler.getDescription()); + for (Trinity trinity : toDelete) { + message.append("\n").append(trinity.getFirst()); + } + LOG.debug(message.toString()); + if (ourDebugMode) { + System.out.println(message); + } + } + if (!toCompile.isEmpty()) { + final String message = "Found items to compile, compiler " + compiler.getDescription(); + LOG.debug(message); + if (ourDebugMode) { + System.out.println(message); + } + } + } + throw new ExitException(ExitStatus.CANCELLED); + } + + if (!toDelete.isEmpty()) { + try { + wereFilesDeleted[0] = syncOutputDir(context, toDelete); + } + catch (CacheCorruptedException e) { + LOG.info(e); + context.requestRebuildNextTime(e.getMessage()); + } + } + + if ((wereFilesDeleted[0] || !toCompile.isEmpty()) && context.getMessageCount(CompilerMessageCategory.ERROR) == 0) { + compiler.compile(context, moduleChunk, VfsUtilCore.toVirtualFileArray(toCompile), sink); + } + } + finally { + context.getProgressIndicator().popState(); + } + return !toCompile.isEmpty() || wereFilesDeleted[0]; + } + + private static boolean syncOutputDir(final CompileContextEx context, final Collection> toDelete) throws CacheCorruptedException { + final DependencyCache dependencyCache = context.getDependencyCache(); + final boolean isTestMode = ApplicationManager.getApplication().isUnitTestMode(); + + final List filesToRefresh = new ArrayList(); + final boolean[] wereFilesDeleted = {false}; + CompilerUtil.runInContext(context, CompilerBundle.message("progress.synchronizing.output.directory"), new ThrowableRunnable(){ + public void run() throws CacheCorruptedException { + final long start = System.currentTimeMillis(); + try { + for (final Trinity trinity : toDelete) { + final File outputPath = trinity.getFirst(); + context.getProgressIndicator().checkCanceled(); + context.getProgressIndicator().setText2(outputPath.getPath()); + filesToRefresh.add(outputPath); + if (isTestMode) { + LOG.assertTrue(outputPath.exists()); + } + if (!deleteFile(outputPath)) { + if (isTestMode) { + if (outputPath.exists()) { + LOG.error("Was not able to delete output file: " + outputPath.getPath()); + } + else { + CompilerManagerImpl.addDeletedPath(outputPath.getPath()); + } + } + continue; + } + wereFilesDeleted[0] = true; + + // update zip here + //final String outputDir = myOutputFinder.lookupOutputPath(outputPath); + //if (outputDir != null) { + // try { + // context.updateZippedOuput(outputDir, FileUtil.toSystemIndependentName(outputPath.getPath()).substring(outputDir.length() + 1)); + // } + // catch (IOException e) { + // LOG.info(e); + // } + //} + + final String className = trinity.getSecond(); + if (className != null) { + final int id = dependencyCache.getSymbolTable().getId(className); + dependencyCache.addTraverseRoot(id); + final boolean sourcePresent = trinity.getThird().booleanValue(); + if (!sourcePresent) { + dependencyCache.markSourceRemoved(id); + } + } + if (isTestMode) { + CompilerManagerImpl.addDeletedPath(outputPath.getPath()); + } + } + } + finally { + CompilerUtil.logDuration("Sync output directory", System.currentTimeMillis() - start); + CompilerUtil.refreshIOFiles(filesToRefresh); + } + } + }); + return wereFilesDeleted[0]; + } + + // [mike] performance optimization - this method is accessed > 15,000 times in Aurora + private String getModuleOutputPath(final Module module, boolean inTestSourceContent) { + final Map map = inTestSourceContent ? myModuleTestOutputPaths : myModuleOutputPaths; + String path = map.get(module); + if (path == null) { + path = CompilerPaths.getModuleOutputPath(module, inTestSourceContent); + map.put(module, path); + } + + return path; + } + + private boolean processFiles(final FileProcessingCompilerAdapter adapter, + final boolean forceCompile, + final boolean checkScope, + final boolean onlyCheckStatus, final CacheDeferredUpdater cacheUpdater) throws ExitException, IOException { + final CompileContextEx context = (CompileContextEx)adapter.getCompileContext(); + final FileProcessingCompilerStateCache cache = getFileProcessingCompilerCache(adapter.getCompiler()); + final FileProcessingCompiler.ProcessingItem[] items = adapter.getProcessingItems(); + if (context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { + return false; + } + if (LOG.isDebugEnabled() && items.length > 0) { + LOG.debug("Start processing files by " + adapter.getCompiler().getDescription()); + } + final CompileScope scope = context.getCompileScope(); + final List toProcess = new ArrayList(); + final Set allUrls = new HashSet(); + final IOException[] ex = {null}; + DumbService.getInstance(myProject).waitForSmartMode(); + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + try { + for (FileProcessingCompiler.ProcessingItem item : items) { + final VirtualFile file = item.getFile(); + final String url = file.getUrl(); + allUrls.add(url); + if (!forceCompile && cache.getTimestamp(url) == file.getTimeStamp()) { + final ValidityState state = cache.getExtState(url); + final ValidityState itemState = item.getValidityState(); + if (state != null ? state.equalsTo(itemState) : itemState == null) { + continue; + } + } + if (LOG.isDebugEnabled()) { + LOG.debug("Adding item to process: " + url + "; saved ts= " + cache.getTimestamp(url) + "; VFS ts=" + file.getTimeStamp()); + } + toProcess.add(item); + } + } + catch (IOException e) { + ex[0] = e; + } + } + }); + + if (ex[0] != null) { + throw ex[0]; + } + + final Collection urls = cache.getUrls(); + final List urlsToRemove = new ArrayList(); + if (!urls.isEmpty()) { + CompilerUtil.runInContext(context, CompilerBundle.message("progress.processing.outdated.files"), new ThrowableRunnable(){ + public void run() throws IOException { + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + for (final String url : urls) { + if (!allUrls.contains(url)) { + if (!checkScope || scope.belongs(url)) { + urlsToRemove.add(url); + } + } + } + } + }); + if (!onlyCheckStatus && !urlsToRemove.isEmpty()) { + for (final String url : urlsToRemove) { + adapter.processOutdatedItem(context, url, cache.getExtState(url)); + cache.remove(url); + } + } + } + }); + } + + if (onlyCheckStatus) { + if (urlsToRemove.isEmpty() && toProcess.isEmpty()) { + return false; + } + if (LOG.isDebugEnabled()) { + if (!urlsToRemove.isEmpty()) { + LOG.debug("Found urls to remove, compiler " + adapter.getCompiler().getDescription()); + for (String url : urlsToRemove) { + LOG.debug("\t" + url); + } + } + if (!toProcess.isEmpty()) { + LOG.debug("Found items to compile, compiler " + adapter.getCompiler().getDescription()); + for (FileProcessingCompiler.ProcessingItem item : toProcess) { + LOG.debug("\t" + item.getFile().getPresentableUrl()); + } + } + } + throw new ExitException(ExitStatus.CANCELLED); + } + + if (toProcess.isEmpty()) { + return false; + } + + final FileProcessingCompiler.ProcessingItem[] processed = + adapter.process(toProcess.toArray(new FileProcessingCompiler.ProcessingItem[toProcess.size()])); + + if (processed.length == 0) { + return true; + } + CompilerUtil.runInContext(context, CompilerBundle.message("progress.updating.caches"), new ThrowableRunnable() { + public void run() { + final List vFiles = new ArrayList(processed.length); + for (FileProcessingCompiler.ProcessingItem aProcessed : processed) { + final VirtualFile file = aProcessed.getFile(); + vFiles.add(file); + if (LOG.isDebugEnabled()) { + LOG.debug("\tFile processed " + file.getPresentableUrl() + "; ts=" + file.getTimeStamp()); + } + + //final String path = file.getPath(); + //final String outputDir = myOutputFinder.lookupOutputPath(path); + //if (outputDir != null) { + // context.updateZippedOuput(outputDir, path.substring(outputDir.length() + 1)); + //} + } + LocalFileSystem.getInstance().refreshFiles(vFiles); + if (LOG.isDebugEnabled()) { + LOG.debug("Files after VFS refresh:"); + for (VirtualFile file : vFiles) { + LOG.debug("\t" + file.getPresentableUrl() + "; ts=" + file.getTimeStamp()); + } + } + for (FileProcessingCompiler.ProcessingItem item : processed) { + cacheUpdater.addFileForUpdate(item, cache); + } + } + }); + return true; + } + + private FileProcessingCompilerStateCache getFileProcessingCompilerCache(FileProcessingCompiler compiler) throws IOException { + return CompilerCacheManager.getInstance(myProject).getFileProcessingCompilerCache(compiler); + } + + private StateCache getGeneratingCompilerCache(final GeneratingCompiler compiler) throws IOException { + return CompilerCacheManager.getInstance(myProject).getGeneratingCompilerCache(compiler); + } + + public void executeCompileTask(final CompileTask task, final CompileScope scope, final String contentName, final Runnable onTaskFinished) { + final CompilerTask progressManagerTask = + new CompilerTask(myProject, contentName, false, false); + final CompileContextImpl compileContext = new CompileContextImpl(myProject, progressManagerTask, scope, null, false, false); + + FileDocumentManager.getInstance().saveAllDocuments(); + + progressManagerTask.start(new Runnable() { + public void run() { + try { + task.execute(compileContext); + } + catch (ProcessCanceledException ex) { + // suppressed + } + finally { + if (onTaskFinished != null) { + onTaskFinished.run(); + } + } + } + }, null); + } + + private boolean executeCompileTasks(final CompileContext context, final boolean beforeTasks) { + final CompilerManager manager = CompilerManager.getInstance(myProject); + final ProgressIndicator progressIndicator = context.getProgressIndicator(); + progressIndicator.pushState(); + try { + CompileTask[] tasks = beforeTasks ? manager.getBeforeTasks() : manager.getAfterTasks(); + if (tasks.length > 0) { + progressIndicator.setText(beforeTasks + ? CompilerBundle.message("progress.executing.precompile.tasks") + : CompilerBundle.message("progress.executing.postcompile.tasks")); + for (CompileTask task : tasks) { + if (!task.execute(context)) { + return false; + } + } + } + } + finally { + progressIndicator.popState(); + WindowManager.getInstance().getStatusBar(myProject).setInfo(""); + if (progressIndicator instanceof CompilerTask) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + ((CompilerTask)progressIndicator).showCompilerContent(); + } + }); + } + } + return true; + } + + private boolean validateCompilerConfiguration(final CompileScope scope, boolean checkOutputAndSourceIntersection) { + try { + final Module[] scopeModules = scope.getAffectedModules()/*ModuleManager.getInstance(myProject).getModules()*/; + final List modulesWithoutOutputPathSpecified = new ArrayList(); + boolean isProjectCompilePathSpecified = true; + final List modulesWithoutJdkAssigned = new ArrayList(); + final Set nonExistingOutputPaths = new HashSet(); + final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject); + final CompilerManager compilerManager = CompilerManager.getInstance(myProject); + for (final Module module : scopeModules) { + if (!compilerManager.isValidationEnabled(module)) { + continue; + } + final boolean hasSources = hasSources(module, false); + final boolean hasTestSources = hasSources(module, true); + if (!hasSources && !hasTestSources) { + // If module contains no sources, shouldn't have to select JDK or output directory (SCR #19333) + // todo still there may be problems with this approach if some generated files are attributed by this module + continue; + } + final Sdk jdk = ModuleRootManager.getInstance(module).getSdk(); + if (jdk == null) { + modulesWithoutJdkAssigned.add(module.getName()); + } + final String outputPath = getModuleOutputPath(module, false); + final String testsOutputPath = getModuleOutputPath(module, true); + if (outputPath == null && testsOutputPath == null) { + modulesWithoutOutputPathSpecified.add(module.getName()); + } + else { + if (outputPath != null) { + final File file = new File(outputPath.replace('/', File.separatorChar)); + if (!file.exists()) { + nonExistingOutputPaths.add(file); + } + } + else { + if (hasSources) { + modulesWithoutOutputPathSpecified.add(module.getName()); + } + } + if (testsOutputPath != null) { + final File f = new File(testsOutputPath.replace('/', File.separatorChar)); + if (!f.exists()) { + nonExistingOutputPaths.add(f); + } + } + else { + if (hasTestSources) { + modulesWithoutOutputPathSpecified.add(module.getName()); + } + } + if (!useOutOfProcessBuild()) { + if (config.getAnnotationProcessingConfiguration(module).isEnabled()) { + final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module); + if (path == null) { + final CompilerProjectExtension extension = CompilerProjectExtension.getInstance(module.getProject()); + if (extension == null || extension.getCompilerOutputUrl() == null) { + isProjectCompilePathSpecified = false; + } + else { + modulesWithoutOutputPathSpecified.add(module.getName()); + } + } + else { + final File file = new File(path); + if (!file.exists()) { + nonExistingOutputPaths.add(file); + } + } + } + } + } + } + if (!modulesWithoutJdkAssigned.isEmpty()) { + showNotSpecifiedError("error.jdk.not.specified", modulesWithoutJdkAssigned, ProjectBundle.message("modules.classpath.title")); + return false; + } + + if (!isProjectCompilePathSpecified) { + final String message = CompilerBundle.message("error.project.output.not.specified"); + if (ApplicationManager.getApplication().isUnitTestMode()) { + LOG.error(message); + } + + Messages.showMessageDialog(myProject, message, CommonBundle.getErrorTitle(), Messages.getErrorIcon()); + ProjectSettingsService.getInstance(myProject).openProjectSettings(); + return false; + } + + if (!modulesWithoutOutputPathSpecified.isEmpty()) { + showNotSpecifiedError("error.output.not.specified", modulesWithoutOutputPathSpecified, CommonContentEntriesEditor.NAME); + return false; + } + + if (!nonExistingOutputPaths.isEmpty()) { + for (File file : nonExistingOutputPaths) { + final boolean succeeded = file.mkdirs(); + if (!succeeded) { + if (file.exists()) { + // for overlapping paths, this one might have been created as an intermediate path on a previous iteration + continue; + } + Messages.showMessageDialog(myProject, CompilerBundle.message("error.failed.to.create.directory", file.getPath()), + CommonBundle.getErrorTitle(), Messages.getErrorIcon()); + return false; + } + } + final Boolean refreshSuccess = + new WriteAction() { + @Override + protected void run(Result result) throws Throwable { + LocalFileSystem.getInstance().refreshIoFiles(nonExistingOutputPaths); + Boolean res = Boolean.TRUE; + for (File file : nonExistingOutputPaths) { + if (LocalFileSystem.getInstance().findFileByIoFile(file) == null) { + res = Boolean.FALSE; + break; + } + } + result.setResult(res); + } + }.execute().getResultObject(); + + if (!refreshSuccess.booleanValue()) { + return false; + } + dropScopesCaches(); + } + + if (checkOutputAndSourceIntersection && myShouldClearOutputDirectory) { + if (!validateOutputAndSourcePathsIntersection()) { + return false; + } + // myShouldClearOutputDirectory may change in validateOutputAndSourcePathsIntersection() + CompilerPathsEx.CLEAR_ALL_OUTPUTS_KEY.set(scope, myShouldClearOutputDirectory); + } + else { + CompilerPathsEx.CLEAR_ALL_OUTPUTS_KEY.set(scope, false); + } + final List> chunks = ModuleCompilerUtil.getSortedModuleChunks(myProject, Arrays.asList(scopeModules)); + for (final Chunk chunk : chunks) { + final Set chunkModules = chunk.getNodes(); + if (chunkModules.size() <= 1) { + continue; // no need to check one-module chunks + } + for (Module chunkModule : chunkModules) { + if (config.getAnnotationProcessingConfiguration(chunkModule).isEnabled()) { + showCyclesNotSupportedForAnnotationProcessors(chunkModules.toArray(new Module[chunkModules.size()])); + return false; + } + } + Sdk jdk = null; + LanguageLevel languageLevel = null; + for (final Module module : chunkModules) { + final Sdk moduleJdk = ModuleRootManager.getInstance(module).getSdk(); + if (jdk == null) { + jdk = moduleJdk; + } + else { + if (!jdk.equals(moduleJdk)) { + showCyclicModulesHaveDifferentJdksError(chunkModules.toArray(new Module[chunkModules.size()])); + return false; + } + } + + LanguageLevel moduleLanguageLevel = LanguageLevelUtil.getEffectiveLanguageLevel(module); + if (languageLevel == null) { + languageLevel = moduleLanguageLevel; + } + else { + if (!languageLevel.equals(moduleLanguageLevel)) { + showCyclicModulesHaveDifferentLanguageLevel(chunkModules.toArray(new Module[chunkModules.size()])); + return false; + } + } + } + } + if (!useOutOfProcessBuild()) { + final Compiler[] allCompilers = compilerManager.getCompilers(Compiler.class); + for (Compiler compiler : allCompilers) { + if (!compiler.validateConfiguration(scope)) { + return false; + } + } + } + return true; + } + catch (Throwable e) { + LOG.info(e); + return false; + } + } + + private boolean useOutOfProcessBuild() { + return CompilerWorkspaceConfiguration.getInstance(myProject).useOutOfProcessBuild(); + } + + private void showCyclicModulesHaveDifferentLanguageLevel(Module[] modulesInChunk) { + LOG.assertTrue(modulesInChunk.length > 0); + String moduleNameToSelect = modulesInChunk[0].getName(); + final String moduleNames = getModulesString(modulesInChunk); + Messages.showMessageDialog(myProject, CompilerBundle.message("error.chunk.modules.must.have.same.language.level", moduleNames), + CommonBundle.getErrorTitle(), Messages.getErrorIcon()); + showConfigurationDialog(moduleNameToSelect, null); + } + + private void showCyclicModulesHaveDifferentJdksError(Module[] modulesInChunk) { + LOG.assertTrue(modulesInChunk.length > 0); + String moduleNameToSelect = modulesInChunk[0].getName(); + final String moduleNames = getModulesString(modulesInChunk); + Messages.showMessageDialog(myProject, CompilerBundle.message("error.chunk.modules.must.have.same.jdk", moduleNames), + CommonBundle.getErrorTitle(), Messages.getErrorIcon()); + showConfigurationDialog(moduleNameToSelect, null); + } + + private void showCyclesNotSupportedForAnnotationProcessors(Module[] modulesInChunk) { + LOG.assertTrue(modulesInChunk.length > 0); + String moduleNameToSelect = modulesInChunk[0].getName(); + final String moduleNames = getModulesString(modulesInChunk); + Messages.showMessageDialog(myProject, CompilerBundle.message("error.annotation.processing.not.supported.for.module.cycles", moduleNames), + CommonBundle.getErrorTitle(), Messages.getErrorIcon()); + showConfigurationDialog(moduleNameToSelect, null); + } + + private static String getModulesString(Module[] modulesInChunk) { + final StringBuilder moduleNames = StringBuilderSpinAllocator.alloc(); + try { + for (Module module : modulesInChunk) { + if (moduleNames.length() > 0) { + moduleNames.append("\n"); + } + moduleNames.append("\"").append(module.getName()).append("\""); + } + return moduleNames.toString(); + } + finally { + StringBuilderSpinAllocator.dispose(moduleNames); + } + } + + private static boolean hasSources(Module module, boolean checkTestSources) { + final ContentEntry[] contentEntries = ModuleRootManager.getInstance(module).getContentEntries(); + for (final ContentEntry contentEntry : contentEntries) { + final SourceFolder[] sourceFolders = contentEntry.getSourceFolders(); + for (final SourceFolder sourceFolder : sourceFolders) { + if (sourceFolder.getFile() == null) { + continue; // skip invalid source folders + } + if (checkTestSources) { + if (sourceFolder.isTestSource()) { + return true; + } + } + else { + if (!sourceFolder.isTestSource()) { + return true; + } + } + } + } + return false; + } + + private void showNotSpecifiedError(@NonNls final String resourceId, List modules, String editorNameToSelect) { + String nameToSelect = null; + final StringBuilder names = StringBuilderSpinAllocator.alloc(); + final String message; + try { + final int maxModulesToShow = 10; + for (String name : modules.size() > maxModulesToShow ? modules.subList(0, maxModulesToShow) : modules) { + if (nameToSelect == null) { + nameToSelect = name; + } + if (names.length() > 0) { + names.append(",\n"); + } + names.append("\""); + names.append(name); + names.append("\""); + } + if (modules.size() > maxModulesToShow) { + names.append(",\n..."); + } + message = CompilerBundle.message(resourceId, modules.size(), names.toString()); + } + finally { + StringBuilderSpinAllocator.dispose(names); + } + + if (ApplicationManager.getApplication().isUnitTestMode()) { + LOG.error(message); + } + + Messages.showMessageDialog(myProject, message, CommonBundle.getErrorTitle(), Messages.getErrorIcon()); + showConfigurationDialog(nameToSelect, editorNameToSelect); + } + + private boolean validateOutputAndSourcePathsIntersection() { + final Module[] allModules = ModuleManager.getInstance(myProject).getModules(); + List allOutputs = new ArrayList(); + ContainerUtil.addAll(allOutputs, CompilerPathsEx.getOutputDirectories(allModules)); + for (Artifact artifact : ArtifactManager.getInstance(myProject).getArtifacts()) { + ContainerUtil.addIfNotNull(artifact.getOutputFile(), allOutputs); + } + final Set affectedOutputPaths = new HashSet(); + CompilerUtil.computeIntersectingPaths(myProject, allOutputs, affectedOutputPaths); + affectedOutputPaths.addAll(ArtifactCompilerUtil.getArtifactOutputsContainingSourceFiles(myProject)); + + if (!affectedOutputPaths.isEmpty()) { + if (CompilerUtil.askUserToContinueWithNoClearing(myProject, affectedOutputPaths)) { + myShouldClearOutputDirectory = false; + return true; + } + else { + return false; + } + } + return true; + } + + private void showConfigurationDialog(String moduleNameToSelect, String tabNameToSelect) { + ProjectSettingsService.getInstance(myProject).showModuleConfigurationDialog(moduleNameToSelect, tabNameToSelect); + } + + private static VirtualFile lookupVFile(final LocalFileSystem lfs, final String path) { + final File file = new File(path); + + VirtualFile vFile = lfs.findFileByIoFile(file); + if (vFile != null) { + return vFile; + } + + final boolean justCreated = file.mkdirs(); + vFile = lfs.refreshAndFindFileByIoFile(file); + + if (vFile == null) { + assert false: "Virtual file not found for " + file.getPath() + "; mkdirs() exit code is " + justCreated + "; file exists()? " + file.exists(); + } + + return vFile; + } + + private static class CacheDeferredUpdater { + private final Map>> myData = new java.util.HashMap>>(); + + public void addFileForUpdate(final FileProcessingCompiler.ProcessingItem item, FileProcessingCompilerStateCache cache) { + final VirtualFile file = item.getFile(); + List> list = myData.get(file); + if (list == null) { + list = new ArrayList>(); + myData.put(file, list); + } + list.add(new Pair(cache, item)); + } + + public void doUpdate() throws IOException{ + final IOException[] ex = {null}; + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + try { + for (Map.Entry>> entry : myData.entrySet()) { + for (Pair pair : entry.getValue()) { + final FileProcessingCompiler.ProcessingItem item = pair.getSecond(); + pair.getFirst().update(entry.getKey(), item.getValidityState()); + } + } + } + catch (IOException e) { + ex[0] = e; + } + } + }); + if (ex[0] != null) { + throw ex[0]; + } + } + } + + private static class TranslatorsOutputSink implements TranslatingCompiler.OutputSink { + final Map> myPostponedItems = new HashMap>(); + private final CompileContextEx myContext; + private final TranslatingCompiler[] myCompilers; + private int myCurrentCompilerIdx; + private final Set myCompiledSources = new HashSet(); + //private LinkedBlockingQueue myFutures = new LinkedBlockingQueue(); + + private TranslatorsOutputSink(CompileContextEx context, TranslatingCompiler[] compilers) { + myContext = context; + myCompilers = compilers; + } + + public void setCurrentCompilerIndex(int index) { + myCurrentCompilerIdx = index; + } + + public Set getCompiledSources() { + return Collections.unmodifiableSet(myCompiledSources); + } + + public void add(final String outputRoot, final Collection items, final VirtualFile[] filesToRecompile) { + for (TranslatingCompiler.OutputItem item : items) { + final VirtualFile file = item.getSourceFile(); + if (file != null) { + myCompiledSources.add(file); + } + } + final TranslatingCompiler compiler = myCompilers[myCurrentCompilerIdx]; + if (compiler instanceof IntermediateOutputCompiler) { + final LocalFileSystem lfs = LocalFileSystem.getInstance(); + final List outputs = new ArrayList(); + for (TranslatingCompiler.OutputItem item : items) { + final VirtualFile vFile = lfs.findFileByPath(item.getOutputPath()); + if (vFile != null) { + outputs.add(vFile); + } + } + myContext.markGenerated(outputs); + } + final int nextCompilerIdx = myCurrentCompilerIdx + 1; + try { + if (nextCompilerIdx < myCompilers.length ) { + final Map> updateNow = new java.util.HashMap>(); + // process postponed + for (Map.Entry> entry : myPostponedItems.entrySet()) { + final String outputDir = entry.getKey(); + final Collection postponed = entry.getValue(); + for (Iterator it = postponed.iterator(); it.hasNext();) { + TranslatingCompiler.OutputItem item = it.next(); + boolean shouldPostpone = false; + for (int idx = nextCompilerIdx; idx < myCompilers.length; idx++) { + shouldPostpone = myCompilers[idx].isCompilableFile(item.getSourceFile(), myContext); + if (shouldPostpone) { + break; + } + } + if (!shouldPostpone) { + // the file is not compilable by the rest of compilers, so it is safe to update it now + it.remove(); + addItemToMap(updateNow, outputDir, item); + } + } + } + // process items from current compilation + for (TranslatingCompiler.OutputItem item : items) { + boolean shouldPostpone = false; + for (int idx = nextCompilerIdx; idx < myCompilers.length; idx++) { + shouldPostpone = myCompilers[idx].isCompilableFile(item.getSourceFile(), myContext); + if (shouldPostpone) { + break; + } + } + if (shouldPostpone) { + // the file is compilable by the next compiler in row, update should be postponed + addItemToMap(myPostponedItems, outputRoot, item); + } + else { + addItemToMap(updateNow, outputRoot, item); + } + } + + if (updateNow.size() == 1) { + final Map.Entry> entry = updateNow.entrySet().iterator().next(); + final String outputDir = entry.getKey(); + final Collection itemsToUpdate = entry.getValue(); + TranslatingCompilerFilesMonitor.getInstance().update(myContext, outputDir, itemsToUpdate, filesToRecompile); + } + else { + for (Map.Entry> entry : updateNow.entrySet()) { + final String outputDir = entry.getKey(); + final Collection itemsToUpdate = entry.getValue(); + TranslatingCompilerFilesMonitor.getInstance().update(myContext, outputDir, itemsToUpdate, VirtualFile.EMPTY_ARRAY); + } + if (filesToRecompile.length > 0) { + TranslatingCompilerFilesMonitor.getInstance().update(myContext, null, Collections.emptyList(), filesToRecompile); + } + } + } + else { + TranslatingCompilerFilesMonitor.getInstance().update(myContext, outputRoot, items, filesToRecompile); + } + } + catch (IOException e) { + LOG.info(e); + myContext.requestRebuildNextTime(e.getMessage()); + } + } + + private static void addItemToMap(Map> map, String outputDir, TranslatingCompiler.OutputItem item) { + Collection collection = map.get(outputDir); + if (collection == null) { + collection = new ArrayList(); + map.put(outputDir, collection); + } + collection.add(item); + } + + public void flushPostponedItems() { + final TranslatingCompilerFilesMonitor filesMonitor = TranslatingCompilerFilesMonitor.getInstance(); + try { + for (Map.Entry> entry : myPostponedItems.entrySet()) { + final String outputDir = entry.getKey(); + final Collection items = entry.getValue(); + filesMonitor.update(myContext, outputDir, items, VirtualFile.EMPTY_ARRAY); + } + } + catch (IOException e) { + LOG.info(e); + myContext.requestRebuildNextTime(e.getMessage()); + } + } + } + + private static class DependentClassesCumulativeFilter implements Function>, Pair>> { + + private final TIntHashSet myProcessedNames = new TIntHashSet(); + private final Set myProcessedFiles = new HashSet(); + + public Pair> fun(Pair> deps) { + final TIntHashSet currentDeps = new TIntHashSet(deps.getFirst()); + currentDeps.removeAll(myProcessedNames.toArray()); + myProcessedNames.addAll(deps.getFirst()); + + final Set depFiles = new HashSet(deps.getSecond()); + depFiles.removeAll(myProcessedFiles); + myProcessedFiles.addAll(deps.getSecond()); + return new Pair>(currentDeps.toArray(), depFiles); + } + } +} diff --git a/java/compiler/impl/src/com/intellij/compiler/options/CompilerOptionsPanel.form b/java/compiler/impl/src/com/intellij/compiler/options/CompilerOptionsPanel.form index a236930b8592..86eb2d00103a 100644 --- a/java/compiler/impl/src/com/intellij/compiler/options/CompilerOptionsPanel.form +++ b/java/compiler/impl/src/com/intellij/compiler/options/CompilerOptionsPanel.form @@ -1,153 +1,153 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/java/compiler/impl/src/com/intellij/compiler/options/CompilerUIConfigurable.java b/java/compiler/impl/src/com/intellij/compiler/options/CompilerUIConfigurable.java index 8620d7396e97..f7a778767a1e 100644 --- a/java/compiler/impl/src/com/intellij/compiler/options/CompilerUIConfigurable.java +++ b/java/compiler/impl/src/com/intellij/compiler/options/CompilerUIConfigurable.java @@ -1,246 +1,246 @@ -/* - * 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.compiler.options; - -import com.intellij.compiler.CompilerConfiguration; -import com.intellij.compiler.CompilerConfigurationImpl; -import com.intellij.compiler.CompilerWorkspaceConfiguration; -import com.intellij.compiler.MalformedPatternException; -import com.intellij.compiler.impl.TranslatingCompilerFilesMonitor; -import com.intellij.compiler.server.BuildManager; -import com.intellij.openapi.compiler.CompilerBundle; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.options.Configurable; -import com.intellij.openapi.options.ConfigurationException; -import com.intellij.openapi.options.SearchableConfigurable; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.ui.components.JBLabel; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.StringTokenizer; - -public class CompilerUIConfigurable implements SearchableConfigurable, Configurable.NoScroll { - private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.options.CompilerUIConfigurable"); - private JPanel myPanel; - private final Project myProject; - - private JTextField myResourcePatternsField; - private JCheckBox myCbClearOutputDirectory; - private JCheckBox myCbAssertNotNull; - private JBLabel myPatternLegendLabel; - private JCheckBox myCbAutoShowFirstError; - private JCheckBox myCbUseExternalBuild; - private JCheckBox myCbEnableAutomake; - private JCheckBox myCbParallelCompilation; - private JTextField myHeapSizeField; - private JTextField myVMOptionsField; - private JLabel myHeapSizeLabel; - private JLabel myVMOptionsLabel; - - public CompilerUIConfigurable(final Project project) { - myProject = project; - - myPatternLegendLabel.setText("" + - "Use ; to separate patterns and ! to negate a pattern. " + - "Accepted wildcards: ? — exactly one symbol; * — zero or more symbols; " + - "/ — path separator; /**/ — any number of directories; " + - "<dir_name>:<pattern> — restrict to source roots with the specified name" + - ""); - myCbUseExternalBuild.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - updateExternalMakeOptionControls(myCbUseExternalBuild.isSelected()); - } - }); - } - - public void reset() { - - final CompilerConfigurationImpl configuration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject); - final CompilerWorkspaceConfiguration workspaceConfiguration = CompilerWorkspaceConfiguration.getInstance(myProject); - myCbAutoShowFirstError.setSelected(workspaceConfiguration.AUTO_SHOW_ERRORS_IN_EDITOR); - myCbClearOutputDirectory.setSelected(workspaceConfiguration.CLEAR_OUTPUT_DIRECTORY); - myCbAssertNotNull.setSelected(configuration.isAddNotNullAssertions()); - myCbUseExternalBuild.setSelected(workspaceConfiguration.USE_COMPILE_SERVER); - myCbEnableAutomake.setSelected(workspaceConfiguration.MAKE_PROJECT_ON_SAVE); - myCbParallelCompilation.setSelected(workspaceConfiguration.PARALLEL_COMPILATION); - myHeapSizeField.setText(String.valueOf(workspaceConfiguration.COMPILER_PROCESS_HEAP_SIZE)); - final String options = workspaceConfiguration.COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS; - myVMOptionsField.setText(options == null? "" : options.trim()); - updateExternalMakeOptionControls(myCbUseExternalBuild.isSelected()); - - configuration.convertPatterns(); - - myResourcePatternsField.setText(patternsToString(configuration.getResourceFilePatterns())); - } - - private static String patternsToString(final String[] patterns) { - final StringBuilder extensionsString = new StringBuilder(); - for (int idx = 0; idx < patterns.length; idx++) { - if (idx > 0) { - extensionsString.append(";"); - } - extensionsString.append(patterns[idx]); - } - return extensionsString.toString(); - } - - public void apply() throws ConfigurationException { - - CompilerConfigurationImpl configuration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject); - final CompilerWorkspaceConfiguration workspaceConfiguration = CompilerWorkspaceConfiguration.getInstance(myProject); - workspaceConfiguration.AUTO_SHOW_ERRORS_IN_EDITOR = myCbAutoShowFirstError.isSelected(); - workspaceConfiguration.CLEAR_OUTPUT_DIRECTORY = myCbClearOutputDirectory.isSelected(); - boolean wasUsingExternalMake = workspaceConfiguration.USE_COMPILE_SERVER; - workspaceConfiguration.USE_COMPILE_SERVER = myCbUseExternalBuild.isSelected(); - workspaceConfiguration.MAKE_PROJECT_ON_SAVE = myCbEnableAutomake.isSelected(); - workspaceConfiguration.PARALLEL_COMPILATION = myCbParallelCompilation.isSelected(); - try { - workspaceConfiguration.COMPILER_PROCESS_HEAP_SIZE = Integer.parseInt(myHeapSizeField.getText().trim()); - } - catch (NumberFormatException ignored) { - LOG.info(ignored); - } - workspaceConfiguration.COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS = myVMOptionsField.getText().trim(); - - configuration.setAddNotNullAssertions(myCbAssertNotNull.isSelected()); - configuration.removeResourceFilePatterns(); - String extensionString = myResourcePatternsField.getText().trim(); - applyResourcePatterns(extensionString, (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject)); - - // this will schedule for compilation all files that might become compilable after resource patterns' changing - final TranslatingCompilerFilesMonitor monitor = TranslatingCompilerFilesMonitor.getInstance(); - if (workspaceConfiguration.USE_COMPILE_SERVER) { - monitor.suspendProject(myProject); - //noinspection SSBasedInspection - SwingUtilities.invokeLater(new Runnable() { - public void run() { - BuildManager.getInstance().clearState(myProject); - } - }); - } - else { - // use old make - if (wasUsingExternalMake) { - monitor.watchProject(myProject); - monitor.scanSourcesForCompilableFiles(myProject); - if (!myProject.isDefault()) { - final File buildSystem = BuildManager.getInstance().getBuildSystemDirectory(); - final File[] subdirs = buildSystem.listFiles(); - if (subdirs != null) { - final String prefix = myProject.getName().toLowerCase(Locale.US) + "_"; - for (File subdir : subdirs) { - if (subdir.getName().startsWith(prefix)) { - FileUtil.asyncDelete(subdir); - } - } - } - } - } - } - } - - private static void applyResourcePatterns(String extensionString, final CompilerConfigurationImpl configuration) - throws ConfigurationException { - StringTokenizer tokenizer = new StringTokenizer(extensionString, ";", false); - List errors = new ArrayList(); - - while (tokenizer.hasMoreTokens()) { - String namePattern = tokenizer.nextToken(); - try { - configuration.addResourceFilePattern(namePattern); - } - catch (MalformedPatternException e) { - errors.add(new String[]{namePattern, e.getLocalizedMessage()}); - } - } - - if (errors.size() > 0) { - final StringBuilder pattersnsWithErrors = new StringBuilder(); - for (final Object error : errors) { - String[] pair = (String[])error; - pattersnsWithErrors.append("\n"); - pattersnsWithErrors.append(pair[0]); - pattersnsWithErrors.append(": "); - pattersnsWithErrors.append(pair[1]); - } - - throw new ConfigurationException( - CompilerBundle.message("error.compiler.configurable.malformed.patterns", pattersnsWithErrors.toString()), CompilerBundle.message("bad.resource.patterns.dialog.title") - ); - } - } - - public boolean isModified() { - boolean isModified = false; - final CompilerWorkspaceConfiguration workspaceConfiguration = CompilerWorkspaceConfiguration.getInstance(myProject); - isModified |= ComparingUtils.isModified(myCbAutoShowFirstError, workspaceConfiguration.AUTO_SHOW_ERRORS_IN_EDITOR); - isModified |= ComparingUtils.isModified(myCbUseExternalBuild, workspaceConfiguration.USE_COMPILE_SERVER); - isModified |= ComparingUtils.isModified(myCbEnableAutomake, workspaceConfiguration.MAKE_PROJECT_ON_SAVE); - isModified |= ComparingUtils.isModified(myCbParallelCompilation, workspaceConfiguration.PARALLEL_COMPILATION); - isModified |= ComparingUtils.isModified(myHeapSizeField, workspaceConfiguration.COMPILER_PROCESS_HEAP_SIZE); - isModified |= ComparingUtils.isModified(myVMOptionsField, workspaceConfiguration.COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS); - - final CompilerConfigurationImpl compilerConfiguration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject); - isModified |= ComparingUtils.isModified(myCbAssertNotNull, compilerConfiguration.isAddNotNullAssertions()); - isModified |= ComparingUtils.isModified(myCbClearOutputDirectory, workspaceConfiguration.CLEAR_OUTPUT_DIRECTORY); - isModified |= ComparingUtils.isModified(myResourcePatternsField, patternsToString(compilerConfiguration.getResourceFilePatterns())); - - return isModified; - } - - public String getDisplayName() { - return "General"; - } - - public String getHelpTopic() { - return null; - } - - @NotNull - public String getId() { - return "compiler.general"; - } - - public Runnable enableSearch(String option) { - return null; - } - - public JComponent createComponent() { - return myPanel; - } - - public void disposeUIResources() { - } - - private void updateExternalMakeOptionControls(boolean enabled) { - myCbEnableAutomake.setEnabled(enabled); - myCbParallelCompilation.setEnabled(enabled); - myHeapSizeField.setEnabled(enabled); - myVMOptionsField.setEnabled(enabled); - myHeapSizeLabel.setEnabled(enabled); - myVMOptionsLabel.setEnabled(enabled); - } - -} +/* + * 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.compiler.options; + +import com.intellij.compiler.CompilerConfiguration; +import com.intellij.compiler.CompilerConfigurationImpl; +import com.intellij.compiler.CompilerWorkspaceConfiguration; +import com.intellij.compiler.MalformedPatternException; +import com.intellij.compiler.impl.TranslatingCompilerFilesMonitor; +import com.intellij.compiler.server.BuildManager; +import com.intellij.openapi.compiler.CompilerBundle; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.SearchableConfigurable; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.ui.components.JBLabel; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.StringTokenizer; + +public class CompilerUIConfigurable implements SearchableConfigurable, Configurable.NoScroll { + private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.options.CompilerUIConfigurable"); + private JPanel myPanel; + private final Project myProject; + + private JTextField myResourcePatternsField; + private JCheckBox myCbClearOutputDirectory; + private JCheckBox myCbAssertNotNull; + private JBLabel myPatternLegendLabel; + private JCheckBox myCbAutoShowFirstError; + private JCheckBox myCbUseExternalBuild; + private JCheckBox myCbEnableAutomake; + private JCheckBox myCbParallelCompilation; + private JTextField myHeapSizeField; + private JTextField myVMOptionsField; + private JLabel myHeapSizeLabel; + private JLabel myVMOptionsLabel; + + public CompilerUIConfigurable(final Project project) { + myProject = project; + + myPatternLegendLabel.setText("" + + "Use ; to separate patterns and ! to negate a pattern. " + + "Accepted wildcards: ? — exactly one symbol; * — zero or more symbols; " + + "/ — path separator; /**/ — any number of directories; " + + "<dir_name>:<pattern> — restrict to source roots with the specified name" + + ""); + myCbUseExternalBuild.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + updateExternalMakeOptionControls(myCbUseExternalBuild.isSelected()); + } + }); + } + + public void reset() { + + final CompilerConfigurationImpl configuration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject); + final CompilerWorkspaceConfiguration workspaceConfiguration = CompilerWorkspaceConfiguration.getInstance(myProject); + myCbAutoShowFirstError.setSelected(workspaceConfiguration.AUTO_SHOW_ERRORS_IN_EDITOR); + myCbClearOutputDirectory.setSelected(workspaceConfiguration.CLEAR_OUTPUT_DIRECTORY); + myCbAssertNotNull.setSelected(configuration.isAddNotNullAssertions()); + myCbUseExternalBuild.setSelected(workspaceConfiguration.USE_COMPILE_SERVER); + myCbEnableAutomake.setSelected(workspaceConfiguration.MAKE_PROJECT_ON_SAVE); + myCbParallelCompilation.setSelected(workspaceConfiguration.PARALLEL_COMPILATION); + myHeapSizeField.setText(String.valueOf(workspaceConfiguration.COMPILER_PROCESS_HEAP_SIZE)); + final String options = workspaceConfiguration.COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS; + myVMOptionsField.setText(options == null? "" : options.trim()); + updateExternalMakeOptionControls(myCbUseExternalBuild.isSelected()); + + configuration.convertPatterns(); + + myResourcePatternsField.setText(patternsToString(configuration.getResourceFilePatterns())); + } + + private static String patternsToString(final String[] patterns) { + final StringBuilder extensionsString = new StringBuilder(); + for (int idx = 0; idx < patterns.length; idx++) { + if (idx > 0) { + extensionsString.append(";"); + } + extensionsString.append(patterns[idx]); + } + return extensionsString.toString(); + } + + public void apply() throws ConfigurationException { + + CompilerConfigurationImpl configuration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject); + final CompilerWorkspaceConfiguration workspaceConfiguration = CompilerWorkspaceConfiguration.getInstance(myProject); + workspaceConfiguration.AUTO_SHOW_ERRORS_IN_EDITOR = myCbAutoShowFirstError.isSelected(); + workspaceConfiguration.CLEAR_OUTPUT_DIRECTORY = myCbClearOutputDirectory.isSelected(); + boolean wasUsingExternalMake = workspaceConfiguration.USE_COMPILE_SERVER; + workspaceConfiguration.USE_COMPILE_SERVER = myCbUseExternalBuild.isSelected(); + workspaceConfiguration.MAKE_PROJECT_ON_SAVE = myCbEnableAutomake.isSelected(); + workspaceConfiguration.PARALLEL_COMPILATION = myCbParallelCompilation.isSelected(); + try { + workspaceConfiguration.COMPILER_PROCESS_HEAP_SIZE = Integer.parseInt(myHeapSizeField.getText().trim()); + } + catch (NumberFormatException ignored) { + LOG.info(ignored); + } + workspaceConfiguration.COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS = myVMOptionsField.getText().trim(); + + configuration.setAddNotNullAssertions(myCbAssertNotNull.isSelected()); + configuration.removeResourceFilePatterns(); + String extensionString = myResourcePatternsField.getText().trim(); + applyResourcePatterns(extensionString, (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject)); + + // this will schedule for compilation all files that might become compilable after resource patterns' changing + final TranslatingCompilerFilesMonitor monitor = TranslatingCompilerFilesMonitor.getInstance(); + if (workspaceConfiguration.USE_COMPILE_SERVER) { + monitor.suspendProject(myProject); + //noinspection SSBasedInspection + SwingUtilities.invokeLater(new Runnable() { + public void run() { + BuildManager.getInstance().clearState(myProject); + } + }); + } + else { + // use old make + if (wasUsingExternalMake) { + monitor.watchProject(myProject); + monitor.scanSourcesForCompilableFiles(myProject); + if (!myProject.isDefault()) { + final File buildSystem = BuildManager.getInstance().getBuildSystemDirectory(); + final File[] subdirs = buildSystem.listFiles(); + if (subdirs != null) { + final String prefix = myProject.getName().toLowerCase(Locale.US) + "_"; + for (File subdir : subdirs) { + if (subdir.getName().startsWith(prefix)) { + FileUtil.asyncDelete(subdir); + } + } + } + } + } + } + } + + private static void applyResourcePatterns(String extensionString, final CompilerConfigurationImpl configuration) + throws ConfigurationException { + StringTokenizer tokenizer = new StringTokenizer(extensionString, ";", false); + List errors = new ArrayList(); + + while (tokenizer.hasMoreTokens()) { + String namePattern = tokenizer.nextToken(); + try { + configuration.addResourceFilePattern(namePattern); + } + catch (MalformedPatternException e) { + errors.add(new String[]{namePattern, e.getLocalizedMessage()}); + } + } + + if (errors.size() > 0) { + final StringBuilder pattersnsWithErrors = new StringBuilder(); + for (final Object error : errors) { + String[] pair = (String[])error; + pattersnsWithErrors.append("\n"); + pattersnsWithErrors.append(pair[0]); + pattersnsWithErrors.append(": "); + pattersnsWithErrors.append(pair[1]); + } + + throw new ConfigurationException( + CompilerBundle.message("error.compiler.configurable.malformed.patterns", pattersnsWithErrors.toString()), CompilerBundle.message("bad.resource.patterns.dialog.title") + ); + } + } + + public boolean isModified() { + boolean isModified = false; + final CompilerWorkspaceConfiguration workspaceConfiguration = CompilerWorkspaceConfiguration.getInstance(myProject); + isModified |= ComparingUtils.isModified(myCbAutoShowFirstError, workspaceConfiguration.AUTO_SHOW_ERRORS_IN_EDITOR); + isModified |= ComparingUtils.isModified(myCbUseExternalBuild, workspaceConfiguration.USE_COMPILE_SERVER); + isModified |= ComparingUtils.isModified(myCbEnableAutomake, workspaceConfiguration.MAKE_PROJECT_ON_SAVE); + isModified |= ComparingUtils.isModified(myCbParallelCompilation, workspaceConfiguration.PARALLEL_COMPILATION); + isModified |= ComparingUtils.isModified(myHeapSizeField, workspaceConfiguration.COMPILER_PROCESS_HEAP_SIZE); + isModified |= ComparingUtils.isModified(myVMOptionsField, workspaceConfiguration.COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS); + + final CompilerConfigurationImpl compilerConfiguration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject); + isModified |= ComparingUtils.isModified(myCbAssertNotNull, compilerConfiguration.isAddNotNullAssertions()); + isModified |= ComparingUtils.isModified(myCbClearOutputDirectory, workspaceConfiguration.CLEAR_OUTPUT_DIRECTORY); + isModified |= ComparingUtils.isModified(myResourcePatternsField, patternsToString(compilerConfiguration.getResourceFilePatterns())); + + return isModified; + } + + public String getDisplayName() { + return "General"; + } + + public String getHelpTopic() { + return null; + } + + @NotNull + public String getId() { + return "compiler.general"; + } + + public Runnable enableSearch(String option) { + return null; + } + + public JComponent createComponent() { + return myPanel; + } + + public void disposeUIResources() { + } + + private void updateExternalMakeOptionControls(boolean enabled) { + myCbEnableAutomake.setEnabled(enabled); + myCbParallelCompilation.setEnabled(enabled); + myHeapSizeField.setEnabled(enabled); + myVMOptionsField.setEnabled(enabled); + myHeapSizeLabel.setEnabled(enabled); + myVMOptionsLabel.setEnabled(enabled); + } + +} diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProvider.java b/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProvider.java index 9666f729b1fb..a1fa1b427159 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProvider.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/run/BuildArtifactsBeforeRunTaskProvider.java @@ -1,260 +1,260 @@ -/* - * 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.packaging.impl.run; - -import com.intellij.execution.BeforeRunTask; -import com.intellij.execution.BeforeRunTaskProvider; -import com.intellij.execution.RunManagerEx; -import com.intellij.execution.configurations.RunConfiguration; -import com.intellij.execution.impl.ConfigurationSettingsEditorWrapper; -import com.intellij.execution.runners.ExecutionEnvironment; -import com.intellij.icons.AllIcons; -import com.intellij.ide.DataManager; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.application.ReadAction; -import com.intellij.openapi.application.Result; -import com.intellij.openapi.compiler.*; -import com.intellij.openapi.compiler.Compiler; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogBuilder; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Ref; -import com.intellij.packaging.artifacts.*; -import com.intellij.packaging.impl.compiler.ArtifactAwareCompiler; -import com.intellij.packaging.impl.compiler.ArtifactCompileScope; -import com.intellij.packaging.impl.compiler.ArtifactsCompiler; -import com.intellij.util.concurrency.Semaphore; -import com.intellij.util.containers.ContainerUtil; -import gnu.trove.THashSet; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import java.awt.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** - * @author nik - */ -public class BuildArtifactsBeforeRunTaskProvider extends BeforeRunTaskProvider { - @NonNls public static final String BUILD_ARTIFACTS_ID = "BuildArtifacts"; - public static final Key ID = Key.create(BUILD_ARTIFACTS_ID); - private final Project myProject; - - public BuildArtifactsBeforeRunTaskProvider(Project project) { - myProject = project; - project.getMessageBus().connect().subscribe(ArtifactManager.TOPIC, new ArtifactAdapter() { - @Override - public void artifactRemoved(@NotNull Artifact artifact) { - final RunManagerEx runManager = RunManagerEx.getInstanceEx(myProject); - for (RunConfiguration configuration : runManager.getAllConfigurations()) { - final List tasks = runManager.getBeforeRunTasks(configuration, ID); - for (BuildArtifactsBeforeRunTask task : tasks) { - final String artifactName = artifact.getName(); - final List pointersList = task.getArtifactPointers(); - final ArtifactPointer[] pointers = pointersList.toArray(new ArtifactPointer[pointersList.size()]); - for (ArtifactPointer pointer : pointers) { - if (pointer.getArtifactName().equals(artifactName) && ArtifactManager.getInstance(myProject).findArtifact(artifactName) == null) { - task.removeArtifact(pointer); - } - } - } - } - } - }); - } - - public Key getId() { - return ID; - } - - @Override - public Icon getIcon() { - return AllIcons.Nodes.Artifact; - } - - @Override - public String getName() { - return CompilerBundle.message("build.artifacts.before.run.description.empty"); - } - - @Override - public Icon getTaskIcon(BuildArtifactsBeforeRunTask task) { - List pointers = task.getArtifactPointers(); - if (pointers == null || pointers.isEmpty()) - return getIcon(); - Artifact artifact = pointers.get(0).getArtifact(); - if (artifact == null) - return getIcon(); - return artifact.getArtifactType().getIcon(); - } - - @Override - public String getDescription(BuildArtifactsBeforeRunTask task) { - final List pointers = task.getArtifactPointers(); - if (pointers.isEmpty()) { - return CompilerBundle.message("build.artifacts.before.run.description.empty"); - } - if (pointers.size() == 1) { - return CompilerBundle.message("build.artifacts.before.run.description.single", pointers.get(0).getArtifactName()); - } - return CompilerBundle.message("build.artifacts.before.run.description.multiple", pointers.size()); - } - - public boolean isConfigurable() { - return true; - } - - public BuildArtifactsBeforeRunTask createTask(RunConfiguration runConfiguration) { - if (myProject.isDefault()) return null; - return new BuildArtifactsBeforeRunTask(myProject); - } - - public boolean configureTask(RunConfiguration runConfiguration, BuildArtifactsBeforeRunTask task) { - final Artifact[] artifacts = ArtifactManager.getInstance(myProject).getArtifacts(); - Set pointers = new THashSet(); - for (Artifact artifact : artifacts) { - pointers.add(ArtifactPointerManager.getInstance(myProject).createPointer(artifact)); - } - pointers.addAll(task.getArtifactPointers()); - ArtifactChooser chooser = new ArtifactChooser(new ArrayList(pointers)); - chooser.markElements(task.getArtifactPointers()); - chooser.setPreferredSize(new Dimension(400, 300)); - - DialogBuilder builder = new DialogBuilder(myProject); - builder.setTitle(CompilerBundle.message("build.artifacts.before.run.selector.title")); - builder.setDimensionServiceKey("#BuildArtifactsBeforeRunChooser"); - builder.addOkAction(); - builder.addCancelAction(); - builder.setCenterPanel(chooser); - builder.setPreferedFocusComponent(chooser); - if (builder.show() == DialogWrapper.OK_EXIT_CODE) { - task.setArtifactPointers(chooser.getMarkedElements()); - return true; - } - return false; - } - - @Override - public boolean canExecuteTask(RunConfiguration configuration, BuildArtifactsBeforeRunTask task) { - for (ArtifactPointer pointer: task.getArtifactPointers()) { - if (pointer.getArtifact() != null) - return true; - } - return false; - } - - public boolean executeTask(DataContext context, - RunConfiguration configuration, - ExecutionEnvironment env, - final BuildArtifactsBeforeRunTask task) { - final Ref result = Ref.create(false); - final Semaphore finished = new Semaphore(); - - final List artifacts = new ArrayList(); - new ReadAction() { - protected void run(final Result result) { - for (ArtifactPointer pointer : task.getArtifactPointers()) { - ContainerUtil.addIfNotNull(pointer.getArtifact(), artifacts); - } - } - }.execute(); - - final CompileStatusNotification callback = new CompileStatusNotification() { - public void finished(boolean aborted, int errors, int warnings, CompileContext compileContext) { - result.set(!aborted && errors == 0); - finished.up(); - } - }; - final CompilerFilter compilerFilter = new CompilerFilter() { - public boolean acceptCompiler(Compiler compiler) { - return compiler instanceof ArtifactsCompiler - || compiler instanceof ArtifactAwareCompiler && ((ArtifactAwareCompiler)compiler).shouldRun(artifacts); - } - }; - - ApplicationManager.getApplication().invokeAndWait(new Runnable() { - public void run() { - final CompilerManager manager = CompilerManager.getInstance(myProject); - finished.down(); - manager.make(ArtifactCompileScope.createArtifactsScope(myProject, artifacts), compilerFilter, callback); - } - }, ModalityState.NON_MODAL); - - finished.waitFor(); - return result.get(); - } - - public static void setBuildArtifactBeforeRunOption(@NotNull JComponent runConfigurationEditorComponent, - Project project, - @NotNull Artifact artifact, - final boolean enable) { - final DataContext dataContext = DataManager.getInstance().getDataContext(runConfigurationEditorComponent); - final ConfigurationSettingsEditorWrapper editor = ConfigurationSettingsEditorWrapper.CONFIGURATION_EDITOR_KEY.getData(dataContext); - if (editor != null) { - List tasks = editor.getStepsBeforeLaunch(); - List myTasks = new ArrayList(); - for (BeforeRunTask task : tasks) { - if (task instanceof BuildArtifactsBeforeRunTask) { - myTasks.add((BuildArtifactsBeforeRunTask)task); - } - } - if (enable && myTasks.isEmpty()) { - BuildArtifactsBeforeRunTask task = new BuildArtifactsBeforeRunTask(project); - task.addArtifact(artifact); - task.setEnabled(true); - editor.addBeforeLaunchStep(task); - } - else { - for (BuildArtifactsBeforeRunTask task : myTasks) { - if (enable) { - task.addArtifact(artifact); - task.setEnabled(true); - } - else { - task.removeArtifact(artifact); - if (task.getArtifactPointers().isEmpty()) { - task.setEnabled(false); - } - } - } - } - } - } - - public static void setBuildArtifactBeforeRun(@NotNull Project project, @NotNull RunConfiguration configuration, @NotNull Artifact artifact) { - RunManagerEx runManager = RunManagerEx.getInstanceEx(project); - final List buildArtifactsTasks = runManager.getBeforeRunTasks(configuration, ID); - if (buildArtifactsTasks.isEmpty()) { //Add new task if absent - BuildArtifactsBeforeRunTask task = new BuildArtifactsBeforeRunTask(project); - buildArtifactsTasks.add(task); - List tasks = runManager.getBeforeRunTasks(configuration); - tasks.add(task); - runManager.setBeforeRunTasks(configuration, tasks, false); - } - - for (BuildArtifactsBeforeRunTask task : buildArtifactsTasks) { - task.setEnabled(true); - task.addArtifact(artifact); - - } - } -} +/* + * 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.packaging.impl.run; + +import com.intellij.execution.BeforeRunTask; +import com.intellij.execution.BeforeRunTaskProvider; +import com.intellij.execution.RunManagerEx; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.execution.impl.ConfigurationSettingsEditorWrapper; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.icons.AllIcons; +import com.intellij.ide.DataManager; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.application.ReadAction; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.compiler.*; +import com.intellij.openapi.compiler.Compiler; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogBuilder; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Ref; +import com.intellij.packaging.artifacts.*; +import com.intellij.packaging.impl.compiler.ArtifactAwareCompiler; +import com.intellij.packaging.impl.compiler.ArtifactCompileScope; +import com.intellij.packaging.impl.compiler.ArtifactsCompiler; +import com.intellij.util.concurrency.Semaphore; +import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * @author nik + */ +public class BuildArtifactsBeforeRunTaskProvider extends BeforeRunTaskProvider { + @NonNls public static final String BUILD_ARTIFACTS_ID = "BuildArtifacts"; + public static final Key ID = Key.create(BUILD_ARTIFACTS_ID); + private final Project myProject; + + public BuildArtifactsBeforeRunTaskProvider(Project project) { + myProject = project; + project.getMessageBus().connect().subscribe(ArtifactManager.TOPIC, new ArtifactAdapter() { + @Override + public void artifactRemoved(@NotNull Artifact artifact) { + final RunManagerEx runManager = RunManagerEx.getInstanceEx(myProject); + for (RunConfiguration configuration : runManager.getAllConfigurations()) { + final List tasks = runManager.getBeforeRunTasks(configuration, ID); + for (BuildArtifactsBeforeRunTask task : tasks) { + final String artifactName = artifact.getName(); + final List pointersList = task.getArtifactPointers(); + final ArtifactPointer[] pointers = pointersList.toArray(new ArtifactPointer[pointersList.size()]); + for (ArtifactPointer pointer : pointers) { + if (pointer.getArtifactName().equals(artifactName) && ArtifactManager.getInstance(myProject).findArtifact(artifactName) == null) { + task.removeArtifact(pointer); + } + } + } + } + } + }); + } + + public Key getId() { + return ID; + } + + @Override + public Icon getIcon() { + return AllIcons.Nodes.Artifact; + } + + @Override + public String getName() { + return CompilerBundle.message("build.artifacts.before.run.description.empty"); + } + + @Override + public Icon getTaskIcon(BuildArtifactsBeforeRunTask task) { + List pointers = task.getArtifactPointers(); + if (pointers == null || pointers.isEmpty()) + return getIcon(); + Artifact artifact = pointers.get(0).getArtifact(); + if (artifact == null) + return getIcon(); + return artifact.getArtifactType().getIcon(); + } + + @Override + public String getDescription(BuildArtifactsBeforeRunTask task) { + final List pointers = task.getArtifactPointers(); + if (pointers.isEmpty()) { + return CompilerBundle.message("build.artifacts.before.run.description.empty"); + } + if (pointers.size() == 1) { + return CompilerBundle.message("build.artifacts.before.run.description.single", pointers.get(0).getArtifactName()); + } + return CompilerBundle.message("build.artifacts.before.run.description.multiple", pointers.size()); + } + + public boolean isConfigurable() { + return true; + } + + public BuildArtifactsBeforeRunTask createTask(RunConfiguration runConfiguration) { + if (myProject.isDefault()) return null; + return new BuildArtifactsBeforeRunTask(myProject); + } + + public boolean configureTask(RunConfiguration runConfiguration, BuildArtifactsBeforeRunTask task) { + final Artifact[] artifacts = ArtifactManager.getInstance(myProject).getArtifacts(); + Set pointers = new THashSet(); + for (Artifact artifact : artifacts) { + pointers.add(ArtifactPointerManager.getInstance(myProject).createPointer(artifact)); + } + pointers.addAll(task.getArtifactPointers()); + ArtifactChooser chooser = new ArtifactChooser(new ArrayList(pointers)); + chooser.markElements(task.getArtifactPointers()); + chooser.setPreferredSize(new Dimension(400, 300)); + + DialogBuilder builder = new DialogBuilder(myProject); + builder.setTitle(CompilerBundle.message("build.artifacts.before.run.selector.title")); + builder.setDimensionServiceKey("#BuildArtifactsBeforeRunChooser"); + builder.addOkAction(); + builder.addCancelAction(); + builder.setCenterPanel(chooser); + builder.setPreferedFocusComponent(chooser); + if (builder.show() == DialogWrapper.OK_EXIT_CODE) { + task.setArtifactPointers(chooser.getMarkedElements()); + return true; + } + return false; + } + + @Override + public boolean canExecuteTask(RunConfiguration configuration, BuildArtifactsBeforeRunTask task) { + for (ArtifactPointer pointer: task.getArtifactPointers()) { + if (pointer.getArtifact() != null) + return true; + } + return false; + } + + public boolean executeTask(DataContext context, + RunConfiguration configuration, + ExecutionEnvironment env, + final BuildArtifactsBeforeRunTask task) { + final Ref result = Ref.create(false); + final Semaphore finished = new Semaphore(); + + final List artifacts = new ArrayList(); + new ReadAction() { + protected void run(final Result result) { + for (ArtifactPointer pointer : task.getArtifactPointers()) { + ContainerUtil.addIfNotNull(pointer.getArtifact(), artifacts); + } + } + }.execute(); + + final CompileStatusNotification callback = new CompileStatusNotification() { + public void finished(boolean aborted, int errors, int warnings, CompileContext compileContext) { + result.set(!aborted && errors == 0); + finished.up(); + } + }; + final CompilerFilter compilerFilter = new CompilerFilter() { + public boolean acceptCompiler(Compiler compiler) { + return compiler instanceof ArtifactsCompiler + || compiler instanceof ArtifactAwareCompiler && ((ArtifactAwareCompiler)compiler).shouldRun(artifacts); + } + }; + + ApplicationManager.getApplication().invokeAndWait(new Runnable() { + public void run() { + final CompilerManager manager = CompilerManager.getInstance(myProject); + finished.down(); + manager.make(ArtifactCompileScope.createArtifactsScope(myProject, artifacts), compilerFilter, callback); + } + }, ModalityState.NON_MODAL); + + finished.waitFor(); + return result.get(); + } + + public static void setBuildArtifactBeforeRunOption(@NotNull JComponent runConfigurationEditorComponent, + Project project, + @NotNull Artifact artifact, + final boolean enable) { + final DataContext dataContext = DataManager.getInstance().getDataContext(runConfigurationEditorComponent); + final ConfigurationSettingsEditorWrapper editor = ConfigurationSettingsEditorWrapper.CONFIGURATION_EDITOR_KEY.getData(dataContext); + if (editor != null) { + List tasks = editor.getStepsBeforeLaunch(); + List myTasks = new ArrayList(); + for (BeforeRunTask task : tasks) { + if (task instanceof BuildArtifactsBeforeRunTask) { + myTasks.add((BuildArtifactsBeforeRunTask)task); + } + } + if (enable && myTasks.isEmpty()) { + BuildArtifactsBeforeRunTask task = new BuildArtifactsBeforeRunTask(project); + task.addArtifact(artifact); + task.setEnabled(true); + editor.addBeforeLaunchStep(task); + } + else { + for (BuildArtifactsBeforeRunTask task : myTasks) { + if (enable) { + task.addArtifact(artifact); + task.setEnabled(true); + } + else { + task.removeArtifact(artifact); + if (task.getArtifactPointers().isEmpty()) { + task.setEnabled(false); + } + } + } + } + } + } + + public static void setBuildArtifactBeforeRun(@NotNull Project project, @NotNull RunConfiguration configuration, @NotNull Artifact artifact) { + RunManagerEx runManager = RunManagerEx.getInstanceEx(project); + final List buildArtifactsTasks = runManager.getBeforeRunTasks(configuration, ID); + if (buildArtifactsTasks.isEmpty()) { //Add new task if absent + BuildArtifactsBeforeRunTask task = new BuildArtifactsBeforeRunTask(project); + buildArtifactsTasks.add(task); + List tasks = runManager.getBeforeRunTasks(configuration); + tasks.add(task); + runManager.setBeforeRunTasks(configuration, tasks, false); + } + + for (BuildArtifactsBeforeRunTask task : buildArtifactsTasks) { + task.setEnabled(true); + task.addArtifact(artifact); + + } + } +} diff --git a/java/compiler/openapi/src/com/intellij/compiler/CompilerWorkspaceConfiguration.java b/java/compiler/openapi/src/com/intellij/compiler/CompilerWorkspaceConfiguration.java index c739ec86bddd..98250d994f53 100644 --- a/java/compiler/openapi/src/com/intellij/compiler/CompilerWorkspaceConfiguration.java +++ b/java/compiler/openapi/src/com/intellij/compiler/CompilerWorkspaceConfiguration.java @@ -1,65 +1,65 @@ -/* - * 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. - */ - -/* - * @author Eugene Zhuravlev - */ -package com.intellij.compiler; - -import com.intellij.openapi.components.*; -import com.intellij.openapi.project.Project; -import com.intellij.util.xmlb.XmlSerializerUtil; - -@State( - name = "CompilerWorkspaceConfiguration", - storages = { - @Storage( - file = StoragePathMacros.WORKSPACE_FILE - )} -) -public class CompilerWorkspaceConfiguration implements PersistentStateComponent { - public static final int DEFAULT_COMPILE_PROCESS_HEAP_SIZE = 700; - public static final String DEFAULT_COMPILE_PROCESS_VM_OPTIONS = "-ea"; - - public boolean AUTO_SHOW_ERRORS_IN_EDITOR = true; - @Deprecated public boolean CLOSE_MESSAGE_VIEW_IF_SUCCESS = true; - public boolean CLEAR_OUTPUT_DIRECTORY = true; - public boolean USE_COMPILE_SERVER = true; - public boolean MAKE_PROJECT_ON_SAVE = true; - public boolean PARALLEL_COMPILATION = false; - public int COMPILER_PROCESS_HEAP_SIZE = DEFAULT_COMPILE_PROCESS_HEAP_SIZE; - public String COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS = DEFAULT_COMPILE_PROCESS_VM_OPTIONS; - - public static CompilerWorkspaceConfiguration getInstance(Project project) { - return ServiceManager.getService(project, CompilerWorkspaceConfiguration.class); - } - - public CompilerWorkspaceConfiguration getState() { - return this; - } - - public void loadState(CompilerWorkspaceConfiguration state) { - XmlSerializerUtil.copyBean(state, this); - } - - public boolean useOutOfProcessBuild() { - return USE_COMPILE_SERVER; - } - - public boolean allowAutoMakeWhileRunningApplication() { - return false;/*ALLOW_AUTOMAKE_WHILE_RUNNING_APPLICATION*/ - } -} +/* + * 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. + */ + +/* + * @author Eugene Zhuravlev + */ +package com.intellij.compiler; + +import com.intellij.openapi.components.*; +import com.intellij.openapi.project.Project; +import com.intellij.util.xmlb.XmlSerializerUtil; + +@State( + name = "CompilerWorkspaceConfiguration", + storages = { + @Storage( + file = StoragePathMacros.WORKSPACE_FILE + )} +) +public class CompilerWorkspaceConfiguration implements PersistentStateComponent { + public static final int DEFAULT_COMPILE_PROCESS_HEAP_SIZE = 700; + public static final String DEFAULT_COMPILE_PROCESS_VM_OPTIONS = "-ea"; + + public boolean AUTO_SHOW_ERRORS_IN_EDITOR = true; + @Deprecated public boolean CLOSE_MESSAGE_VIEW_IF_SUCCESS = true; + public boolean CLEAR_OUTPUT_DIRECTORY = true; + public boolean USE_COMPILE_SERVER = true; + public boolean MAKE_PROJECT_ON_SAVE = true; + public boolean PARALLEL_COMPILATION = false; + public int COMPILER_PROCESS_HEAP_SIZE = DEFAULT_COMPILE_PROCESS_HEAP_SIZE; + public String COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS = DEFAULT_COMPILE_PROCESS_VM_OPTIONS; + + public static CompilerWorkspaceConfiguration getInstance(Project project) { + return ServiceManager.getService(project, CompilerWorkspaceConfiguration.class); + } + + public CompilerWorkspaceConfiguration getState() { + return this; + } + + public void loadState(CompilerWorkspaceConfiguration state) { + XmlSerializerUtil.copyBean(state, this); + } + + public boolean useOutOfProcessBuild() { + return USE_COMPILE_SERVER; + } + + public boolean allowAutoMakeWhileRunningApplication() { + return false;/*ALLOW_AUTOMAKE_WHILE_RUNNING_APPLICATION*/ + } +} diff --git a/java/execution/impl/src/com/intellij/compiler/options/CompileStepBeforeRun.java b/java/execution/impl/src/com/intellij/compiler/options/CompileStepBeforeRun.java index 3d987f3e9a7c..229c9f5e7b33 100644 --- a/java/execution/impl/src/com/intellij/compiler/options/CompileStepBeforeRun.java +++ b/java/execution/impl/src/com/intellij/compiler/options/CompileStepBeforeRun.java @@ -1,189 +1,189 @@ -/* - * 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.compiler.options; - -import com.intellij.execution.BeforeRunTask; -import com.intellij.execution.BeforeRunTaskProvider; -import com.intellij.execution.ExecutionBundle; -import com.intellij.execution.configurations.RunConfiguration; -import com.intellij.execution.configurations.RunConfigurationBase; -import com.intellij.execution.configurations.RunProfileWithCompileBeforeLaunchOption; -import com.intellij.execution.remote.RemoteConfiguration; -import com.intellij.execution.runners.ExecutionEnvironment; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.DataContext; -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.diagnostic.Logger; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Ref; -import com.intellij.util.concurrency.Semaphore; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; - -/** - * @author spleaner - */ -public class CompileStepBeforeRun extends BeforeRunTaskProvider { - private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.options.CompileStepBeforeRun"); - public static final Key ID = Key.create("Make"); - private static final Key RUN_CONFIGURATION = Key.create("RUN_CONFIGURATION"); - private static final Key RUN_CONFIGURATION_TYPE_ID = Key.create("RUN_CONFIGURATION_TYPE_ID"); - private static final Key RUNNER_ID = Key.create("RUNNER_ID"); - - @NonNls protected static final String MAKE_PROJECT_ON_RUN_KEY = "makeProjectOnRun"; - - private final Project myProject; - - public CompileStepBeforeRun(@NotNull final Project project) { - myProject = project; - } - - public Key getId() { - return ID; - } - - @Override - public String getName() { - return ExecutionBundle.message("before.launch.compile.step"); - } - - @Override - public String getDescription(MakeBeforeRunTask task) { - return ExecutionBundle.message("before.launch.compile.step"); - } - - @Override - public Icon getIcon() { - return AllIcons.Actions.Compile; - } - - @Override - public Icon getTaskIcon(MakeBeforeRunTask task) { - return AllIcons.Actions.Compile; - } - - public MakeBeforeRunTask createTask(RunConfiguration runConfiguration) { - return !(runConfiguration instanceof RemoteConfiguration) && runConfiguration instanceof RunProfileWithCompileBeforeLaunchOption - ? new MakeBeforeRunTask() - : null; - } - - public boolean configureTask(RunConfiguration runConfiguration, MakeBeforeRunTask task) { - return false; - } - - @Override - public boolean canExecuteTask(RunConfiguration configuration, MakeBeforeRunTask task) { - return true; - } - - public boolean executeTask(DataContext context, final RunConfiguration configuration, final ExecutionEnvironment env, MakeBeforeRunTask task) { - if (!(configuration instanceof RunProfileWithCompileBeforeLaunchOption)) { - return true; - } - - if (configuration instanceof RunConfigurationBase && ((RunConfigurationBase)configuration).excludeCompileBeforeLaunchOption()) { - return true; - } - - final RunProfileWithCompileBeforeLaunchOption runConfiguration = (RunProfileWithCompileBeforeLaunchOption)configuration; - final Ref result = new Ref(Boolean.FALSE); - try { - - final Semaphore done = new Semaphore(); - done.down(); - final CompileStatusNotification callback = new CompileStatusNotification() { - public void finished(final boolean aborted, final int errors, final int warnings, CompileContext compileContext) { - if (errors == 0 && !aborted) { - result.set(Boolean.TRUE); - } - done.up(); - } - }; - - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - CompileScope scope; - final CompilerManager compilerManager = CompilerManager.getInstance(myProject); - if (Boolean.valueOf(System.getProperty(MAKE_PROJECT_ON_RUN_KEY, Boolean.FALSE.toString())).booleanValue()) { - // user explicitly requested whole-project make - scope = compilerManager.createProjectCompileScope(myProject); - } - else { - final Module[] modules = runConfiguration.getModules(); - if (modules.length > 0) { - for (Module module : modules) { - if (module == null) { - LOG.error("RunConfiguration should not return null modules. Configuration=" + runConfiguration.getName() + "; class=" + - runConfiguration.getClass().getName()); - } - } - scope = compilerManager.createModulesCompileScope(modules, true); - } - else { - scope = compilerManager.createProjectCompileScope(myProject); - } - } - - if (!myProject.isDisposed()) { - scope.putUserData(RUN_CONFIGURATION, configuration); - scope.putUserData(RUN_CONFIGURATION_TYPE_ID, configuration.getType().getId()); - scope.putUserData(RUNNER_ID, env.getRunnerId()); - compilerManager.make(scope, callback); - } - else { - done.up(); - } - } - }); - done.waitFor(); - } - catch (Exception e) { - return false; - } - - return result.get(); - } - - public boolean isConfigurable() { - return false; - } - - @Nullable - public static RunConfiguration getRunConfiguration(final CompileContext context) { - return getRunConfiguration(context.getCompileScope()); - } - - @Nullable - public static RunConfiguration getRunConfiguration(final CompileScope compileScope) { - return compileScope.getUserData(RUN_CONFIGURATION); - } - - public static class MakeBeforeRunTask extends BeforeRunTask { - private MakeBeforeRunTask() { - super(ID); - setEnabled(true); - } - } -} +/* + * 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.compiler.options; + +import com.intellij.execution.BeforeRunTask; +import com.intellij.execution.BeforeRunTaskProvider; +import com.intellij.execution.ExecutionBundle; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.execution.configurations.RunConfigurationBase; +import com.intellij.execution.configurations.RunProfileWithCompileBeforeLaunchOption; +import com.intellij.execution.remote.RemoteConfiguration; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.DataContext; +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.diagnostic.Logger; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Ref; +import com.intellij.util.concurrency.Semaphore; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +/** + * @author spleaner + */ +public class CompileStepBeforeRun extends BeforeRunTaskProvider { + private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.options.CompileStepBeforeRun"); + public static final Key ID = Key.create("Make"); + private static final Key RUN_CONFIGURATION = Key.create("RUN_CONFIGURATION"); + private static final Key RUN_CONFIGURATION_TYPE_ID = Key.create("RUN_CONFIGURATION_TYPE_ID"); + private static final Key RUNNER_ID = Key.create("RUNNER_ID"); + + @NonNls protected static final String MAKE_PROJECT_ON_RUN_KEY = "makeProjectOnRun"; + + private final Project myProject; + + public CompileStepBeforeRun(@NotNull final Project project) { + myProject = project; + } + + public Key getId() { + return ID; + } + + @Override + public String getName() { + return ExecutionBundle.message("before.launch.compile.step"); + } + + @Override + public String getDescription(MakeBeforeRunTask task) { + return ExecutionBundle.message("before.launch.compile.step"); + } + + @Override + public Icon getIcon() { + return AllIcons.Actions.Compile; + } + + @Override + public Icon getTaskIcon(MakeBeforeRunTask task) { + return AllIcons.Actions.Compile; + } + + public MakeBeforeRunTask createTask(RunConfiguration runConfiguration) { + return !(runConfiguration instanceof RemoteConfiguration) && runConfiguration instanceof RunProfileWithCompileBeforeLaunchOption + ? new MakeBeforeRunTask() + : null; + } + + public boolean configureTask(RunConfiguration runConfiguration, MakeBeforeRunTask task) { + return false; + } + + @Override + public boolean canExecuteTask(RunConfiguration configuration, MakeBeforeRunTask task) { + return true; + } + + public boolean executeTask(DataContext context, final RunConfiguration configuration, final ExecutionEnvironment env, MakeBeforeRunTask task) { + if (!(configuration instanceof RunProfileWithCompileBeforeLaunchOption)) { + return true; + } + + if (configuration instanceof RunConfigurationBase && ((RunConfigurationBase)configuration).excludeCompileBeforeLaunchOption()) { + return true; + } + + final RunProfileWithCompileBeforeLaunchOption runConfiguration = (RunProfileWithCompileBeforeLaunchOption)configuration; + final Ref result = new Ref(Boolean.FALSE); + try { + + final Semaphore done = new Semaphore(); + done.down(); + final CompileStatusNotification callback = new CompileStatusNotification() { + public void finished(final boolean aborted, final int errors, final int warnings, CompileContext compileContext) { + if (errors == 0 && !aborted) { + result.set(Boolean.TRUE); + } + done.up(); + } + }; + + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + CompileScope scope; + final CompilerManager compilerManager = CompilerManager.getInstance(myProject); + if (Boolean.valueOf(System.getProperty(MAKE_PROJECT_ON_RUN_KEY, Boolean.FALSE.toString())).booleanValue()) { + // user explicitly requested whole-project make + scope = compilerManager.createProjectCompileScope(myProject); + } + else { + final Module[] modules = runConfiguration.getModules(); + if (modules.length > 0) { + for (Module module : modules) { + if (module == null) { + LOG.error("RunConfiguration should not return null modules. Configuration=" + runConfiguration.getName() + "; class=" + + runConfiguration.getClass().getName()); + } + } + scope = compilerManager.createModulesCompileScope(modules, true); + } + else { + scope = compilerManager.createProjectCompileScope(myProject); + } + } + + if (!myProject.isDisposed()) { + scope.putUserData(RUN_CONFIGURATION, configuration); + scope.putUserData(RUN_CONFIGURATION_TYPE_ID, configuration.getType().getId()); + scope.putUserData(RUNNER_ID, env.getRunnerId()); + compilerManager.make(scope, callback); + } + else { + done.up(); + } + } + }); + done.waitFor(); + } + catch (Exception e) { + return false; + } + + return result.get(); + } + + public boolean isConfigurable() { + return false; + } + + @Nullable + public static RunConfiguration getRunConfiguration(final CompileContext context) { + return getRunConfiguration(context.getCompileScope()); + } + + @Nullable + public static RunConfiguration getRunConfiguration(final CompileScope compileScope) { + return compileScope.getUserData(RUN_CONFIGURATION); + } + + public static class MakeBeforeRunTask extends BeforeRunTask { + private MakeBeforeRunTask() { + super(ID); + setEnabled(true); + } + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java b/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java index eb2317d06a54..9abea2e942c2 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java @@ -1,250 +1,250 @@ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.ExpectedTypeInfo; -import com.intellij.codeInsight.ExpectedTypesProvider; -import com.intellij.codeInsight.generation.GenerateMembersUtil; -import com.intellij.codeInsight.generation.OverrideImplementUtil; -import com.intellij.codeInsight.generation.PsiGenerationInfo; -import com.intellij.codeInsight.lookup.Lookup; -import com.intellij.codeInsight.lookup.LookupElementDecorator; -import com.intellij.codeInsight.lookup.LookupItem; -import com.intellij.codeInsight.lookup.PsiTypeLookupItem; -import com.intellij.featureStatistics.FeatureUsageTracker; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.command.CommandProcessor; -import com.intellij.openapi.command.UndoConfirmationPolicy; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.ScrollType; -import com.intellij.openapi.project.Project; -import com.intellij.psi.*; -import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.impl.source.PostprocessReformattingAspect; -import com.intellij.psi.infos.CandidateInfo; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collection; -import java.util.List; - -/** -* @author peter -*/ -public class ConstructorInsertHandler implements InsertHandler> { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.ConstructorInsertHandler"); - public static final ConstructorInsertHandler SMART_INSTANCE = new ConstructorInsertHandler(true); - public static final ConstructorInsertHandler BASIC_INSTANCE = new ConstructorInsertHandler(false); - static final OffsetKey PARAM_LIST_START = OffsetKey.create("paramListStart"); - static final OffsetKey PARAM_LIST_END = OffsetKey.create("paramListEnd"); - private final boolean mySmart; - - private ConstructorInsertHandler(boolean smart) { - mySmart = smart; - } - - @Override - public void handleInsert(InsertionContext context, LookupElementDecorator item) { - @SuppressWarnings({"unchecked"}) final LookupItem delegate = item.getDelegate(); - - PsiClass psiClass = (PsiClass)item.getObject(); - - boolean isAbstract = psiClass.hasModifierProperty(PsiModifier.ABSTRACT); - - if (Lookup.REPLACE_SELECT_CHAR == context.getCompletionChar()) { - final int plStart = context.getOffset(PARAM_LIST_START); - final int plEnd = context.getOffset(PARAM_LIST_END); - if (plStart >= 0 && plEnd >= 0) { - context.getDocument().deleteString(plStart, plEnd); - } - } - - context.commitDocument(); - - OffsetKey insideRef = context.trackOffset(context.getTailOffset(), false); - - final PsiElement position = SmartCompletionDecorator.getPosition(context, delegate); - final PsiExpression enclosing = PsiTreeUtil.getContextOfType(position, PsiExpression.class, true); - final PsiAnonymousClass anonymousClass = PsiTreeUtil.getParentOfType(position, PsiAnonymousClass.class); - final boolean inAnonymous = anonymousClass != null && anonymousClass.getParent() == enclosing; - boolean fillTypeArgs = false; - if (delegate instanceof PsiTypeLookupItem) { - fillTypeArgs = !isRawTypeExpected(context, (PsiTypeLookupItem)delegate) && - psiClass.getTypeParameters().length > 0 && - ((PsiTypeLookupItem)delegate).calcGenerics(position, context).isEmpty() && - context.getCompletionChar() != '('; - - if (context.getDocument().getTextLength() > context.getTailOffset() && - context.getDocument().getCharsSequence().charAt(context.getTailOffset()) == '<') { - PsiJavaCodeReferenceElement ref = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getTailOffset(), PsiJavaCodeReferenceElement.class, false); - if (ref != null) { - PsiReferenceParameterList parameterList = ref.getParameterList(); - if (parameterList != null && context.getTailOffset() == parameterList.getTextRange().getStartOffset()) { - context.getDocument().deleteString(parameterList.getTextRange().getStartOffset(), parameterList.getTextRange().getEndOffset()); - context.commitDocument(); - } - } - } - - delegate.handleInsert(context); - PostprocessReformattingAspect.getInstance(context.getProject()).doPostponedFormatting(context.getFile().getViewProvider()); - } - - if (item.getDelegate() instanceof JavaPsiClassReferenceElement) { - PsiTypeLookupItem.addImportForItem(context, psiClass); - } - - - insertParentheses(context, delegate, psiClass, !inAnonymous && isAbstract); - - if (inAnonymous) { - return; - } - - if (mySmart) { - FeatureUsageTracker.getInstance().triggerFeatureUsed(JavaCompletionFeatures.AFTER_NEW); - } - if (isAbstract) { - PostprocessReformattingAspect.getInstance(context.getProject()).doPostponedFormatting(context.getFile().getViewProvider()); - - final Editor editor = context.getEditor(); - final int offset = context.getTailOffset(); - editor.getDocument().insertString(offset, " {}"); - editor.getCaretModel().moveToOffset(offset + 2); - - if (fillTypeArgs && JavaCompletionUtil.promptTypeArgs(context, context.getOffset(insideRef))) return; - - context.setLaterRunnable(generateAnonymousBody(editor, context.getFile())); - } - else { - PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments(); - final PsiNewExpression newExpression = - PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiNewExpression.class, false); - if (newExpression != null) { - final PsiJavaCodeReferenceElement classReference = newExpression.getClassOrAnonymousClassReference(); - if (classReference != null) { - CodeStyleManager.getInstance(context.getProject()).reformat(classReference); - } - } - if (mySmart) { - FeatureUsageTracker.getInstance().triggerFeatureUsed(JavaCompletionFeatures.AFTER_NEW); - } - if (fillTypeArgs && JavaCompletionUtil.promptTypeArgs(context, context.getOffset(insideRef))) return; - } - } - - static boolean isRawTypeExpected(InsertionContext context, PsiTypeLookupItem delegate) { - PsiNewExpression newExpr = - PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiNewExpression.class, false); - if (newExpr != null) { - for (ExpectedTypeInfo info : ExpectedTypesProvider.getExpectedTypes(newExpr, true)) { - PsiType expected = info.getDefaultType(); - if (expected.isAssignableFrom(delegate.getPsiType())) { - if (expected instanceof PsiClassType && ((PsiClassType)expected).isRaw()) { - return true; - } - } - } - } - return false; - } - - public static boolean insertParentheses(InsertionContext context, - LookupItem delegate, - final PsiClass psiClass, - final boolean forAnonymous) { - if (context.getCompletionChar() == '[') { - return false; - } - - final PsiElement place = context.getFile().findElementAt(context.getStartOffset()); - assert place != null; - boolean hasParams = hasConstructorParameters(psiClass, place); - - JavaCompletionUtil.insertParentheses(context, delegate, false, hasParams, forAnonymous); - - return true; - } - - static boolean hasConstructorParameters(PsiClass psiClass, @NotNull PsiElement place) { - final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(place.getProject()).getResolveHelper(); - boolean hasParams = false; - for (PsiMethod constructor : psiClass.getConstructors()) { - if (!resolveHelper.isAccessible(constructor, place, null)) continue; - if (constructor.getParameterList().getParametersCount() > 0) { - hasParams = true; - break; - } - } - return hasParams; - } - - @Nullable - private static Runnable generateAnonymousBody(final Editor editor, final PsiFile file) { - final Project project = file.getProject(); - PsiDocumentManager.getInstance(project).commitAllDocuments(); - - int offset = editor.getCaretModel().getOffset(); - PsiElement element = file.findElementAt(offset); - if (element == null) return null; - - PsiElement parent = element.getParent(); - if (!(parent instanceof PsiAnonymousClass)) return null; - - return genAnonymousBodyFor((PsiAnonymousClass)parent, editor, file, project); - } - - public static Runnable genAnonymousBodyFor(PsiAnonymousClass parent, - final Editor editor, - final PsiFile file, - final Project project) { - try { - CodeStyleManager.getInstance(project).reformat(parent); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - int offset = parent.getTextRange().getEndOffset() - 1; - editor.getCaretModel().moveToOffset(offset); - editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); - editor.getSelectionModel().removeSelection(); - - return new Runnable() { - @Override - public void run(){ - CommandProcessor.getInstance().executeCommand(project, new Runnable() { - @Override - public void run() { - PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); - final PsiAnonymousClass aClass = PsiTreeUtil.findElementOfClassAtOffset(file, editor.getCaretModel().getOffset(), PsiAnonymousClass.class, false); - if (aClass == null) return; - - final Collection candidatesToImplement = OverrideImplementUtil.getMethodsToOverrideImplement(aClass, true); - boolean invokeOverride = candidatesToImplement.isEmpty(); - if (invokeOverride){ - OverrideImplementUtil.chooseAndOverrideOrImplementMethods(project, editor, aClass, false); - } - else{ - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - try{ - List methods = OverrideImplementUtil.overrideOrImplementMethodCandidates(aClass, candidatesToImplement, false); - List> prototypes = OverrideImplementUtil.convert2GenerationInfos(methods); - List> resultMembers = GenerateMembersUtil.insertMembersBeforeAnchor(aClass, null, prototypes); - resultMembers.get(0).positionCaret(editor, true); - } - catch(IncorrectOperationException ioe){ - LOG.error(ioe); - } - } - }); - } - - } - }, CompletionBundle.message("completion.smart.type.generate.anonymous.body"), null, UndoConfirmationPolicy.DEFAULT, editor.getDocument()); - } - }; - } -} +package com.intellij.codeInsight.completion; + +import com.intellij.codeInsight.ExpectedTypeInfo; +import com.intellij.codeInsight.ExpectedTypesProvider; +import com.intellij.codeInsight.generation.GenerateMembersUtil; +import com.intellij.codeInsight.generation.OverrideImplementUtil; +import com.intellij.codeInsight.generation.PsiGenerationInfo; +import com.intellij.codeInsight.lookup.Lookup; +import com.intellij.codeInsight.lookup.LookupElementDecorator; +import com.intellij.codeInsight.lookup.LookupItem; +import com.intellij.codeInsight.lookup.PsiTypeLookupItem; +import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.command.UndoConfirmationPolicy; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.impl.source.PostprocessReformattingAspect; +import com.intellij.psi.infos.CandidateInfo; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; + +/** +* @author peter +*/ +public class ConstructorInsertHandler implements InsertHandler> { + private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.ConstructorInsertHandler"); + public static final ConstructorInsertHandler SMART_INSTANCE = new ConstructorInsertHandler(true); + public static final ConstructorInsertHandler BASIC_INSTANCE = new ConstructorInsertHandler(false); + static final OffsetKey PARAM_LIST_START = OffsetKey.create("paramListStart"); + static final OffsetKey PARAM_LIST_END = OffsetKey.create("paramListEnd"); + private final boolean mySmart; + + private ConstructorInsertHandler(boolean smart) { + mySmart = smart; + } + + @Override + public void handleInsert(InsertionContext context, LookupElementDecorator item) { + @SuppressWarnings({"unchecked"}) final LookupItem delegate = item.getDelegate(); + + PsiClass psiClass = (PsiClass)item.getObject(); + + boolean isAbstract = psiClass.hasModifierProperty(PsiModifier.ABSTRACT); + + if (Lookup.REPLACE_SELECT_CHAR == context.getCompletionChar()) { + final int plStart = context.getOffset(PARAM_LIST_START); + final int plEnd = context.getOffset(PARAM_LIST_END); + if (plStart >= 0 && plEnd >= 0) { + context.getDocument().deleteString(plStart, plEnd); + } + } + + context.commitDocument(); + + OffsetKey insideRef = context.trackOffset(context.getTailOffset(), false); + + final PsiElement position = SmartCompletionDecorator.getPosition(context, delegate); + final PsiExpression enclosing = PsiTreeUtil.getContextOfType(position, PsiExpression.class, true); + final PsiAnonymousClass anonymousClass = PsiTreeUtil.getParentOfType(position, PsiAnonymousClass.class); + final boolean inAnonymous = anonymousClass != null && anonymousClass.getParent() == enclosing; + boolean fillTypeArgs = false; + if (delegate instanceof PsiTypeLookupItem) { + fillTypeArgs = !isRawTypeExpected(context, (PsiTypeLookupItem)delegate) && + psiClass.getTypeParameters().length > 0 && + ((PsiTypeLookupItem)delegate).calcGenerics(position, context).isEmpty() && + context.getCompletionChar() != '('; + + if (context.getDocument().getTextLength() > context.getTailOffset() && + context.getDocument().getCharsSequence().charAt(context.getTailOffset()) == '<') { + PsiJavaCodeReferenceElement ref = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getTailOffset(), PsiJavaCodeReferenceElement.class, false); + if (ref != null) { + PsiReferenceParameterList parameterList = ref.getParameterList(); + if (parameterList != null && context.getTailOffset() == parameterList.getTextRange().getStartOffset()) { + context.getDocument().deleteString(parameterList.getTextRange().getStartOffset(), parameterList.getTextRange().getEndOffset()); + context.commitDocument(); + } + } + } + + delegate.handleInsert(context); + PostprocessReformattingAspect.getInstance(context.getProject()).doPostponedFormatting(context.getFile().getViewProvider()); + } + + if (item.getDelegate() instanceof JavaPsiClassReferenceElement) { + PsiTypeLookupItem.addImportForItem(context, psiClass); + } + + + insertParentheses(context, delegate, psiClass, !inAnonymous && isAbstract); + + if (inAnonymous) { + return; + } + + if (mySmart) { + FeatureUsageTracker.getInstance().triggerFeatureUsed(JavaCompletionFeatures.AFTER_NEW); + } + if (isAbstract) { + PostprocessReformattingAspect.getInstance(context.getProject()).doPostponedFormatting(context.getFile().getViewProvider()); + + final Editor editor = context.getEditor(); + final int offset = context.getTailOffset(); + editor.getDocument().insertString(offset, " {}"); + editor.getCaretModel().moveToOffset(offset + 2); + + if (fillTypeArgs && JavaCompletionUtil.promptTypeArgs(context, context.getOffset(insideRef))) return; + + context.setLaterRunnable(generateAnonymousBody(editor, context.getFile())); + } + else { + PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments(); + final PsiNewExpression newExpression = + PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiNewExpression.class, false); + if (newExpression != null) { + final PsiJavaCodeReferenceElement classReference = newExpression.getClassOrAnonymousClassReference(); + if (classReference != null) { + CodeStyleManager.getInstance(context.getProject()).reformat(classReference); + } + } + if (mySmart) { + FeatureUsageTracker.getInstance().triggerFeatureUsed(JavaCompletionFeatures.AFTER_NEW); + } + if (fillTypeArgs && JavaCompletionUtil.promptTypeArgs(context, context.getOffset(insideRef))) return; + } + } + + static boolean isRawTypeExpected(InsertionContext context, PsiTypeLookupItem delegate) { + PsiNewExpression newExpr = + PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiNewExpression.class, false); + if (newExpr != null) { + for (ExpectedTypeInfo info : ExpectedTypesProvider.getExpectedTypes(newExpr, true)) { + PsiType expected = info.getDefaultType(); + if (expected.isAssignableFrom(delegate.getPsiType())) { + if (expected instanceof PsiClassType && ((PsiClassType)expected).isRaw()) { + return true; + } + } + } + } + return false; + } + + public static boolean insertParentheses(InsertionContext context, + LookupItem delegate, + final PsiClass psiClass, + final boolean forAnonymous) { + if (context.getCompletionChar() == '[') { + return false; + } + + final PsiElement place = context.getFile().findElementAt(context.getStartOffset()); + assert place != null; + boolean hasParams = hasConstructorParameters(psiClass, place); + + JavaCompletionUtil.insertParentheses(context, delegate, false, hasParams, forAnonymous); + + return true; + } + + static boolean hasConstructorParameters(PsiClass psiClass, @NotNull PsiElement place) { + final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(place.getProject()).getResolveHelper(); + boolean hasParams = false; + for (PsiMethod constructor : psiClass.getConstructors()) { + if (!resolveHelper.isAccessible(constructor, place, null)) continue; + if (constructor.getParameterList().getParametersCount() > 0) { + hasParams = true; + break; + } + } + return hasParams; + } + + @Nullable + private static Runnable generateAnonymousBody(final Editor editor, final PsiFile file) { + final Project project = file.getProject(); + PsiDocumentManager.getInstance(project).commitAllDocuments(); + + int offset = editor.getCaretModel().getOffset(); + PsiElement element = file.findElementAt(offset); + if (element == null) return null; + + PsiElement parent = element.getParent(); + if (!(parent instanceof PsiAnonymousClass)) return null; + + return genAnonymousBodyFor((PsiAnonymousClass)parent, editor, file, project); + } + + public static Runnable genAnonymousBodyFor(PsiAnonymousClass parent, + final Editor editor, + final PsiFile file, + final Project project) { + try { + CodeStyleManager.getInstance(project).reformat(parent); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + int offset = parent.getTextRange().getEndOffset() - 1; + editor.getCaretModel().moveToOffset(offset); + editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); + editor.getSelectionModel().removeSelection(); + + return new Runnable() { + @Override + public void run(){ + CommandProcessor.getInstance().executeCommand(project, new Runnable() { + @Override + public void run() { + PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); + final PsiAnonymousClass aClass = PsiTreeUtil.findElementOfClassAtOffset(file, editor.getCaretModel().getOffset(), PsiAnonymousClass.class, false); + if (aClass == null) return; + + final Collection candidatesToImplement = OverrideImplementUtil.getMethodsToOverrideImplement(aClass, true); + boolean invokeOverride = candidatesToImplement.isEmpty(); + if (invokeOverride){ + OverrideImplementUtil.chooseAndOverrideOrImplementMethods(project, editor, aClass, false); + } + else{ + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + try{ + List methods = OverrideImplementUtil.overrideOrImplementMethodCandidates(aClass, candidatesToImplement, false); + List> prototypes = OverrideImplementUtil.convert2GenerationInfos(methods); + List> resultMembers = GenerateMembersUtil.insertMembersBeforeAnchor(aClass, null, prototypes); + resultMembers.get(0).positionCaret(editor, true); + } + catch(IncorrectOperationException ioe){ + LOG.error(ioe); + } + } + }); + } + + } + }, CompletionBundle.message("completion.smart.type.generate.anonymous.body"), null, UndoConfirmationPolicy.DEFAULT, editor.getDocument()); + } + }; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java index 99d3cfea274f..d1166c749091 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java @@ -1,183 +1,183 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.ExpectedTypeInfo; -import com.intellij.codeInsight.ExpectedTypesProvider; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.lang.LangBundle; -import com.intellij.lang.java.JavaLanguage; -import com.intellij.openapi.actionSystem.IdeActions; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileTypes.impl.CustomSyntaxTableFileType; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.patterns.PsiJavaElementPattern; -import com.intellij.psi.*; -import com.intellij.psi.filters.ClassFilter; -import com.intellij.psi.filters.ElementFilter; -import com.intellij.psi.filters.TrueFilter; -import com.intellij.psi.filters.element.ExcludeDeclaredFilter; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.util.Consumer; -import com.intellij.util.SmartList; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -import static com.intellij.patterns.PsiJavaPatterns.psiElement; - -/** - * @author peter - */ -public class JavaClassNameCompletionContributor extends CompletionContributor { - public static final PsiJavaElementPattern.Capture AFTER_NEW = psiElement().afterLeaf(PsiKeyword.NEW); - private static final PsiJavaElementPattern.Capture IN_TYPE_PARAMETER = - psiElement().afterLeaf(PsiKeyword.EXTENDS, PsiKeyword.SUPER, "&").withParent( - psiElement(PsiReferenceList.class).withParent(PsiTypeParameter.class)); - - @Override - public void fillCompletionVariants(CompletionParameters parameters, final CompletionResultSet _result) { - if (parameters.getCompletionType() == CompletionType.CLASS_NAME || - parameters.isExtendedCompletion() && mayContainClassName(parameters)) { - addAllClasses(parameters, _result); - } - } - - static void addAllClasses(CompletionParameters parameters, final CompletionResultSet _result) { - CompletionResultSet result = _result.withPrefixMatcher(CompletionUtil.findReferenceOrAlphanumericPrefix(parameters)); - addAllClasses(parameters, parameters.getInvocationCount() <= 1, result.getPrefixMatcher(), _result); - } - - private static boolean mayContainClassName(CompletionParameters parameters) { - PsiElement position = parameters.getPosition(); - PsiFile file = position.getContainingFile(); - if (file instanceof PsiPlainTextFile || file.getFileType() instanceof CustomSyntaxTableFileType) { - return true; - } - if (SkipAutopopupInStrings.isInStringLiteral(position)) { - return true; - } - if (PsiTreeUtil.getParentOfType(position, PsiComment.class, false) != null) { - return true; - } - return false; - } - - public static void addAllClasses(CompletionParameters parameters, - final boolean filterByScope, - @NotNull final PrefixMatcher matcher, - @NotNull final Consumer consumer) { - final PsiElement insertedElement = parameters.getPosition(); - - final ElementFilter filter = - IN_TYPE_PARAMETER.accepts(insertedElement) ? new ExcludeDeclaredFilter(new ClassFilter(PsiTypeParameter.class)) : TrueFilter.INSTANCE; - - final boolean inJavaContext = parameters.getPosition() instanceof PsiIdentifier; - final boolean afterNew = AFTER_NEW.accepts(insertedElement); - if (afterNew) { - final PsiExpression expr = PsiTreeUtil.getContextOfType(insertedElement, PsiExpression.class, true); - for (final ExpectedTypeInfo info : ExpectedTypesProvider.getExpectedTypes(expr, true)) { - final PsiType type = info.getType(); - final PsiClass psiClass = PsiUtil.resolveClassInType(type); - if (psiClass != null) { - consumer.consume(createClassLookupItem(psiClass, inJavaContext)); - } - final PsiType defaultType = info.getDefaultType(); - if (!defaultType.equals(type)) { - final PsiClass defClass = PsiUtil.resolveClassInType(defaultType); - if (defClass != null) { - consumer.consume(createClassLookupItem(defClass, true)); - } - } - } - } - - final boolean pkgContext = JavaCompletionUtil.inSomePackage(insertedElement); - AllClassesGetter.processJavaClasses(parameters, matcher, filterByScope, new Consumer() { - @Override - public void consume(PsiClass psiClass) { - if (filter.isAcceptable(psiClass, insertedElement)) { - if (!inJavaContext) { - consumer.consume(AllClassesGetter.createLookupItem(psiClass, AllClassesGetter.TRY_SHORTENING)); - } else { - for (JavaPsiClassReferenceElement element : createClassLookupItems(psiClass, afterNew, - JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER, new Condition() { - @Override - public boolean value(PsiClass psiClass) { - return filter.isAcceptable(psiClass, insertedElement) && - AllClassesGetter.isAcceptableInContext(insertedElement, psiClass, filterByScope, pkgContext); - } - })) { - consumer.consume(element); - } - } - } - } - }); - } - - public static JavaPsiClassReferenceElement createClassLookupItem(final PsiClass psiClass, final boolean inJavaContext) { - return AllClassesGetter.createLookupItem(psiClass, inJavaContext ? JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER - : AllClassesGetter.TRY_SHORTENING); - } - - public static List createClassLookupItems(final PsiClass psiClass, - boolean withInners, - InsertHandler insertHandler, - Condition condition) { - List result = new SmartList(); - if (condition.value(psiClass)) { - result.add(AllClassesGetter.createLookupItem(psiClass, insertHandler)); - } - String name = psiClass.getName(); - if (withInners && name != null) { - for (PsiClass inner : psiClass.getInnerClasses()) { - if (inner.hasModifierProperty(PsiModifier.STATIC)) { - for (JavaPsiClassReferenceElement lookupInner : createClassLookupItems(inner, withInners, insertHandler, condition)) { - String forced = lookupInner.getForcedPresentableName(); - lookupInner.setForcedPresentableName(name + "." + (forced != null ? forced : inner.getName())); - result.add(lookupInner); - } - } - } - } - return result; - } - - - - @Override - public String handleEmptyLookup(@NotNull final CompletionParameters parameters, final Editor editor) { - if (!(parameters.getOriginalFile() instanceof PsiJavaFile)) return null; - - if (shouldShowSecondSmartCompletionHint(parameters)) { - return LangBundle.message("completion.no.suggestions") + - "; " + - StringUtil.decapitalize( - CompletionBundle.message("completion.class.name.hint.2", getActionShortcut(IdeActions.ACTION_CODE_COMPLETION))); - } - - return null; - } - - private static boolean shouldShowSecondSmartCompletionHint(final CompletionParameters parameters) { - return parameters.getCompletionType() == CompletionType.BASIC && - parameters.getInvocationCount() == 2 && - parameters.getOriginalFile().getLanguage().isKindOf(JavaLanguage.INSTANCE); - } -} +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.completion; + +import com.intellij.codeInsight.ExpectedTypeInfo; +import com.intellij.codeInsight.ExpectedTypesProvider; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.lang.LangBundle; +import com.intellij.lang.java.JavaLanguage; +import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.fileTypes.impl.CustomSyntaxTableFileType; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.patterns.PsiJavaElementPattern; +import com.intellij.psi.*; +import com.intellij.psi.filters.ClassFilter; +import com.intellij.psi.filters.ElementFilter; +import com.intellij.psi.filters.TrueFilter; +import com.intellij.psi.filters.element.ExcludeDeclaredFilter; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import com.intellij.util.Consumer; +import com.intellij.util.SmartList; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +import static com.intellij.patterns.PsiJavaPatterns.psiElement; + +/** + * @author peter + */ +public class JavaClassNameCompletionContributor extends CompletionContributor { + public static final PsiJavaElementPattern.Capture AFTER_NEW = psiElement().afterLeaf(PsiKeyword.NEW); + private static final PsiJavaElementPattern.Capture IN_TYPE_PARAMETER = + psiElement().afterLeaf(PsiKeyword.EXTENDS, PsiKeyword.SUPER, "&").withParent( + psiElement(PsiReferenceList.class).withParent(PsiTypeParameter.class)); + + @Override + public void fillCompletionVariants(CompletionParameters parameters, final CompletionResultSet _result) { + if (parameters.getCompletionType() == CompletionType.CLASS_NAME || + parameters.isExtendedCompletion() && mayContainClassName(parameters)) { + addAllClasses(parameters, _result); + } + } + + static void addAllClasses(CompletionParameters parameters, final CompletionResultSet _result) { + CompletionResultSet result = _result.withPrefixMatcher(CompletionUtil.findReferenceOrAlphanumericPrefix(parameters)); + addAllClasses(parameters, parameters.getInvocationCount() <= 1, result.getPrefixMatcher(), _result); + } + + private static boolean mayContainClassName(CompletionParameters parameters) { + PsiElement position = parameters.getPosition(); + PsiFile file = position.getContainingFile(); + if (file instanceof PsiPlainTextFile || file.getFileType() instanceof CustomSyntaxTableFileType) { + return true; + } + if (SkipAutopopupInStrings.isInStringLiteral(position)) { + return true; + } + if (PsiTreeUtil.getParentOfType(position, PsiComment.class, false) != null) { + return true; + } + return false; + } + + public static void addAllClasses(CompletionParameters parameters, + final boolean filterByScope, + @NotNull final PrefixMatcher matcher, + @NotNull final Consumer consumer) { + final PsiElement insertedElement = parameters.getPosition(); + + final ElementFilter filter = + IN_TYPE_PARAMETER.accepts(insertedElement) ? new ExcludeDeclaredFilter(new ClassFilter(PsiTypeParameter.class)) : TrueFilter.INSTANCE; + + final boolean inJavaContext = parameters.getPosition() instanceof PsiIdentifier; + final boolean afterNew = AFTER_NEW.accepts(insertedElement); + if (afterNew) { + final PsiExpression expr = PsiTreeUtil.getContextOfType(insertedElement, PsiExpression.class, true); + for (final ExpectedTypeInfo info : ExpectedTypesProvider.getExpectedTypes(expr, true)) { + final PsiType type = info.getType(); + final PsiClass psiClass = PsiUtil.resolveClassInType(type); + if (psiClass != null) { + consumer.consume(createClassLookupItem(psiClass, inJavaContext)); + } + final PsiType defaultType = info.getDefaultType(); + if (!defaultType.equals(type)) { + final PsiClass defClass = PsiUtil.resolveClassInType(defaultType); + if (defClass != null) { + consumer.consume(createClassLookupItem(defClass, true)); + } + } + } + } + + final boolean pkgContext = JavaCompletionUtil.inSomePackage(insertedElement); + AllClassesGetter.processJavaClasses(parameters, matcher, filterByScope, new Consumer() { + @Override + public void consume(PsiClass psiClass) { + if (filter.isAcceptable(psiClass, insertedElement)) { + if (!inJavaContext) { + consumer.consume(AllClassesGetter.createLookupItem(psiClass, AllClassesGetter.TRY_SHORTENING)); + } else { + for (JavaPsiClassReferenceElement element : createClassLookupItems(psiClass, afterNew, + JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER, new Condition() { + @Override + public boolean value(PsiClass psiClass) { + return filter.isAcceptable(psiClass, insertedElement) && + AllClassesGetter.isAcceptableInContext(insertedElement, psiClass, filterByScope, pkgContext); + } + })) { + consumer.consume(element); + } + } + } + } + }); + } + + public static JavaPsiClassReferenceElement createClassLookupItem(final PsiClass psiClass, final boolean inJavaContext) { + return AllClassesGetter.createLookupItem(psiClass, inJavaContext ? JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER + : AllClassesGetter.TRY_SHORTENING); + } + + public static List createClassLookupItems(final PsiClass psiClass, + boolean withInners, + InsertHandler insertHandler, + Condition condition) { + List result = new SmartList(); + if (condition.value(psiClass)) { + result.add(AllClassesGetter.createLookupItem(psiClass, insertHandler)); + } + String name = psiClass.getName(); + if (withInners && name != null) { + for (PsiClass inner : psiClass.getInnerClasses()) { + if (inner.hasModifierProperty(PsiModifier.STATIC)) { + for (JavaPsiClassReferenceElement lookupInner : createClassLookupItems(inner, withInners, insertHandler, condition)) { + String forced = lookupInner.getForcedPresentableName(); + lookupInner.setForcedPresentableName(name + "." + (forced != null ? forced : inner.getName())); + result.add(lookupInner); + } + } + } + } + return result; + } + + + + @Override + public String handleEmptyLookup(@NotNull final CompletionParameters parameters, final Editor editor) { + if (!(parameters.getOriginalFile() instanceof PsiJavaFile)) return null; + + if (shouldShowSecondSmartCompletionHint(parameters)) { + return LangBundle.message("completion.no.suggestions") + + "; " + + StringUtil.decapitalize( + CompletionBundle.message("completion.class.name.hint.2", getActionShortcut(IdeActions.ACTION_CODE_COMPLETION))); + } + + return null; + } + + private static boolean shouldShowSecondSmartCompletionHint(final CompletionParameters parameters) { + return parameters.getCompletionType() == CompletionType.BASIC && + parameters.getInvocationCount() == 2 && + parameters.getOriginalFile().getLanguage().isKindOf(JavaLanguage.INSTANCE); + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionFeatures.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionFeatures.java index 1002b5854116..ac5cfe25fe3a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionFeatures.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionFeatures.java @@ -1,30 +1,30 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import org.jetbrains.annotations.NonNls; - -/** - * @author peter - */ -public interface JavaCompletionFeatures { - @NonNls String SECOND_SMART_COMPLETION_CHAIN = "editing.completion.second.smarttype.chain"; - @NonNls String SECOND_SMART_COMPLETION_TOAR = "editing.completion.second.smarttype.toar"; - @NonNls String SECOND_SMART_COMPLETION_ASLIST = "editing.completion.second.smarttype.aslist"; - @NonNls String SECOND_SMART_COMPLETION_ARRAY_MEMBER = "editing.completion.second.smarttype.array.member"; - @NonNls String GLOBAL_MEMBER_NAME = "editing.completion.global.member.name"; - @NonNls String AFTER_NEW = "editing.completion.smarttype.afternew"; -} +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.completion; + +import org.jetbrains.annotations.NonNls; + +/** + * @author peter + */ +public interface JavaCompletionFeatures { + @NonNls String SECOND_SMART_COMPLETION_CHAIN = "editing.completion.second.smarttype.chain"; + @NonNls String SECOND_SMART_COMPLETION_TOAR = "editing.completion.second.smarttype.toar"; + @NonNls String SECOND_SMART_COMPLETION_ASLIST = "editing.completion.second.smarttype.aslist"; + @NonNls String SECOND_SMART_COMPLETION_ARRAY_MEMBER = "editing.completion.second.smarttype.array.member"; + @NonNls String GLOBAL_MEMBER_NAME = "editing.completion.global.member.name"; + @NonNls String AFTER_NEW = "editing.completion.smarttype.afternew"; +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaStaticMemberProcessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaStaticMemberProcessor.java index 345e05963400..432011d72b70 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaStaticMemberProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaStaticMemberProcessor.java @@ -1,90 +1,90 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.lookup.AutoCompletionPolicy; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.VariableLookupItem; -import com.intellij.featureStatistics.FeatureUsageTracker; -import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -/** -* @author peter -*/ -public class JavaStaticMemberProcessor extends StaticMemberProcessor { - private final PsiElement myOriginalPosition; - - public JavaStaticMemberProcessor(CompletionParameters parameters) { - super(parameters.getPosition()); - myOriginalPosition = parameters.getOriginalPosition(); - - final PsiFile file = parameters.getPosition().getContainingFile(); - if (file instanceof PsiJavaFile) { - final PsiImportList importList = ((PsiJavaFile)file).getImportList(); - if (importList != null) { - for (PsiImportStaticStatement statement : importList.getImportStaticStatements()) { - importMembersOf(statement.resolveTargetClass()); - } - } - } - } - - @NotNull - @Override - protected LookupElement createLookupElement(@NotNull PsiMember member, @NotNull final PsiClass containingClass, boolean shouldImport) { - shouldImport |= myOriginalPosition != null && PsiTreeUtil.isAncestor(containingClass, myOriginalPosition, false); - - if (member instanceof PsiMethod) { - return AutoCompletionPolicy.NEVER_AUTOCOMPLETE.applyPolicy(new GlobalMethodCallElement((PsiMethod)member, shouldImport, false)); - } - return AutoCompletionPolicy.NEVER_AUTOCOMPLETE.applyPolicy(new VariableLookupItem((PsiField)member, shouldImport) { - @Override - public void handleInsert(InsertionContext context) { - FeatureUsageTracker.getInstance().triggerFeatureUsed(JavaCompletionFeatures.GLOBAL_MEMBER_NAME); - - super.handleInsert(context); - } - }); - } - - @Override - protected LookupElement createLookupElement(@NotNull List overloads, - @NotNull PsiClass containingClass, - boolean shouldImport) { - shouldImport |= myOriginalPosition != null && PsiTreeUtil.isAncestor(containingClass, myOriginalPosition, false); - - final JavaMethodCallElement element = new GlobalMethodCallElement(overloads.get(0), shouldImport, true); - element.putUserData(JavaCompletionUtil.ALL_METHODS_ATTRIBUTE, overloads); - return element; - } - - private static class GlobalMethodCallElement extends JavaMethodCallElement { - public GlobalMethodCallElement(PsiMethod member, boolean shouldImport, boolean mergedOverloads) { - super(member, shouldImport, mergedOverloads); - } - - @Override - public void handleInsert(InsertionContext context) { - FeatureUsageTracker.getInstance().triggerFeatureUsed(JavaCompletionFeatures.GLOBAL_MEMBER_NAME); - - super.handleInsert(context); - } - } -} +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.completion; + +import com.intellij.codeInsight.lookup.AutoCompletionPolicy; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.VariableLookupItem; +import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** +* @author peter +*/ +public class JavaStaticMemberProcessor extends StaticMemberProcessor { + private final PsiElement myOriginalPosition; + + public JavaStaticMemberProcessor(CompletionParameters parameters) { + super(parameters.getPosition()); + myOriginalPosition = parameters.getOriginalPosition(); + + final PsiFile file = parameters.getPosition().getContainingFile(); + if (file instanceof PsiJavaFile) { + final PsiImportList importList = ((PsiJavaFile)file).getImportList(); + if (importList != null) { + for (PsiImportStaticStatement statement : importList.getImportStaticStatements()) { + importMembersOf(statement.resolveTargetClass()); + } + } + } + } + + @NotNull + @Override + protected LookupElement createLookupElement(@NotNull PsiMember member, @NotNull final PsiClass containingClass, boolean shouldImport) { + shouldImport |= myOriginalPosition != null && PsiTreeUtil.isAncestor(containingClass, myOriginalPosition, false); + + if (member instanceof PsiMethod) { + return AutoCompletionPolicy.NEVER_AUTOCOMPLETE.applyPolicy(new GlobalMethodCallElement((PsiMethod)member, shouldImport, false)); + } + return AutoCompletionPolicy.NEVER_AUTOCOMPLETE.applyPolicy(new VariableLookupItem((PsiField)member, shouldImport) { + @Override + public void handleInsert(InsertionContext context) { + FeatureUsageTracker.getInstance().triggerFeatureUsed(JavaCompletionFeatures.GLOBAL_MEMBER_NAME); + + super.handleInsert(context); + } + }); + } + + @Override + protected LookupElement createLookupElement(@NotNull List overloads, + @NotNull PsiClass containingClass, + boolean shouldImport) { + shouldImport |= myOriginalPosition != null && PsiTreeUtil.isAncestor(containingClass, myOriginalPosition, false); + + final JavaMethodCallElement element = new GlobalMethodCallElement(overloads.get(0), shouldImport, true); + element.putUserData(JavaCompletionUtil.ALL_METHODS_ATTRIBUTE, overloads); + return element; + } + + private static class GlobalMethodCallElement extends JavaMethodCallElement { + public GlobalMethodCallElement(PsiMethod member, boolean shouldImport, boolean mergedOverloads) { + super(member, shouldImport, mergedOverloads); + } + + @Override + public void handleInsert(InsertionContext context) { + FeatureUsageTracker.getInstance().triggerFeatureUsed(JavaCompletionFeatures.GLOBAL_MEMBER_NAME); + + super.handleInsert(context); + } + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DefaultQuickFixProvider.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DefaultQuickFixProvider.java index 87db50fec91c..71b3176e7a29 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DefaultQuickFixProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DefaultQuickFixProvider.java @@ -1,129 +1,129 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.daemon.impl.quickfix; - -import com.intellij.codeInsight.daemon.QuickFixActionRegistrar; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightMethodUtil; -import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.codeInsight.intention.impl.PriorityIntentionActionWrapper; -import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider; -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.*; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.codeStyle.VariableKind; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import org.jetbrains.annotations.NotNull; - -import java.util.HashMap; -import java.util.Map; - -public class DefaultQuickFixProvider extends UnresolvedReferenceQuickFixProvider { - @Override - public void registerFixes(PsiJavaCodeReferenceElement ref, QuickFixActionRegistrar registrar) { - registrar.register(new ImportClassFix(ref)); - registrar.register(SetupJDKFix.getInstance()); - OrderEntryFix.registerFixes(registrar, ref); - MoveClassToModuleFix.registerFixes(registrar, ref); - - if (ref instanceof PsiReferenceExpression) { - TextRange fixRange = HighlightMethodUtil.getFixRange(ref); - PsiReferenceExpression refExpr = (PsiReferenceExpression)ref; - - registrar.register(fixRange, new CreateEnumConstantFromUsageFix(refExpr), null); - registrar.register(new RenameWrongRefFix(refExpr)); - - if (!ref.isQualified()) { - registrar.register(fixRange, new BringVariableIntoScopeFix(refExpr), null); - } - - registerPriorityActions(registrar,fixRange,refExpr); - } - - registrar.register(new CreateClassFromUsageFix(ref, CreateClassKind.INTERFACE)); - if (PsiUtil.isLanguageLevel5OrHigher(ref)) { - registrar.register(new CreateClassFromUsageFix(ref, CreateClassKind.ENUM)); - registrar.register(new CreateClassFromUsageFix(ref, CreateClassKind.ANNOTATION)); - } - PsiElement parent = PsiTreeUtil.getParentOfType(ref, PsiNewExpression.class, PsiMethod.class); - final PsiExpressionList expressionList = PsiTreeUtil.getParentOfType(ref, PsiExpressionList.class); - if (parent instanceof PsiNewExpression && !(ref.getParent() instanceof PsiTypeElement) && (expressionList == null || !PsiTreeUtil.isAncestor(parent, expressionList, false))) { - registrar.register(new CreateClassFromNewFix((PsiNewExpression)parent)); - registrar.register(new CreateInnerClassFromNewFix((PsiNewExpression)parent)); - } - else { - registrar.register(new CreateClassFromUsageFix(ref, CreateClassKind.CLASS)); - registrar.register(new CreateInnerClassFromUsageFix(ref, CreateClassKind.CLASS)); - } - } - - private static void registerPriorityActions(@NotNull final QuickFixActionRegistrar registrar, - @NotNull final TextRange fixRange, - @NotNull final PsiReferenceExpression refExpr) { - final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(refExpr.getProject()); - - final Map map = new HashMap() { - { - put(VariableKind.FIELD, new CreateFieldFromUsageFix(refExpr)); - put(VariableKind.STATIC_FINAL_FIELD, new CreateConstantFieldFromUsageFix(refExpr)); - if (!refExpr.isQualified()) { - put(VariableKind.LOCAL_VARIABLE, new CreateLocalFromUsageFix(refExpr)); - put(VariableKind.PARAMETER, new CreateParameterFromUsageFix(refExpr)); - } - } - }; - - final VariableKind kind = getKind(styleManager, refExpr); - if (map.containsKey(kind)){ - map.put(kind, PriorityIntentionActionWrapper.highPriority(map.get(kind))); - } - - for (IntentionAction action : map.values()){ - registrar.register(fixRange, action, null); - } - } - - @NotNull - private static VariableKind getKind(@NotNull JavaCodeStyleManager styleManager, - @NotNull PsiReferenceExpression refExpr) { - final String reference = refExpr.getText(); - - if (reference.toUpperCase().equals(reference)){ - return VariableKind.STATIC_FINAL_FIELD; - } - - for (VariableKind kind : VariableKind.values()) { - final String prefix = styleManager.getPrefixByVariableKind(kind); - final String suffix = styleManager.getSuffixByVariableKind(kind); - - if (prefix.isEmpty() && suffix.isEmpty()) { - continue; - } - - if (reference.startsWith(prefix) && reference.endsWith(suffix)) { - return kind; - } - } - - return VariableKind.LOCAL_VARIABLE; - } - - @Override - @NotNull - public Class getReferenceClass() { - return PsiJavaCodeReferenceElement.class; - } +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.daemon.impl.quickfix; + +import com.intellij.codeInsight.daemon.QuickFixActionRegistrar; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightMethodUtil; +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInsight.intention.impl.PriorityIntentionActionWrapper; +import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.VariableKind; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; + +public class DefaultQuickFixProvider extends UnresolvedReferenceQuickFixProvider { + @Override + public void registerFixes(PsiJavaCodeReferenceElement ref, QuickFixActionRegistrar registrar) { + registrar.register(new ImportClassFix(ref)); + registrar.register(SetupJDKFix.getInstance()); + OrderEntryFix.registerFixes(registrar, ref); + MoveClassToModuleFix.registerFixes(registrar, ref); + + if (ref instanceof PsiReferenceExpression) { + TextRange fixRange = HighlightMethodUtil.getFixRange(ref); + PsiReferenceExpression refExpr = (PsiReferenceExpression)ref; + + registrar.register(fixRange, new CreateEnumConstantFromUsageFix(refExpr), null); + registrar.register(new RenameWrongRefFix(refExpr)); + + if (!ref.isQualified()) { + registrar.register(fixRange, new BringVariableIntoScopeFix(refExpr), null); + } + + registerPriorityActions(registrar,fixRange,refExpr); + } + + registrar.register(new CreateClassFromUsageFix(ref, CreateClassKind.INTERFACE)); + if (PsiUtil.isLanguageLevel5OrHigher(ref)) { + registrar.register(new CreateClassFromUsageFix(ref, CreateClassKind.ENUM)); + registrar.register(new CreateClassFromUsageFix(ref, CreateClassKind.ANNOTATION)); + } + PsiElement parent = PsiTreeUtil.getParentOfType(ref, PsiNewExpression.class, PsiMethod.class); + final PsiExpressionList expressionList = PsiTreeUtil.getParentOfType(ref, PsiExpressionList.class); + if (parent instanceof PsiNewExpression && !(ref.getParent() instanceof PsiTypeElement) && (expressionList == null || !PsiTreeUtil.isAncestor(parent, expressionList, false))) { + registrar.register(new CreateClassFromNewFix((PsiNewExpression)parent)); + registrar.register(new CreateInnerClassFromNewFix((PsiNewExpression)parent)); + } + else { + registrar.register(new CreateClassFromUsageFix(ref, CreateClassKind.CLASS)); + registrar.register(new CreateInnerClassFromUsageFix(ref, CreateClassKind.CLASS)); + } + } + + private static void registerPriorityActions(@NotNull final QuickFixActionRegistrar registrar, + @NotNull final TextRange fixRange, + @NotNull final PsiReferenceExpression refExpr) { + final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(refExpr.getProject()); + + final Map map = new HashMap() { + { + put(VariableKind.FIELD, new CreateFieldFromUsageFix(refExpr)); + put(VariableKind.STATIC_FINAL_FIELD, new CreateConstantFieldFromUsageFix(refExpr)); + if (!refExpr.isQualified()) { + put(VariableKind.LOCAL_VARIABLE, new CreateLocalFromUsageFix(refExpr)); + put(VariableKind.PARAMETER, new CreateParameterFromUsageFix(refExpr)); + } + } + }; + + final VariableKind kind = getKind(styleManager, refExpr); + if (map.containsKey(kind)){ + map.put(kind, PriorityIntentionActionWrapper.highPriority(map.get(kind))); + } + + for (IntentionAction action : map.values()){ + registrar.register(fixRange, action, null); + } + } + + @NotNull + private static VariableKind getKind(@NotNull JavaCodeStyleManager styleManager, + @NotNull PsiReferenceExpression refExpr) { + final String reference = refExpr.getText(); + + if (reference.toUpperCase().equals(reference)){ + return VariableKind.STATIC_FINAL_FIELD; + } + + for (VariableKind kind : VariableKind.values()) { + final String prefix = styleManager.getPrefixByVariableKind(kind); + final String suffix = styleManager.getSuffixByVariableKind(kind); + + if (prefix.isEmpty() && suffix.isEmpty()) { + continue; + } + + if (reference.startsWith(prefix) && reference.endsWith(suffix)) { + return kind; + } + } + + return VariableKind.LOCAL_VARIABLE; + } + + @Override + @NotNull + public Class getReferenceClass() { + return PsiJavaCodeReferenceElement.class; + } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/BreakStringOnLineBreaksIntentionAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/BreakStringOnLineBreaksIntentionAction.java index 90e9453db472..8dc97d1c0c15 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/BreakStringOnLineBreaksIntentionAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/BreakStringOnLineBreaksIntentionAction.java @@ -1,109 +1,109 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.intention.impl; - -import com.intellij.codeInsight.CodeInsightBundle; -import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.*; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.NotNull; - -/** - * @author Danila Ponomarenko - */ -public class BreakStringOnLineBreaksIntentionAction extends PsiElementBaseIntentionAction { - @Override - public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { - if (!(element instanceof PsiJavaToken)) { - return false; - } - - final PsiJavaToken token = (PsiJavaToken)element; - - if (token.getTokenType() != JavaTokenType.STRING_LITERAL) { - return false; - } - - final String text = token.getText(); - if (text == null) { - return false; - } - - final int indexOfSlashN = text.indexOf("\\n"); - if (indexOfSlashN == -1 || Comparing.equal(text.substring(indexOfSlashN, text.length()), "\\n\"")){ - return false; - } - - final int indexOfSlashNSlashR = text.indexOf("\\n\\r"); - if (indexOfSlashNSlashR != -1 && Comparing.equal(text.substring(indexOfSlashNSlashR, text.length()), "\\n\\r\"")){ - return false; - } - - return true; - } - - @Override - public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { - if (!(element instanceof PsiJavaToken)) { - return; - } - - final PsiJavaToken token = (PsiJavaToken)element; - - if (token.getTokenType() != JavaTokenType.STRING_LITERAL) { - return; - } - - - final String text = token.getText(); - if (text == null) { - return; - } - - final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); - token.replace(factory.createExpressionFromText(breakOnLineBreaks(text), element)); - } - - - @NotNull - private static String breakOnLineBreaks(@NotNull String string) { - final String result = StringUtil.replace( - string, - new String[]{"\\n\\r", "\\n"}, - new String[]{"\\n\\r\" + \n\"", "\\n\" + \n\""} - ); - - final String redundantSuffix = " + \n\"\""; - - return result.endsWith(redundantSuffix) ? result.substring(0, result.length() - redundantSuffix.length()) : result; - } - - @NotNull - @Override - public String getText() { - return CodeInsightBundle.message("intention.break.string.on.line.breaks.text"); - } - - @NotNull - @Override - public String getFamilyName() { - return getText(); - } -} +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.intention.impl; + +import com.intellij.codeInsight.CodeInsightBundle; +import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; + +/** + * @author Danila Ponomarenko + */ +public class BreakStringOnLineBreaksIntentionAction extends PsiElementBaseIntentionAction { + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { + if (!(element instanceof PsiJavaToken)) { + return false; + } + + final PsiJavaToken token = (PsiJavaToken)element; + + if (token.getTokenType() != JavaTokenType.STRING_LITERAL) { + return false; + } + + final String text = token.getText(); + if (text == null) { + return false; + } + + final int indexOfSlashN = text.indexOf("\\n"); + if (indexOfSlashN == -1 || Comparing.equal(text.substring(indexOfSlashN, text.length()), "\\n\"")){ + return false; + } + + final int indexOfSlashNSlashR = text.indexOf("\\n\\r"); + if (indexOfSlashNSlashR != -1 && Comparing.equal(text.substring(indexOfSlashNSlashR, text.length()), "\\n\\r\"")){ + return false; + } + + return true; + } + + @Override + public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { + if (!(element instanceof PsiJavaToken)) { + return; + } + + final PsiJavaToken token = (PsiJavaToken)element; + + if (token.getTokenType() != JavaTokenType.STRING_LITERAL) { + return; + } + + + final String text = token.getText(); + if (text == null) { + return; + } + + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); + token.replace(factory.createExpressionFromText(breakOnLineBreaks(text), element)); + } + + + @NotNull + private static String breakOnLineBreaks(@NotNull String string) { + final String result = StringUtil.replace( + string, + new String[]{"\\n\\r", "\\n"}, + new String[]{"\\n\\r\" + \n\"", "\\n\" + \n\""} + ); + + final String redundantSuffix = " + \n\"\""; + + return result.endsWith(redundantSuffix) ? result.substring(0, result.length() - redundantSuffix.length()) : result; + } + + @NotNull + @Override + public String getText() { + return CodeInsightBundle.message("intention.break.string.on.line.breaks.text"); + } + + @NotNull + @Override + public String getFamilyName() { + return getText(); + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/navigation/JavaGotoSuperHandler.java b/java/java-impl/src/com/intellij/codeInsight/navigation/JavaGotoSuperHandler.java index f83f2e37c4a7..b23209ae5fd0 100644 --- a/java/java-impl/src/com/intellij/codeInsight/navigation/JavaGotoSuperHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/navigation/JavaGotoSuperHandler.java @@ -1,82 +1,82 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.navigation; - -import com.intellij.codeInsight.CodeInsightActionHandler; -import com.intellij.codeInsight.CodeInsightBundle; -import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator; -import com.intellij.codeInsight.navigation.actions.GotoSuperAction; -import com.intellij.featureStatistics.FeatureUsageTracker; -import com.intellij.ide.util.MethodCellRenderer; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.fileEditor.OpenFileDescriptor; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; -import com.intellij.psi.impl.FindSuperElementsHelper; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class JavaGotoSuperHandler implements CodeInsightActionHandler { - @Override - public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file) { - FeatureUsageTracker.getInstance().triggerFeatureUsed(GotoSuperAction.FEATURE_ID); - - int offset = editor.getCaretModel().getOffset(); - PsiElement[] superElements = findSuperElements(file, offset); - if (superElements == null || superElements.length == 0) return; - if (superElements.length == 1) { - PsiElement superElement = superElements[0].getNavigationElement(); - final PsiFile containingFile = superElement.getContainingFile(); - if (containingFile == null) return; - final VirtualFile virtualFile = containingFile.getVirtualFile(); - if (virtualFile == null) return; - OpenFileDescriptor descriptor = new OpenFileDescriptor(project, virtualFile, superElement.getTextOffset()); - FileEditorManager.getInstance(project).openTextEditor(descriptor, true); - } else { - if (superElements[0] instanceof PsiMethod) { - boolean showMethodNames = !PsiUtil.allMethodsHaveSameSignature((PsiMethod[])superElements); - PsiElementListNavigator.openTargets(editor, (PsiMethod[])superElements, - CodeInsightBundle.message("goto.super.method.chooser.title"), - CodeInsightBundle.message("goto.super.method.findUsages.title", ((PsiMethod)superElements[0]).getName()), - new MethodCellRenderer(showMethodNames)); - } - else { - NavigationUtil.getPsiElementPopup(superElements, CodeInsightBundle.message("goto.super.class.chooser.title")).showInBestPositionFor(editor); - } - } - } - - @Nullable - private static PsiElement[] findSuperElements(PsiFile file, int offset) { - PsiElement element = file.findElementAt(offset); - if (element == null) return null; - - PsiNameIdentifierOwner parent = PsiTreeUtil.getParentOfType(element, PsiMethod.class, PsiClass.class); - if (parent == null) - return null; - - return FindSuperElementsHelper.findSuperElements(parent); - } - - @Override - public boolean startInWriteAction() { - return false; - } -} +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.navigation; + +import com.intellij.codeInsight.CodeInsightActionHandler; +import com.intellij.codeInsight.CodeInsightBundle; +import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator; +import com.intellij.codeInsight.navigation.actions.GotoSuperAction; +import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.ide.util.MethodCellRenderer; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.fileEditor.OpenFileDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.psi.impl.FindSuperElementsHelper; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class JavaGotoSuperHandler implements CodeInsightActionHandler { + @Override + public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file) { + FeatureUsageTracker.getInstance().triggerFeatureUsed(GotoSuperAction.FEATURE_ID); + + int offset = editor.getCaretModel().getOffset(); + PsiElement[] superElements = findSuperElements(file, offset); + if (superElements == null || superElements.length == 0) return; + if (superElements.length == 1) { + PsiElement superElement = superElements[0].getNavigationElement(); + final PsiFile containingFile = superElement.getContainingFile(); + if (containingFile == null) return; + final VirtualFile virtualFile = containingFile.getVirtualFile(); + if (virtualFile == null) return; + OpenFileDescriptor descriptor = new OpenFileDescriptor(project, virtualFile, superElement.getTextOffset()); + FileEditorManager.getInstance(project).openTextEditor(descriptor, true); + } else { + if (superElements[0] instanceof PsiMethod) { + boolean showMethodNames = !PsiUtil.allMethodsHaveSameSignature((PsiMethod[])superElements); + PsiElementListNavigator.openTargets(editor, (PsiMethod[])superElements, + CodeInsightBundle.message("goto.super.method.chooser.title"), + CodeInsightBundle.message("goto.super.method.findUsages.title", ((PsiMethod)superElements[0]).getName()), + new MethodCellRenderer(showMethodNames)); + } + else { + NavigationUtil.getPsiElementPopup(superElements, CodeInsightBundle.message("goto.super.class.chooser.title")).showInBestPositionFor(editor); + } + } + } + + @Nullable + private static PsiElement[] findSuperElements(PsiFile file, int offset) { + PsiElement element = file.findElementAt(offset); + if (element == null) return null; + + PsiNameIdentifierOwner parent = PsiTreeUtil.getParentOfType(element, PsiMethod.class, PsiClass.class); + if (parent == null) + return null; + + return FindSuperElementsHelper.findSuperElements(parent); + } + + @Override + public boolean startInWriteAction() { + return false; + } +} diff --git a/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java b/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java index 2ca943236bdf..309fefcddba8 100644 --- a/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java +++ b/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java @@ -1,194 +1,194 @@ -/* - * 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.codeInspection.defaultFileTemplateUsage; - -import com.intellij.codeInsight.CodeInsightUtil; -import com.intellij.codeInspection.*; -import com.intellij.ide.fileTemplates.FileTemplate; -import com.intellij.ide.fileTemplates.FileTemplateManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Ref; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.JavaRecursiveElementWalkingVisitor; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.javadoc.PsiDocComment; -import com.intellij.util.IncorrectOperationException; -import gnu.trove.TIntObjectHashMap; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Properties; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * @author Alexey - */ -public class FileHeaderChecker { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.defaultFileTemplateUsage.FileHeaderChecker"); - - static ProblemDescriptor checkFileHeader(@NotNull final PsiFile file, final InspectionManager manager, boolean onTheFly) { - FileTemplate template = FileTemplateManager.getInstance().getDefaultTemplate(FileTemplateManager.FILE_HEADER_TEMPLATE_NAME); - TIntObjectHashMap offsetToProperty = new TIntObjectHashMap(); - String templateText = template.getText().trim(); - String regex = templateToRegex(templateText, offsetToProperty, file.getProject()); - regex = StringUtil.replace(regex, "with", "(?:with|by)"); - regex = ".*("+regex+").*"; - String fileText = file.getText(); - Pattern pattern = Pattern.compile(regex, Pattern.DOTALL); - Matcher matcher = pattern.matcher(fileText); - if (matcher.matches()) { - final int startOffset = matcher.start(1); - final int endOffset = matcher.end(1); - final Ref docComment = new Ref(); - file.accept(new JavaRecursiveElementWalkingVisitor(){ - @Override public void visitElement(PsiElement element) { - if (docComment.get() != null) return; - TextRange range = element.getTextRange(); - if (!range.contains(startOffset) && !range.contains(endOffset)) return; - super.visitElement(element); - } - @Override public void visitDocComment(PsiDocComment comment) { - docComment.set(comment); - } - }); - PsiDocComment element = docComment.get(); - if (element == null) return null; - LocalQuickFix[] quickFix = createQuickFix(matcher, offsetToProperty); - final String description = InspectionsBundle.message("default.file.template.description"); - return manager.createProblemDescriptor(element, description, onTheFly, quickFix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING); - } - return null; - } - - private static Properties computeProperties(final Matcher matcher, final TIntObjectHashMap offsetToProperty) { - Properties properties = new Properties(FileTemplateManager.getInstance().getDefaultProperties()); - int[] offsets = offsetToProperty.keys(); - Arrays.sort(offsets); - - for (int i = 0; i < offsets.length; i++) { - final int offset = offsets[i]; - String propName = offsetToProperty.get(offset); - int groupNum = i + 2; // first group is whole doc comment - String propValue = matcher.group(groupNum); - properties.put(propName, propValue); - } - return properties; - } - - private static LocalQuickFix[] createQuickFix(final Matcher matcher, - final TIntObjectHashMap offsetToProperty) { - final FileTemplate template = FileTemplateManager.getInstance().getPattern(FileTemplateManager.FILE_HEADER_TEMPLATE_NAME); - - final ReplaceWithFileTemplateFix replaceTemplateFix = new ReplaceWithFileTemplateFix() { - public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { - PsiElement element = descriptor.getPsiElement(); - if (element == null || !element.isValid()) return; - if (!CodeInsightUtil.preparePsiElementsForWrite(element)) return; - String newText; - try { - newText = template.getText(computeProperties(matcher, offsetToProperty)); - } - catch (IOException e) { - LOG.error(e); - return; - } - try { - int offset = element.getTextRange().getStartOffset(); - PsiFile psiFile = element.getContainingFile(); - if (psiFile == null) return; - PsiDocumentManager documentManager = PsiDocumentManager.getInstance(psiFile.getProject()); - Document document = documentManager.getDocument(psiFile); - if (document == null) return; - - element.delete(); - documentManager.doPostponedOperationsAndUnblockDocument(document); - documentManager.commitDocument(document); - - document.insertString(offset, newText); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - catch (IllegalStateException e) { - LOG.error("Cannot create doc comment from text: '" + newText + "'", e); - } - } - }; - final LocalQuickFix editFileTemplateFix = DefaultFileTemplateUsageInspection.createEditFileTemplateFix(template, replaceTemplateFix); - if (template.isDefault()) { - return new LocalQuickFix[]{editFileTemplateFix}; - } - return new LocalQuickFix[]{replaceTemplateFix,editFileTemplateFix}; - } - - private static String templateToRegex(final String text, TIntObjectHashMap offsetToProperty, Project project) { - String regex = text; - @NonNls Collection properties = new ArrayList((Collection)FileTemplateManager.getInstance().getDefaultProperties(project).keySet()); - properties.add("PACKAGE_NAME"); - - regex = escapeRegexChars(regex); - // first group is a whole file header - int groupNumber = 1; - for (String name : properties) { - String escaped = escapeRegexChars("${"+name+"}"); - boolean first = true; - for (int i = regex.indexOf(escaped); i!=-1 && i i) { - String prop = offsetToProperty.remove(off); - offsetToProperty.put(off - delta, prop); - } - } - offsetToProperty.put(i, name); - regex = regex.substring(0,i) + replacement + regex.substring(i+escaped.length()); - if (first) { - groupNumber++; - first = false; - } - } - } - return regex; - } - - private static String escapeRegexChars(String regex) { - regex = StringUtil.replace(regex,"|", "\\|"); - regex = StringUtil.replace(regex,".", "\\."); - regex = StringUtil.replace(regex,"*", "\\*"); - regex = StringUtil.replace(regex,"+", "\\+"); - regex = StringUtil.replace(regex,"?", "\\?"); - regex = StringUtil.replace(regex,"$", "\\$"); - regex = StringUtil.replace(regex,"(", "\\("); - regex = StringUtil.replace(regex,")", "\\)"); - regex = StringUtil.replace(regex,"[", "\\["); - regex = StringUtil.replace(regex,"]", "\\]"); - regex = StringUtil.replace(regex,"{", "\\{"); - regex = StringUtil.replace(regex,"}", "\\}"); - return regex; - } -} +/* + * 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.codeInspection.defaultFileTemplateUsage; + +import com.intellij.codeInsight.CodeInsightUtil; +import com.intellij.codeInspection.*; +import com.intellij.ide.fileTemplates.FileTemplate; +import com.intellij.ide.fileTemplates.FileTemplateManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.JavaRecursiveElementWalkingVisitor; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.util.IncorrectOperationException; +import gnu.trove.TIntObjectHashMap; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Alexey + */ +public class FileHeaderChecker { + private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.defaultFileTemplateUsage.FileHeaderChecker"); + + static ProblemDescriptor checkFileHeader(@NotNull final PsiFile file, final InspectionManager manager, boolean onTheFly) { + FileTemplate template = FileTemplateManager.getInstance().getDefaultTemplate(FileTemplateManager.FILE_HEADER_TEMPLATE_NAME); + TIntObjectHashMap offsetToProperty = new TIntObjectHashMap(); + String templateText = template.getText().trim(); + String regex = templateToRegex(templateText, offsetToProperty, file.getProject()); + regex = StringUtil.replace(regex, "with", "(?:with|by)"); + regex = ".*("+regex+").*"; + String fileText = file.getText(); + Pattern pattern = Pattern.compile(regex, Pattern.DOTALL); + Matcher matcher = pattern.matcher(fileText); + if (matcher.matches()) { + final int startOffset = matcher.start(1); + final int endOffset = matcher.end(1); + final Ref docComment = new Ref(); + file.accept(new JavaRecursiveElementWalkingVisitor(){ + @Override public void visitElement(PsiElement element) { + if (docComment.get() != null) return; + TextRange range = element.getTextRange(); + if (!range.contains(startOffset) && !range.contains(endOffset)) return; + super.visitElement(element); + } + @Override public void visitDocComment(PsiDocComment comment) { + docComment.set(comment); + } + }); + PsiDocComment element = docComment.get(); + if (element == null) return null; + LocalQuickFix[] quickFix = createQuickFix(matcher, offsetToProperty); + final String description = InspectionsBundle.message("default.file.template.description"); + return manager.createProblemDescriptor(element, description, onTheFly, quickFix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING); + } + return null; + } + + private static Properties computeProperties(final Matcher matcher, final TIntObjectHashMap offsetToProperty) { + Properties properties = new Properties(FileTemplateManager.getInstance().getDefaultProperties()); + int[] offsets = offsetToProperty.keys(); + Arrays.sort(offsets); + + for (int i = 0; i < offsets.length; i++) { + final int offset = offsets[i]; + String propName = offsetToProperty.get(offset); + int groupNum = i + 2; // first group is whole doc comment + String propValue = matcher.group(groupNum); + properties.put(propName, propValue); + } + return properties; + } + + private static LocalQuickFix[] createQuickFix(final Matcher matcher, + final TIntObjectHashMap offsetToProperty) { + final FileTemplate template = FileTemplateManager.getInstance().getPattern(FileTemplateManager.FILE_HEADER_TEMPLATE_NAME); + + final ReplaceWithFileTemplateFix replaceTemplateFix = new ReplaceWithFileTemplateFix() { + public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { + PsiElement element = descriptor.getPsiElement(); + if (element == null || !element.isValid()) return; + if (!CodeInsightUtil.preparePsiElementsForWrite(element)) return; + String newText; + try { + newText = template.getText(computeProperties(matcher, offsetToProperty)); + } + catch (IOException e) { + LOG.error(e); + return; + } + try { + int offset = element.getTextRange().getStartOffset(); + PsiFile psiFile = element.getContainingFile(); + if (psiFile == null) return; + PsiDocumentManager documentManager = PsiDocumentManager.getInstance(psiFile.getProject()); + Document document = documentManager.getDocument(psiFile); + if (document == null) return; + + element.delete(); + documentManager.doPostponedOperationsAndUnblockDocument(document); + documentManager.commitDocument(document); + + document.insertString(offset, newText); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + catch (IllegalStateException e) { + LOG.error("Cannot create doc comment from text: '" + newText + "'", e); + } + } + }; + final LocalQuickFix editFileTemplateFix = DefaultFileTemplateUsageInspection.createEditFileTemplateFix(template, replaceTemplateFix); + if (template.isDefault()) { + return new LocalQuickFix[]{editFileTemplateFix}; + } + return new LocalQuickFix[]{replaceTemplateFix,editFileTemplateFix}; + } + + private static String templateToRegex(final String text, TIntObjectHashMap offsetToProperty, Project project) { + String regex = text; + @NonNls Collection properties = new ArrayList((Collection)FileTemplateManager.getInstance().getDefaultProperties(project).keySet()); + properties.add("PACKAGE_NAME"); + + regex = escapeRegexChars(regex); + // first group is a whole file header + int groupNumber = 1; + for (String name : properties) { + String escaped = escapeRegexChars("${"+name+"}"); + boolean first = true; + for (int i = regex.indexOf(escaped); i!=-1 && i i) { + String prop = offsetToProperty.remove(off); + offsetToProperty.put(off - delta, prop); + } + } + offsetToProperty.put(i, name); + regex = regex.substring(0,i) + replacement + regex.substring(i+escaped.length()); + if (first) { + groupNumber++; + first = false; + } + } + } + return regex; + } + + private static String escapeRegexChars(String regex) { + regex = StringUtil.replace(regex,"|", "\\|"); + regex = StringUtil.replace(regex,".", "\\."); + regex = StringUtil.replace(regex,"*", "\\*"); + regex = StringUtil.replace(regex,"+", "\\+"); + regex = StringUtil.replace(regex,"?", "\\?"); + regex = StringUtil.replace(regex,"$", "\\$"); + regex = StringUtil.replace(regex,"(", "\\("); + regex = StringUtil.replace(regex,")", "\\)"); + regex = StringUtil.replace(regex,"[", "\\["); + regex = StringUtil.replace(regex,"]", "\\]"); + regex = StringUtil.replace(regex,"{", "\\{"); + regex = StringUtil.replace(regex,"}", "\\}"); + return regex; + } +} diff --git a/java/java-impl/src/com/intellij/codeInspection/internal/FileEqualsUsageInspection.java b/java/java-impl/src/com/intellij/codeInspection/internal/FileEqualsUsageInspection.java index baba5bc221bd..9f835dd7e380 100644 --- a/java/java-impl/src/com/intellij/codeInspection/internal/FileEqualsUsageInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/internal/FileEqualsUsageInspection.java @@ -1,50 +1,50 @@ -/* - * 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.codeInspection.internal; - -import com.intellij.codeInspection.ProblemHighlightType; -import com.intellij.codeInspection.ProblemsHolder; -import com.intellij.psi.*; -import org.jetbrains.annotations.NotNull; - -public class FileEqualsUsageInspection extends InternalInspection { - private static final String MESSAGE = - "Do not use File.equals/hashCode/compareTo as they don't honor case-sensitivity on MacOS. " + - "Please use FileUtil.filesEquals/fileHashCode/compareFiles instead"; - - @NotNull - public PsiElementVisitor buildInternalVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { - return new JavaElementVisitor() { - @Override - public void visitMethodCallExpression(PsiMethodCallExpression expression) { - PsiReferenceExpression methodExpression = expression.getMethodExpression(); - PsiElement resolved = methodExpression.resolve(); - if (!(resolved instanceof PsiMethod)) return; - - PsiMethod method = (PsiMethod)resolved; - - PsiClass clazz = method.getContainingClass(); - if (clazz == null) return; - - String methodName = method.getName(); - if (CommonClassNames.JAVA_IO_FILE.equals(clazz.getQualifiedName()) && - ("equals".equals(methodName) || "compareTo".equals(methodName) || "hashCode".equals(methodName))) { - holder.registerProblem(methodExpression, MESSAGE, ProblemHighlightType.LIKE_DEPRECATED); - } - } - }; - } -} +/* + * 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.codeInspection.internal; + +import com.intellij.codeInspection.ProblemHighlightType; +import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.psi.*; +import org.jetbrains.annotations.NotNull; + +public class FileEqualsUsageInspection extends InternalInspection { + private static final String MESSAGE = + "Do not use File.equals/hashCode/compareTo as they don't honor case-sensitivity on MacOS. " + + "Please use FileUtil.filesEquals/fileHashCode/compareFiles instead"; + + @NotNull + public PsiElementVisitor buildInternalVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { + return new JavaElementVisitor() { + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + PsiReferenceExpression methodExpression = expression.getMethodExpression(); + PsiElement resolved = methodExpression.resolve(); + if (!(resolved instanceof PsiMethod)) return; + + PsiMethod method = (PsiMethod)resolved; + + PsiClass clazz = method.getContainingClass(); + if (clazz == null) return; + + String methodName = method.getName(); + if (CommonClassNames.JAVA_IO_FILE.equals(clazz.getQualifiedName()) && + ("equals".equals(methodName) || "compareTo".equals(methodName) || "hashCode".equals(methodName))) { + holder.registerProblem(methodExpression, MESSAGE, ProblemHighlightType.LIKE_DEPRECATED); + } + } + }; + } +} diff --git a/java/java-impl/src/com/intellij/psi/filters/getters/JavaMembersGetter.java b/java/java-impl/src/com/intellij/psi/filters/getters/JavaMembersGetter.java index fe99e4889216..f85c56be916e 100644 --- a/java/java-impl/src/com/intellij/psi/filters/getters/JavaMembersGetter.java +++ b/java/java-impl/src/com/intellij/psi/filters/getters/JavaMembersGetter.java @@ -1,156 +1,156 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES 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.filters.getters; - -import com.intellij.codeInsight.TailType; -import com.intellij.codeInsight.completion.*; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.TailTypeDecorator; -import com.intellij.codeInsight.lookup.VariableLookupItem; -import com.intellij.psi.*; -import com.intellij.psi.tree.IElementType; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.util.Consumer; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.HashSet; -import java.util.Set; - -/** - * @author peter - */ -public class JavaMembersGetter extends MembersGetter { - private final PsiType myExpectedType; - - public JavaMembersGetter(@NotNull PsiType expectedType, CompletionParameters parameters) { - super(new JavaStaticMemberProcessor(parameters), parameters.getPosition()); - myExpectedType = JavaCompletionUtil.originalize(expectedType); - } - - public void addMembers(boolean searchInheritors, final Consumer results) { - if (myExpectedType instanceof PsiPrimitiveType && PsiType.DOUBLE.isAssignableFrom(myExpectedType)) { - addConstantsFromTargetClass(results, searchInheritors); - addConstantsFromReferencedClassesInSwitch(results); - } - - if (myPlace.getParent().getParent() instanceof PsiSwitchLabelStatement) { - return; //non-enum values are processed above, enum values will be suggested by reference completion - } - - final PsiClass psiClass = PsiUtil.resolveClassInType(myExpectedType); - processMembers(results, psiClass, PsiTreeUtil.getParentOfType(myPlace, PsiAnnotation.class) == null, searchInheritors); - } - - private void addConstantsFromReferencedClassesInSwitch(final Consumer results) { - final Set fields = ReferenceExpressionCompletionContributor.findConstantsUsedInSwitch(myPlace); - final Set classes = new HashSet(); - for (PsiField field : fields) { - ContainerUtil.addIfNotNull(classes, field.getContainingClass()); - } - for (PsiClass aClass : classes) { - processMembers(new Consumer() { - @Override - public void consume(LookupElement element) { - //noinspection SuspiciousMethodCalls - if (!fields.contains(element.getObject())) { - results.consume(TailTypeDecorator.withTail(element, TailType.CASE_COLON)); - } - } - }, aClass, true, false); - } - } - - private void addConstantsFromTargetClass(Consumer results, boolean searchInheritors) { - PsiElement parent = myPlace.getParent(); - if (!(parent instanceof PsiReferenceExpression)) { - return; - } - - PsiElement prev = parent; - parent = parent.getParent(); - while (parent instanceof PsiBinaryExpression) { - final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)parent; - final IElementType op = binaryExpression.getOperationTokenType(); - if (JavaTokenType.EQEQ == op || JavaTokenType.NE == op) { - if (prev == binaryExpression.getROperand()) { - processMembers(results, getCalledClass(binaryExpression.getLOperand()), true, searchInheritors - ); - } - return; - } - prev = parent; - parent = parent.getParent(); - } - if (parent instanceof PsiExpressionList) { - processMembers(results, getCalledClass(parent.getParent()), true, searchInheritors); - } - } - - @Nullable - private static PsiClass getCalledClass(@Nullable PsiElement call) { - if (call instanceof PsiMethodCallExpression) { - for (final JavaResolveResult result : ((PsiMethodCallExpression)call).getMethodExpression().multiResolve(true)) { - final PsiElement element = result.getElement(); - if (element instanceof PsiMethod) { - final PsiClass aClass = ((PsiMethod)element).getContainingClass(); - if (aClass != null) { - return aClass; - } - } - } - } - if (call instanceof PsiNewExpression) { - final PsiJavaCodeReferenceElement reference = ((PsiNewExpression)call).getClassReference(); - if (reference != null) { - for (final JavaResolveResult result : reference.multiResolve(true)) { - final PsiElement element = result.getElement(); - if (element instanceof PsiClass) { - return (PsiClass)element; - } - } - } - } - return null; - } - - @Override - @Nullable - protected LookupElement createFieldElement(PsiField field) { - if (!myExpectedType.isAssignableFrom(field.getType())) { - return null; - } - - return new VariableLookupItem(field, false); - } - - @Override - @Nullable - protected LookupElement createMethodElement(PsiMethod method) { - PsiSubstitutor substitutor = SmartCompletionDecorator.calculateMethodReturnTypeSubstitutor(method, myExpectedType); - PsiType type = substitutor.substitute(method.getReturnType()); - if (type == null || !myExpectedType.isAssignableFrom(type)) { - return null; - } - - - JavaMethodCallElement item = new JavaMethodCallElement(method, false, false); - item.setInferenceSubstitutor(substitutor, myPlace); - return item; - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.filters.getters; + +import com.intellij.codeInsight.TailType; +import com.intellij.codeInsight.completion.*; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.TailTypeDecorator; +import com.intellij.codeInsight.lookup.VariableLookupItem; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import com.intellij.util.Consumer; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author peter + */ +public class JavaMembersGetter extends MembersGetter { + private final PsiType myExpectedType; + + public JavaMembersGetter(@NotNull PsiType expectedType, CompletionParameters parameters) { + super(new JavaStaticMemberProcessor(parameters), parameters.getPosition()); + myExpectedType = JavaCompletionUtil.originalize(expectedType); + } + + public void addMembers(boolean searchInheritors, final Consumer results) { + if (myExpectedType instanceof PsiPrimitiveType && PsiType.DOUBLE.isAssignableFrom(myExpectedType)) { + addConstantsFromTargetClass(results, searchInheritors); + addConstantsFromReferencedClassesInSwitch(results); + } + + if (myPlace.getParent().getParent() instanceof PsiSwitchLabelStatement) { + return; //non-enum values are processed above, enum values will be suggested by reference completion + } + + final PsiClass psiClass = PsiUtil.resolveClassInType(myExpectedType); + processMembers(results, psiClass, PsiTreeUtil.getParentOfType(myPlace, PsiAnnotation.class) == null, searchInheritors); + } + + private void addConstantsFromReferencedClassesInSwitch(final Consumer results) { + final Set fields = ReferenceExpressionCompletionContributor.findConstantsUsedInSwitch(myPlace); + final Set classes = new HashSet(); + for (PsiField field : fields) { + ContainerUtil.addIfNotNull(classes, field.getContainingClass()); + } + for (PsiClass aClass : classes) { + processMembers(new Consumer() { + @Override + public void consume(LookupElement element) { + //noinspection SuspiciousMethodCalls + if (!fields.contains(element.getObject())) { + results.consume(TailTypeDecorator.withTail(element, TailType.CASE_COLON)); + } + } + }, aClass, true, false); + } + } + + private void addConstantsFromTargetClass(Consumer results, boolean searchInheritors) { + PsiElement parent = myPlace.getParent(); + if (!(parent instanceof PsiReferenceExpression)) { + return; + } + + PsiElement prev = parent; + parent = parent.getParent(); + while (parent instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)parent; + final IElementType op = binaryExpression.getOperationTokenType(); + if (JavaTokenType.EQEQ == op || JavaTokenType.NE == op) { + if (prev == binaryExpression.getROperand()) { + processMembers(results, getCalledClass(binaryExpression.getLOperand()), true, searchInheritors + ); + } + return; + } + prev = parent; + parent = parent.getParent(); + } + if (parent instanceof PsiExpressionList) { + processMembers(results, getCalledClass(parent.getParent()), true, searchInheritors); + } + } + + @Nullable + private static PsiClass getCalledClass(@Nullable PsiElement call) { + if (call instanceof PsiMethodCallExpression) { + for (final JavaResolveResult result : ((PsiMethodCallExpression)call).getMethodExpression().multiResolve(true)) { + final PsiElement element = result.getElement(); + if (element instanceof PsiMethod) { + final PsiClass aClass = ((PsiMethod)element).getContainingClass(); + if (aClass != null) { + return aClass; + } + } + } + } + if (call instanceof PsiNewExpression) { + final PsiJavaCodeReferenceElement reference = ((PsiNewExpression)call).getClassReference(); + if (reference != null) { + for (final JavaResolveResult result : reference.multiResolve(true)) { + final PsiElement element = result.getElement(); + if (element instanceof PsiClass) { + return (PsiClass)element; + } + } + } + } + return null; + } + + @Override + @Nullable + protected LookupElement createFieldElement(PsiField field) { + if (!myExpectedType.isAssignableFrom(field.getType())) { + return null; + } + + return new VariableLookupItem(field, false); + } + + @Override + @Nullable + protected LookupElement createMethodElement(PsiMethod method) { + PsiSubstitutor substitutor = SmartCompletionDecorator.calculateMethodReturnTypeSubstitutor(method, myExpectedType); + PsiType type = substitutor.substitute(method.getReturnType()); + if (type == null || !myExpectedType.isAssignableFrom(type)) { + return null; + } + + + JavaMethodCallElement item = new JavaMethodCallElement(method, false, false); + item.setInferenceSubstitutor(substitutor, myPlace); + return item; + } +} diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java index 727ab77b817c..ef0cf6652e03 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java @@ -1,1497 +1,1497 @@ -/* - * 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.psi.formatter.java; - -import com.intellij.formatting.*; -import com.intellij.formatting.alignment.AlignmentInColumnsConfig; -import com.intellij.formatting.alignment.AlignmentInColumnsHelper; -import com.intellij.formatting.alignment.AlignmentStrategy; -import com.intellij.lang.ASTNode; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.fileTypes.StdFileTypes; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.*; -import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.intellij.psi.codeStyle.CommonCodeStyleSettings; -import com.intellij.psi.formatter.FormatterUtil; -import com.intellij.psi.formatter.common.AbstractBlock; -import com.intellij.psi.formatter.java.wrap.JavaWrapManager; -import com.intellij.psi.formatter.java.wrap.ReservedWrapsProvider; -import com.intellij.psi.impl.source.SourceTreeToPsiMap; -import com.intellij.psi.impl.source.codeStyle.ShiftIndentInsideHelper; -import com.intellij.psi.impl.source.tree.*; -import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; -import com.intellij.psi.impl.source.tree.java.ClassElement; -import com.intellij.psi.jsp.JspElementType; -import com.intellij.psi.tree.IElementType; -import com.intellij.psi.tree.TokenSet; -import com.intellij.util.text.CharArrayUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlock, ReservedWrapsProvider { - - /** - * Holds types of the elements for which 'align in column' rule may be preserved. - * - * @see CodeStyleSettings#ALIGN_GROUP_FIELD_DECLARATIONS - */ - protected static final Set ALIGN_IN_COLUMNS_ELEMENT_TYPES = Collections.unmodifiableSet(new HashSet( - Arrays.asList(JavaElementType.FIELD))); - - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.formatter.java.AbstractJavaBlock"); - - /** - * Shared thread-safe config object to use during 'align in column' processing. - * - * @see CodeStyleSettings#ALIGN_GROUP_FIELD_DECLARATIONS - */ - private static final AlignmentInColumnsConfig ALIGNMENT_IN_COLUMNS_CONFIG = new AlignmentInColumnsConfig( - TokenSet.create(JavaTokenType.IDENTIFIER), JavaJspElementType.WHITE_SPACE_BIT_SET, ElementType.JAVA_COMMENT_BIT_SET, - TokenSet.create(JavaTokenType.EQ), TokenSet.create(JavaElementType.FIELD)); - - /** - * Enumerates types of variable declaration sub-elements that should be aligned in columns. - */ - private static final Set VAR_DECLARATION_ELEMENT_TYPES_TO_ALIGN = new HashSet(Arrays.asList( - JavaElementType.MODIFIER_LIST, JavaElementType.TYPE, JavaTokenType.IDENTIFIER, JavaTokenType.EQ - )); - - @NotNull protected final CommonCodeStyleSettings mySettings; - protected final CommonCodeStyleSettings.IndentOptions myIndentSettings; - private final Indent myIndent; - protected Indent myChildIndent; - protected Alignment myChildAlignment; - protected boolean myUseChildAttributes = false; - @NotNull protected final AlignmentStrategy myAlignmentStrategy; - private boolean myIsAfterClassKeyword = false; - private Wrap myAnnotationWrap = null; - - protected Alignment myReservedAlignment; - protected Alignment myReservedAlignment2; - - private final JavaWrapManager myWrapManager; - private final AlignmentInColumnsHelper myAlignmentInColumnsHelper; - - protected AbstractJavaBlock(@NotNull final ASTNode node, - final Wrap wrap, - final Alignment alignment, - final Indent indent, - @NotNull final CommonCodeStyleSettings settings) { - this(node, wrap, indent, settings, JavaWrapManager.INSTANCE, AlignmentStrategy.wrap(alignment), AlignmentInColumnsHelper.INSTANCE); - } - - protected AbstractJavaBlock(@NotNull final ASTNode node, - final Wrap wrap, - @NotNull final AlignmentStrategy alignmentStrategy, - final Indent indent, - @NotNull final CommonCodeStyleSettings settings) { - this(node, wrap, indent, settings, JavaWrapManager.INSTANCE, alignmentStrategy, AlignmentInColumnsHelper.INSTANCE); - } - - protected AbstractJavaBlock(@NotNull final ASTNode node, - final Wrap wrap, - final Indent indent, - @NotNull final CommonCodeStyleSettings settings, - final JavaWrapManager wrapManager, - @NotNull final AlignmentStrategy alignmentStrategy, - AlignmentInColumnsHelper alignmentInColumnsHelper) { - super(node, wrap, createBlockAlignment(alignmentStrategy, node)); - mySettings = settings; - myIndentSettings = settings.getIndentOptions(); - myIndent = indent; - myWrapManager = wrapManager; - myAlignmentStrategy = alignmentStrategy; - myAlignmentInColumnsHelper = alignmentInColumnsHelper; - } - - @Nullable - private static Alignment createBlockAlignment(@NotNull AlignmentStrategy strategy, @NotNull ASTNode node) { - // There is a possible case that 'implements' section is incomplete (e.g. ends with comma). We may want to align lbrace - // to the first implemented interface reference then. - if (node.getElementType() == JavaElementType.IMPLEMENTS_LIST) { - return null; - } - return strategy.getAlignment(node.getElementType()); - } - - @NotNull - public static Block createJavaBlock(@NotNull final ASTNode child, - @NotNull final CommonCodeStyleSettings settings, - @Nullable final Indent indent, - @Nullable Wrap wrap, - Alignment alignment) { - return createJavaBlock(child, settings, indent, wrap, AlignmentStrategy.wrap(alignment)); - } - - @NotNull - public static Block createJavaBlock(@NotNull final ASTNode child, - @NotNull final CommonCodeStyleSettings settings, - final Indent indent, - @Nullable Wrap wrap, - @NotNull AlignmentStrategy alignmentStrategy) { - return createJavaBlock(child, settings, indent, wrap, alignmentStrategy, -1); - } - - @NotNull - public static Block createJavaBlock(@NotNull final ASTNode child, - @NotNull final CommonCodeStyleSettings settings, - @Nullable final Indent indent, - Wrap wrap, - @NotNull AlignmentStrategy alignmentStrategy, - int startOffset) { - Indent actualIndent = indent == null ? getDefaultSubtreeIndent(child, settings.getRootSettings().getIndentOptions(StdFileTypes.JAVA)) : indent; - final IElementType elementType = child.getElementType(); - Alignment alignment = alignmentStrategy.getAlignment(elementType); - - if (child.getPsi() instanceof PsiWhiteSpace) { - String text = child.getText(); - int start = CharArrayUtil.shiftForward(text, 0, " \t\n"); - int end = CharArrayUtil.shiftBackward(text, text.length() - 1, " \t\n") + 1; - LOG.assertTrue(start < end); - return new PartialWhitespaceBlock(child, new TextRange(start + child.getStartOffset(), end + child.getStartOffset()), - wrap, alignment, actualIndent, settings); - } - if (child.getPsi() instanceof PsiClass) { - return new CodeBlockBlock(child, wrap, alignment, actualIndent, settings); - } - if (isBlockType(elementType)) { - return new BlockContainingJavaBlock(child, wrap, alignment, actualIndent, settings); - } - if (isStatement(child, child.getTreeParent())) { - return new CodeBlockBlock(child, wrap, alignment, actualIndent, settings); - } - if (child instanceof PsiComment && child instanceof PsiLanguageInjectionHost && InjectedLanguageUtil - .hasInjections((PsiLanguageInjectionHost)child)) { - return new CommentWithInjectionBlock(child, wrap, alignment, indent, settings); - } - if (child instanceof LeafElement) { - final LeafBlock block = new LeafBlock(child, wrap, alignment, actualIndent); - block.setStartOffset(startOffset); - return block; - } - else if (isLikeExtendsList(elementType)) { - return new ExtendsListBlock(child, wrap, alignmentStrategy, settings); - } - else if (elementType == JavaElementType.CODE_BLOCK) { - return new CodeBlockBlock(child, wrap, alignment, actualIndent, settings); - } - else if (elementType == JavaElementType.LABELED_STATEMENT) { - return new LabeledJavaBlock(child, wrap, alignment, actualIndent, settings); - } - else if (elementType == JavaDocElementType.DOC_COMMENT) { - return new DocCommentBlock(child, wrap, alignment, actualIndent, settings); - } - else { - final SimpleJavaBlock simpleJavaBlock = new SimpleJavaBlock(child, wrap, alignmentStrategy, actualIndent, settings); - simpleJavaBlock.setStartOffset(startOffset); - return simpleJavaBlock; - } - } - - @NotNull - public static Block createJavaBlock(@NotNull ASTNode child, @NotNull CommonCodeStyleSettings settings) { - return createJavaBlock(child, settings, getDefaultSubtreeIndent(child, settings.getRootSettings().getIndentOptions(StdFileTypes.JAVA)), - null, AlignmentStrategy.getNullStrategy()); - } - - private static boolean isLikeExtendsList(final IElementType elementType) { - return elementType == JavaElementType.EXTENDS_LIST - || elementType == JavaElementType.IMPLEMENTS_LIST - || elementType == JavaElementType.THROWS_LIST; - } - - private static boolean isBlockType(final IElementType elementType) { - return elementType == JavaElementType.SWITCH_STATEMENT - || elementType == JavaElementType.FOR_STATEMENT - || elementType == JavaElementType.WHILE_STATEMENT - || elementType == JavaElementType.DO_WHILE_STATEMENT - || elementType == JavaElementType.TRY_STATEMENT - || elementType == JavaElementType.CATCH_SECTION - || elementType == JavaElementType.IF_STATEMENT - || elementType == JavaElementType.METHOD - || elementType == JavaElementType.ARRAY_INITIALIZER_EXPRESSION - || elementType == JavaElementType.ANNOTATION_ARRAY_INITIALIZER - || elementType == JavaElementType.CLASS_INITIALIZER - || elementType == JavaElementType.SYNCHRONIZED_STATEMENT - || elementType == JavaElementType.FOREACH_STATEMENT; - } - - - @Nullable - private static Indent getDefaultSubtreeIndent(@NotNull ASTNode child, @NotNull CommonCodeStyleSettings.IndentOptions indentOptions) { - final ASTNode parent = child.getTreeParent(); - final IElementType childNodeType = child.getElementType(); - if (childNodeType == JavaElementType.ANNOTATION) { - if (parent.getPsi() instanceof PsiArrayInitializerMemberValue) { - return Indent.getNormalIndent(); - } - return Indent.getNoneIndent(); - } - - final ASTNode prevElement = FormatterUtil.getPreviousNonWhitespaceSibling(child); - if (prevElement != null && prevElement.getElementType() == JavaElementType.MODIFIER_LIST) { - return Indent.getNoneIndent(); - } - - if (childNodeType == JavaDocElementType.DOC_TAG) return Indent.getNoneIndent(); - if (childNodeType == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS) return Indent.getSpaceIndent(1); - if (child.getPsi() instanceof PsiFile) return Indent.getNoneIndent(); - if (parent != null) { - final Indent defaultChildIndent = getChildIndent(parent, indentOptions); - if (defaultChildIndent != null) return defaultChildIndent; - } - - return null; - } - - @Nullable - private static Indent getChildIndent(@NotNull ASTNode parent, @NotNull CommonCodeStyleSettings.IndentOptions indentOptions) { - final IElementType parentType = parent.getElementType(); - if (parentType == JavaElementType.MODIFIER_LIST) return Indent.getNoneIndent(); - if (parentType == JspElementType.JSP_CODE_BLOCK) return Indent.getNormalIndent(); - if (parentType == JspElementType.JSP_CLASS_LEVEL_DECLARATION_STATEMENT) return Indent.getNormalIndent(); - if (parentType == TokenType.DUMMY_HOLDER) return Indent.getNoneIndent(); - if (parentType == JavaElementType.CLASS) return Indent.getNoneIndent(); - if (parentType == JavaElementType.IF_STATEMENT) return Indent.getNoneIndent(); - if (parentType == JavaElementType.TRY_STATEMENT) return Indent.getNoneIndent(); - if (parentType == JavaElementType.CATCH_SECTION) return Indent.getNoneIndent(); - if (parentType == JavaElementType.FOR_STATEMENT) return Indent.getNoneIndent(); - if (parentType == JavaElementType.FOREACH_STATEMENT) return Indent.getNoneIndent(); - if (parentType == JavaElementType.BLOCK_STATEMENT) return Indent.getNoneIndent(); - if (parentType == JavaElementType.DO_WHILE_STATEMENT) return Indent.getNoneIndent(); - if (parentType == JavaElementType.WHILE_STATEMENT) return Indent.getNoneIndent(); - if (parentType == JavaElementType.SWITCH_STATEMENT) return Indent.getNoneIndent(); - if (parentType == JavaElementType.METHOD) return Indent.getNoneIndent(); - if (parentType == JavaDocElementType.DOC_COMMENT) return Indent.getNoneIndent(); - if (parentType == JavaDocElementType.DOC_TAG) return Indent.getNoneIndent(); - if (parentType == JavaDocElementType.DOC_INLINE_TAG) return Indent.getNoneIndent(); - if (parentType == JavaElementType.IMPORT_LIST) return Indent.getNoneIndent(); - if (parentType == JavaElementType.FIELD) return Indent.getContinuationWithoutFirstIndent(indentOptions.USE_RELATIVE_INDENTS); - if (parentType == JavaElementType.EXPRESSION_STATEMENT) return Indent.getNoneIndent(); - if (SourceTreeToPsiMap.treeElementToPsi(parent) instanceof PsiFile) { - return Indent.getNoneIndent(); - } - return null; - } - - protected static boolean isRBrace(@NotNull final ASTNode child) { - return child.getElementType() == JavaTokenType.RBRACE; - } - - @Nullable - @Override - public Spacing getSpacing(Block child1, @NotNull Block child2) { - return JavaSpacePropertyProcessor.getSpacing(getTreeNode(child2), mySettings); - } - - @Override - public ASTNode getFirstTreeNode() { - return myNode; - } - - @Override - public Indent getIndent() { - return myIndent; - } - - protected static boolean isStatement(final ASTNode child, @Nullable final ASTNode parentNode) { - if (parentNode != null) { - final IElementType parentType = parentNode.getElementType(); - if (parentType == JavaElementType.CODE_BLOCK) return false; - final int role = ((CompositeElement)parentNode).getChildRole(child); - if (parentType == JavaElementType.IF_STATEMENT) return role == ChildRole.THEN_BRANCH || role == ChildRole.ELSE_BRANCH; - if (parentType == JavaElementType.FOR_STATEMENT) return role == ChildRole.LOOP_BODY; - if (parentType == JavaElementType.WHILE_STATEMENT) return role == ChildRole.LOOP_BODY; - if (parentType == JavaElementType.DO_WHILE_STATEMENT) return role == ChildRole.LOOP_BODY; - if (parentType == JavaElementType.FOREACH_STATEMENT) return role == ChildRole.LOOP_BODY; - } - return false; - } - - @Nullable - protected Wrap createChildWrap() { - return myWrapManager.createChildBlockWrap(this, getSettings(), this); - } - - @Nullable - protected Alignment createChildAlignment() { - IElementType nodeType = myNode.getElementType(); - if (nodeType == JavaElementType.POLYADIC_EXPRESSION) nodeType = JavaElementType.BINARY_EXPRESSION; - if (nodeType == JavaElementType.ASSIGNMENT_EXPRESSION) { - if (myNode.getTreeParent() != null - && myNode.getTreeParent().getElementType() == JavaElementType.ASSIGNMENT_EXPRESSION - && myAlignment != null) { - return myAlignment; - } - return createAlignment(mySettings.ALIGN_MULTILINE_ASSIGNMENT, null); - } - if (nodeType == JavaElementType.PARENTH_EXPRESSION) { - return createAlignment(mySettings.ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION, null); - } - if (nodeType == JavaElementType.CONDITIONAL_EXPRESSION) { - return createAlignment(mySettings.ALIGN_MULTILINE_TERNARY_OPERATION, null); - } - if (nodeType == JavaElementType.FOR_STATEMENT) { - return createAlignment(mySettings.ALIGN_MULTILINE_FOR, null); - } - if (nodeType == JavaElementType.EXTENDS_LIST || nodeType == JavaElementType.IMPLEMENTS_LIST) { - return createAlignment(mySettings.ALIGN_MULTILINE_EXTENDS_LIST, null); - } - if (nodeType == JavaElementType.THROWS_LIST) { - return createAlignment(mySettings.ALIGN_MULTILINE_THROWS_LIST, null); - } - if (nodeType == JavaElementType.PARAMETER_LIST) { - return createAlignment(mySettings.ALIGN_MULTILINE_PARAMETERS, null); - } - if (nodeType == JavaElementType.RESOURCE_LIST) { - return createAlignment(mySettings.ALIGN_MULTILINE_RESOURCES, null); - } - if (nodeType == JavaElementType.BINARY_EXPRESSION) { - Alignment defaultAlignment = null; - if (shouldInheritAlignment()) { - defaultAlignment = myAlignment; - } - return createAlignment(mySettings.ALIGN_MULTILINE_BINARY_OPERATION, defaultAlignment); - } - if (nodeType == JavaElementType.CLASS || nodeType == JavaElementType.METHOD) { - return Alignment.createAlignment(); - } - return null; - } - - @Nullable - protected Alignment createChildAlignment2(@Nullable Alignment base) { - final IElementType nodeType = myNode.getElementType(); - if (nodeType == JavaElementType.CONDITIONAL_EXPRESSION) { - return base == null ? createAlignment(mySettings.ALIGN_MULTILINE_TERNARY_OPERATION, null) : createAlignment(base, mySettings.ALIGN_MULTILINE_TERNARY_OPERATION, null); - } - return null; - } - - @Nullable - protected Alignment chooseAlignment(@Nullable Alignment alignment, @Nullable Alignment alignment2, @NotNull ASTNode child) { - if (preferSlaveAlignment(child)) { - return alignment2; - } - return alignment; - } - - private boolean preferSlaveAlignment(@NotNull final ASTNode child) { - final IElementType nodeType = myNode.getElementType(); - - if (nodeType == JavaElementType.CONDITIONAL_EXPRESSION) { - IElementType childType = child.getElementType(); - return childType == JavaTokenType.QUEST || childType ==JavaTokenType.COLON; - } - else { - return false; - } - } - - private boolean shouldInheritAlignment() { - if (myNode instanceof PsiPolyadicExpression) { - final ASTNode treeParent = myNode.getTreeParent(); - if (treeParent instanceof PsiPolyadicExpression) { - return JavaFormatterUtil.areSamePriorityBinaryExpressions(myNode, treeParent); - } - } - return false; - } - - - @Nullable - protected ASTNode processChild(@NotNull final List result, - @NotNull ASTNode child, - Alignment defaultAlignment, - final Wrap defaultWrap, - final Indent childIndent) { - return processChild(result, child, AlignmentStrategy.wrap(defaultAlignment), defaultWrap, childIndent, -1); - } - - @Nullable - protected ASTNode processChild(@NotNull final List result, - @NotNull ASTNode child, - @NotNull AlignmentStrategy alignmentStrategy, - @Nullable final Wrap defaultWrap, - final Indent childIndent) { - return processChild(result, child, alignmentStrategy, defaultWrap, childIndent, -1); - } - - @Nullable - protected ASTNode processChild(@NotNull final List result, - @NotNull ASTNode child, - @NotNull AlignmentStrategy alignmentStrategy, - final Wrap defaultWrap, - final Indent childIndent, - int childOffset) { - final IElementType childType = child.getElementType(); - if (childType == JavaTokenType.CLASS_KEYWORD || childType == JavaTokenType.INTERFACE_KEYWORD) { - myIsAfterClassKeyword = true; - } - if (childType == JavaElementType.METHOD_CALL_EXPRESSION) { - result.add(createMethodCallExpressionBlock(child, - arrangeChildWrap(child, defaultWrap), - arrangeChildAlignment(child, alignmentStrategy))); - } - else { - IElementType nodeType = myNode.getElementType(); - if (nodeType == JavaElementType.POLYADIC_EXPRESSION) nodeType = JavaElementType.BINARY_EXPRESSION; - - if (childType == JavaTokenType.LBRACE && nodeType == JavaElementType.ARRAY_INITIALIZER_EXPRESSION) { - final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.ARRAY_INITIALIZER_WRAP), false); - child = processParenthesisBlock(JavaTokenType.LBRACE, JavaTokenType.RBRACE, - result, - child, - WrappingStrategy.createDoNotWrapCommaStrategy(wrap), - mySettings.ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION); - } - else if (childType == JavaTokenType.LBRACE && nodeType == JavaElementType.ANNOTATION_ARRAY_INITIALIZER) { - final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.ARRAY_INITIALIZER_WRAP), false); - child = processParenthesisBlock(JavaTokenType.LBRACE, JavaTokenType.RBRACE, - result, - child, - WrappingStrategy.createDoNotWrapCommaStrategy(wrap), - mySettings.ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION); - } - else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.EXPRESSION_LIST) { - final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.CALL_PARAMETERS_WRAP), false); - if (mySettings.PREFER_PARAMETERS_WRAP) { - wrap.ignoreParentWraps(); - } - child = processParenthesisBlock(result, - child, - WrappingStrategy.createDoNotWrapCommaStrategy(wrap), - mySettings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS); - } - else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.PARAMETER_LIST) { - final Wrap wrap; - Wrap reservedWrap = getReservedWrap(JavaElementType.MODIFIER_LIST); - // There is a possible case that particular annotated method definition is too long. We may wrap either after annotation - // or after opening lbrace then. Our strategy is to wrap after annotation whenever possible. - if (reservedWrap == null) { - wrap = Wrap.createWrap(getWrapType(mySettings.METHOD_PARAMETERS_WRAP), false); - } - else { - wrap = Wrap.createChildWrap(reservedWrap, getWrapType(mySettings.METHOD_PARAMETERS_WRAP), false); - } - child = processParenthesisBlock(result, child, - WrappingStrategy.createDoNotWrapCommaStrategy(wrap), - mySettings.ALIGN_MULTILINE_PARAMETERS); - } - else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.RESOURCE_LIST) { - final Wrap reservedWrap = getReservedWrap(JavaElementType.MODIFIER_LIST); - final Wrap wrap = reservedWrap != null - ? Wrap.createChildWrap(reservedWrap, getWrapType(mySettings.RESOURCE_LIST_WRAP), false) - : Wrap.createWrap(getWrapType(mySettings.RESOURCE_LIST_WRAP), false); - child = processParenthesisBlock(result, child, WrappingStrategy.createDoNotWrapCommaStrategy(wrap), - mySettings.ALIGN_MULTILINE_RESOURCES); - } - else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.ANNOTATION_PARAMETER_LIST) { - final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.CALL_PARAMETERS_WRAP), false); - child = processParenthesisBlock(result, child, - WrappingStrategy.createDoNotWrapCommaStrategy(wrap), - mySettings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS); - } - else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.PARENTH_EXPRESSION) { - child = processParenthesisBlock(result, child, - WrappingStrategy.DO_NOT_WRAP, - mySettings.ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION); - } - else if (childType == JavaElementType.ENUM_CONSTANT && myNode instanceof ClassElement) { - child = processEnumBlock(result, child, ((ClassElement)myNode).findEnumConstantListDelimiterPlace()); - } - else if (mySettings.TERNARY_OPERATION_SIGNS_ON_NEXT_LINE && isTernaryOperationSign(child)) { - child = processTernaryOperationRange(result, child, defaultWrap, childIndent); - } - else if (childType == JavaElementType.FIELD) { - child = processField(result, child, alignmentStrategy, defaultWrap, childIndent); - } - else if (childType == JavaElementType.LOCAL_VARIABLE - || childType == JavaElementType.DECLARATION_STATEMENT && myNode.getElementType() == JavaElementType.METHOD) - { - result.add(new SimpleJavaBlock(child, defaultWrap, alignmentStrategy, childIndent, mySettings)); - } - else { - AlignmentStrategy alignmentStrategyToUse = AlignmentStrategy.wrap(arrangeChildAlignment(child, alignmentStrategy)); - if (myAlignmentStrategy.getAlignment(nodeType, childType) != null - && (nodeType == JavaElementType.IMPLEMENTS_LIST || nodeType == JavaElementType.CLASS)) - { - alignmentStrategyToUse = myAlignmentStrategy; - } - final Block block = createJavaBlock( - child, mySettings, childIndent, arrangeChildWrap(child, defaultWrap), alignmentStrategyToUse, childOffset - ); - - if (childType == JavaElementType.MODIFIER_LIST && containsAnnotations(child)) { - myAnnotationWrap = Wrap.createWrap(getWrapType(getAnnotationWrapType(child)), true); - } - - if (block instanceof AbstractJavaBlock) { - final AbstractJavaBlock javaBlock = (AbstractJavaBlock)block; - if (nodeType == JavaElementType.METHOD_CALL_EXPRESSION && childType == JavaElementType.REFERENCE_EXPRESSION - || nodeType == JavaElementType.REFERENCE_EXPRESSION && childType == JavaElementType.METHOD_CALL_EXPRESSION) - { - javaBlock.setReservedWrap(getReservedWrap(nodeType), nodeType); - javaBlock.setReservedWrap(getReservedWrap(childType), childType); - } - else if (nodeType == JavaElementType.BINARY_EXPRESSION) { - javaBlock.setReservedWrap(defaultWrap, nodeType); - } - else if (childType == JavaElementType.MODIFIER_LIST) { - javaBlock.setReservedWrap(myAnnotationWrap, JavaElementType.MODIFIER_LIST); - if (!lastChildIsAnnotation(child)) { - myAnnotationWrap = null; - } - } - else if (childType == JavaElementType.PARAMETER_LIST && nodeType == JavaElementType.METHOD) { - // We prefer wrapping after method annotation to wrapping method parameter list, hence, deliver target wrap object - // to child block if necessary. - if (!result.isEmpty()) { - Block firstChildBlock = result.get(0); - if (firstChildBlock instanceof AbstractJavaBlock) { - AbstractJavaBlock childJavaBlock = (AbstractJavaBlock)firstChildBlock; - if (firstChildIsAnnotation(childJavaBlock.getNode())) { - javaBlock.setReservedWrap(childJavaBlock.getReservedWrap(JavaElementType.MODIFIER_LIST), JavaElementType.MODIFIER_LIST); - } - } - } - } - } - - result.add(block); - } - } - - - return child; - } - - private ASTNode processField(@NotNull final List result, - ASTNode child, - @NotNull final AlignmentStrategy alignmentStrategy, - final Wrap defaultWrap, - final Indent childIndent) { - ASTNode lastFieldInGroup = findLastFieldInGroup(child); - if (lastFieldInGroup == child) { - result.add(createJavaBlock(child, getSettings(), childIndent, arrangeChildWrap(child, defaultWrap), alignmentStrategy)); - return child; - } - else { - final ArrayList localResult = new ArrayList(); - while (child != null) { - if (!FormatterUtil.containsWhiteSpacesOnly(child)) { - localResult.add(createJavaBlock(child, - getSettings(), - Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS), - arrangeChildWrap(child, defaultWrap), - alignmentStrategy) - ); - } - if (child == lastFieldInGroup) break; - - child = child.getTreeNext(); - } - if (!localResult.isEmpty()) { - result.add(new SyntheticCodeBlock(localResult, null, getSettings(), childIndent, null)); - } - return lastFieldInGroup; - } - } - - /** - * Serves for processing composite field definitions as a single formatting block. - *

- * 'Composite field definition' looks like {@code 'int i1, i2 = 2'}. It produces two nodes of type - * {@link JavaElementType#FIELD} - {@code 'int i1'} and {@code 'i2 = 2'}. This method returns the second node if the first one - * is given (the given node is returned for 'single' fields). - * - * @param child child field node to check - * @return last child field node at the field group identified by the given node if any; given child otherwise - */ - @NotNull - private static ASTNode findLastFieldInGroup(@NotNull final ASTNode child) { - PsiElement psi = child.getPsi(); - if (psi == null) { - return child; - } - final PsiTypeElement typeElement = ((PsiVariable)psi).getTypeElement(); - if (typeElement == null) return child; - - ASTNode lastChildNode = child.getLastChildNode(); - if (lastChildNode == null) return child; - - if (lastChildNode.getElementType() == JavaTokenType.SEMICOLON) return child; - - ASTNode currentResult = child; - ASTNode currentNode = child.getTreeNext(); - - while (currentNode != null) { - if (currentNode.getElementType() == TokenType.WHITE_SPACE - || currentNode.getElementType() == JavaTokenType.COMMA - || StdTokenSets.COMMENT_BIT_SET.contains(currentNode.getElementType())) { - } - else if (currentNode.getElementType() == JavaElementType.FIELD) { - if (compoundFieldPart(currentNode)) { - currentResult = currentNode; - } - else { - return currentResult; - } - } - else { - return currentResult; - } - - currentNode = currentNode.getTreeNext(); - } - return currentResult; - } - - @Nullable - private ASTNode processTernaryOperationRange(@NotNull final List result, - @NotNull final ASTNode child, - final Wrap defaultWrap, - final Indent childIndent) { - final ArrayList localResult = new ArrayList(); - final Wrap wrap = arrangeChildWrap(child, defaultWrap); - final Alignment alignment = myReservedAlignment; - final Alignment alignment2 = myReservedAlignment2; - localResult.add(new LeafBlock(child, wrap, chooseAlignment(alignment, alignment2, child), childIndent)); - - ASTNode current = child.getTreeNext(); - while (current != null) { - if (!FormatterUtil.containsWhiteSpacesOnly(current) && current.getTextLength() > 0) { - if (isTernaryOperationSign(current)) break; - current = processChild(localResult, current, chooseAlignment(alignment, alignment2, current), defaultWrap, childIndent); - } - if (current != null) { - current = current.getTreeNext(); - } - } - - result.add(new SyntheticCodeBlock(localResult, chooseAlignment(alignment, alignment2, child), getSettings(), null, wrap)); - - if (current == null) { - return null; - } - return current.getTreePrev(); - } - - private boolean isTernaryOperationSign(@NotNull final ASTNode child) { - if (myNode.getElementType() != JavaElementType.CONDITIONAL_EXPRESSION) return false; - final int role = ((CompositeElement)child.getTreeParent()).getChildRole(child); - return role == ChildRole.OPERATION_SIGN || role == ChildRole.COLON; - } - - @NotNull - private Block createMethodCallExpressionBlock(@NotNull final ASTNode node, final Wrap blockWrap, final Alignment alignment) { - final ArrayList nodes = new ArrayList(); - final ArrayList subBlocks = new ArrayList(); - collectNodes(nodes, node); - - final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.METHOD_CALL_CHAIN_WRAP), false); - - // We use this alignment object to align chained method calls to the first method invocation place if necessary (see IDEA-30369) - Alignment chainedCallsAlignment = createAlignment(mySettings.ALIGN_MULTILINE_CHAINED_METHODS, null); - - // We want to align chained method calls only if method target is explicitly specified, i.e. we don't want to align methods - // chain like 'recursive().recursive().recursive()' but want to align calls like 'foo.recursive().recursive().recursive()' - boolean callPointDefined = false; - List lookAheadNodes = null; - boolean afterIdentifier = false; - - while (!nodes.isEmpty() || lookAheadNodes != null) { - final List subNodes; - if (lookAheadNodes == null) { - subNodes = readToNextDot(nodes); - } - else { - subNodes = new ArrayList(lookAheadNodes); - lookAheadNodes = null; - } - Alignment alignmentToUseForSubBlock = null; - - // Just create a no-aligned sub-block if we don't need to bother with it's alignment (either due to end-user - // setup or sub-block state). - if (chainedCallsAlignment == null || subNodes.isEmpty()) { - subBlocks.add(createSyntheticBlock(subNodes, wrap, alignmentToUseForSubBlock)); - continue; - } - - IElementType lastNodeType = subNodes.get(subNodes.size() - 1).getElementType(); - boolean currentSubBlockIsMethodCall = lastNodeType == JavaElementType.EXPRESSION_LIST; - - // Update information about chained method alignment point if necessary. I.e. we want to align only continuous method calls - // like 'foo.bar().bar().bar()' but not 'foo.bar().foo.bar()' - if (callPointDefined && !currentSubBlockIsMethodCall) { - chainedCallsAlignment = createAlignment(mySettings.ALIGN_MULTILINE_CHAINED_METHODS, null); - } - callPointDefined |= !currentSubBlockIsMethodCall; - - // We want to align method call only if call target is defined for the first chained method and current block is a method call. - if (callPointDefined && currentSubBlockIsMethodCall) { - alignmentToUseForSubBlock = chainedCallsAlignment; - } - else if (afterIdentifier && lastNodeType == JavaTokenType.IDENTIFIER) { - // Align method call to the last field access. Example: - // MyClass.staticField - // .foo(); - lookAheadNodes = readToNextDot(nodes); - if (!lookAheadNodes.isEmpty() && lookAheadNodes.get(lookAheadNodes.size() - 1).getElementType() == JavaElementType.EXPRESSION_LIST) { - alignmentToUseForSubBlock = chainedCallsAlignment; - } - } - afterIdentifier = lastNodeType == JavaTokenType.IDENTIFIER; - subBlocks.add(createSyntheticBlock(subNodes, wrap, alignmentToUseForSubBlock)); - } - - return new SyntheticCodeBlock(subBlocks, alignment, mySettings, - Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS), blockWrap); - } - - @NotNull - private Block createSyntheticBlock(@NotNull final List subNodes, final Wrap wrap, @Nullable final Alignment alignment) { - final ArrayList subBlocks = new ArrayList(); - final ASTNode firstNode = subNodes.get(0); - if (firstNode.getElementType() == JavaTokenType.DOT) { - subBlocks.add(createJavaBlock(firstNode, getSettings(), Indent.getNoneIndent(), null, AlignmentStrategy.getNullStrategy())); - subNodes.remove(0); - if (!subNodes.isEmpty()) { - subBlocks.add(createSyntheticBlock(subNodes, wrap, null)); - } - return new SyntheticCodeBlock(subBlocks, alignment, mySettings, - Indent.getContinuationIndent(myIndentSettings.USE_RELATIVE_INDENTS), wrap); - } - return new SyntheticCodeBlock(createJavaBlocks(subNodes), alignment, mySettings, - Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS), null); - } - - @NotNull - private List createJavaBlocks(@NotNull final List subNodes) { - final ArrayList result = new ArrayList(); - for (ASTNode node : subNodes) { - result.add(createJavaBlock(node, getSettings(), Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS), null, - AlignmentStrategy.getNullStrategy())); - } - return result; - } - - @NotNull - private static List readToNextDot(@NotNull List nodes) { - final ArrayList result = new ArrayList(); - result.add(nodes.remove(0)); - for (Iterator iterator = nodes.iterator(); iterator.hasNext();) { - ASTNode node = iterator.next(); - if (node.getElementType() == JavaTokenType.DOT) break; - result.add(node); - iterator.remove(); - } - return result; - } - - private static void collectNodes(@NotNull List nodes, @NotNull ASTNode node) { - ASTNode child = node.getFirstChildNode(); - while (child != null) { - if (!FormatterUtil.containsWhiteSpacesOnly(child)) { - if (child.getElementType() == JavaElementType.METHOD_CALL_EXPRESSION || child.getElementType() == - JavaElementType - .REFERENCE_EXPRESSION) { - collectNodes(nodes, child); - } - else { - nodes.add(child); - } - } - child = child.getTreeNext(); - } - } - - private static boolean firstChildIsAnnotation(@NotNull final ASTNode child) { - ASTNode current = child.getFirstChildNode(); - while (current != null && current.getElementType() == TokenType.WHITE_SPACE) { - current = current.getTreeNext(); - } - return current != null && current.getElementType() == JavaElementType.ANNOTATION; - } - - private static boolean lastChildIsAnnotation(@NotNull final ASTNode child) { - ASTNode current = child.getLastChildNode(); - while (current != null && current.getElementType() == TokenType.WHITE_SPACE) { - current = current.getTreePrev(); - } - return current != null && current.getElementType() == JavaElementType.ANNOTATION; - } - - private static boolean containsAnnotations(@NotNull final ASTNode child) { - PsiElement psi = child.getPsi(); - return psi instanceof PsiModifierList && ((PsiModifierList)psi).getAnnotations().length > 0; - } - - private int getAnnotationWrapType(@NotNull ASTNode child) { - final IElementType nodeType = myNode.getElementType(); - if (nodeType == JavaElementType.METHOD) { - return mySettings.METHOD_ANNOTATION_WRAP; - } - if (nodeType == JavaElementType.CLASS) { - // There is a possible case that current document state is invalid from language syntax point of view, e.g. the user starts - // typing field definition and re-formatting is triggered by 'auto insert javadoc' processing. Example: - // class Test { - // @NotNull Object - // } - // Here '@NotNull' has a 'class' node as a parent but we want to use field annotation setting value. Hence, we check if subsequent - // parsed info is valid. - for (ASTNode node = child.getTreeNext(); node != null; node = node.getTreeNext()) { - if (TokenType.WHITE_SPACE == node.getElementType() || node instanceof PsiTypeElement) { - continue; - } - if (node instanceof PsiErrorElement) { - return mySettings.FIELD_ANNOTATION_WRAP; - } - } - return mySettings.CLASS_ANNOTATION_WRAP; - } - if (nodeType == JavaElementType.FIELD) { - return mySettings.FIELD_ANNOTATION_WRAP; - } - if (nodeType == JavaElementType.PARAMETER) { - return mySettings.PARAMETER_ANNOTATION_WRAP; - } - if (nodeType == JavaElementType.LOCAL_VARIABLE) { - return mySettings.VARIABLE_ANNOTATION_WRAP; - } - return CommonCodeStyleSettings.DO_NOT_WRAP; - } - - @Nullable - private Alignment arrangeChildAlignment(@NotNull final ASTNode child, @NotNull final AlignmentStrategy alignmentStrategy) { - int role = getChildRole(child); - final IElementType nodeType = myNode.getElementType(); - Alignment defaultAlignment = alignmentStrategy.getAlignment(child.getElementType()); - - if (nodeType == JavaElementType.FOR_STATEMENT) { - if (role == ChildRole.FOR_INITIALIZATION || role == ChildRole.CONDITION || role == ChildRole.FOR_UPDATE) { - return defaultAlignment; - } - return null; - } - else if (nodeType == JavaElementType.EXTENDS_LIST || nodeType == JavaElementType.IMPLEMENTS_LIST) { - if (role == ChildRole.REFERENCE_IN_LIST || role == ChildRole.IMPLEMENTS_KEYWORD) { - return defaultAlignment; - } - return null; - } - else if (nodeType == JavaElementType.THROWS_LIST) { - if (role == ChildRole.REFERENCE_IN_LIST) { - return defaultAlignment; - } - return null; - } - else if (nodeType == JavaElementType.CLASS) { - if (role == ChildRole.CLASS_OR_INTERFACE_KEYWORD) return defaultAlignment; - if (myIsAfterClassKeyword) return null; - if (role == ChildRole.MODIFIER_LIST) return defaultAlignment; - return null; - } - else if (ALIGN_IN_COLUMNS_ELEMENT_TYPES.contains(nodeType)) { - return getVariableDeclarationSubElementAlignment(child); - } - else if (nodeType == JavaElementType.METHOD) { - if (role == ChildRole.MODIFIER_LIST) return defaultAlignment; - if (role == ChildRole.TYPE_PARAMETER_LIST) return defaultAlignment; - if (role == ChildRole.TYPE) return defaultAlignment; - if (role == ChildRole.NAME) return defaultAlignment; - if (role == ChildRole.THROWS_LIST && mySettings.ALIGN_THROWS_KEYWORD) return defaultAlignment; - return null; - } - - else if (nodeType == JavaElementType.ASSIGNMENT_EXPRESSION) { - if (role == ChildRole.LOPERAND) return defaultAlignment; - if (role == ChildRole.ROPERAND && child.getElementType() == JavaElementType.ASSIGNMENT_EXPRESSION) { - return defaultAlignment; - } - return null; - } - - else if (child.getElementType() == JavaTokenType.END_OF_LINE_COMMENT) { - ASTNode previous = child.getTreePrev(); - // There is a special case - comment block that is located at the very start of the line. We don't reformat such a blocks, - // hence, no alignment should be applied to them in order to avoid subsequent blocks aligned with the same alignment to - // be located at the left editor edge as well. - if (previous != null && previous.getElementType() == TokenType.WHITE_SPACE && previous.getChars().length() > 0 - && previous.getChars().charAt(previous.getChars().length() - 1) == '\n') { - return null; - } - return defaultAlignment; - } - - else if (nodeType == JavaElementType.MODIFIER_LIST) { - // There is a possible case that modifier list contains from more than one elements, e.g. 'private final'. It's also possible - // that the list is aligned. We want to apply alignment rule only to the first element then. - ASTNode previous = child.getTreePrev(); - if (previous == null || previous.getTreeParent() != myNode) { - return defaultAlignment; - } - return null; - } - - else { - return defaultAlignment; - } - } - - private static int getChildRole(@NotNull ASTNode child) { - return ((CompositeElement)child.getTreeParent()).getChildRole(child); - } - - /** - * Encapsulates alignment retrieval logic for variable declaration use-case assuming that given node is a child node - * of basic variable declaration node. - * - * @param child variable declaration child node which alignment is to be defined - * @return alignment to use for the given node - * @see CodeStyleSettings#ALIGN_GROUP_FIELD_DECLARATIONS - */ - @Nullable - private Alignment getVariableDeclarationSubElementAlignment(@NotNull ASTNode child) { - // The whole idea of variable declarations alignment is that complete declaration blocks which children are to be aligned hold - // reference to the same AlignmentStrategy object, hence, reuse the same Alignment objects. So, there is no point in checking - // if it's necessary to align sub-blocks if shared strategy is not defined. - if (!mySettings.ALIGN_GROUP_FIELD_DECLARATIONS) { - return null; - } - - IElementType childType = child.getElementType(); - - // We don't want to align subsequent identifiers in single-line declarations like 'int i1, i2, i3'. I.e. only 'i1' - // should be aligned then. - ASTNode previousNode = FormatterUtil.getPreviousNonWhitespaceSibling(child); - if (childType == JavaTokenType.IDENTIFIER && (previousNode == null || previousNode.getElementType() == JavaTokenType.COMMA)) { - return null; - } - - return myAlignmentStrategy.getAlignment(childType); - } - - /* - private boolean isAfterClassKeyword(final ASTNode child) { - ASTNode treePrev = child.getTreePrev(); - while (treePrev != null) { - if (treePrev.getElementType() == ElementType.CLASS_KEYWORD || - treePrev.getElementType() == ElementType.INTERFACE_KEYWORD) { - return true; - } - treePrev = treePrev.getTreePrev(); - } - return false; - } - - */ - - @Nullable - private static Alignment createAlignment(final boolean alignOption, @Nullable final Alignment defaultAlignment) { - return alignOption ? createAlignmentOrDefault(null, defaultAlignment) : defaultAlignment; - } - - @Nullable - private static Alignment createAlignment(Alignment base, final boolean alignOption, @Nullable final Alignment defaultAlignment) { - return alignOption ? createAlignmentOrDefault(base, defaultAlignment) : defaultAlignment; - } - - @Nullable - protected Wrap arrangeChildWrap(final ASTNode child, Wrap defaultWrap) { - if (myAnnotationWrap != null) { - try { - return myAnnotationWrap; - } - finally { - myAnnotationWrap = null; - } - } - return myWrapManager.arrangeChildWrap(child, myNode, getSettings(), defaultWrap, this); - } - - @NotNull - private static WrapType getWrapType(final int wrap) { - switch (wrap) { - case CommonCodeStyleSettings.WRAP_ALWAYS: - return WrapType.ALWAYS; - case CommonCodeStyleSettings.WRAP_AS_NEEDED: - return WrapType.NORMAL; - case CommonCodeStyleSettings.DO_NOT_WRAP: - return WrapType.NONE; - default: - return WrapType.CHOP_DOWN_IF_LONG; - } - } - - @NotNull - private ASTNode processParenthesisBlock(@NotNull List result, - @NotNull ASTNode child, - @NotNull WrappingStrategy wrappingStrategy, - final boolean doAlign) { - - myUseChildAttributes = true; - - final IElementType from = JavaTokenType.LPARENTH; - final IElementType to = JavaTokenType.RPARENTH; - - return processParenthesisBlock(from, to, result, child, wrappingStrategy, doAlign); - } - - - @NotNull - private ASTNode processParenthesisBlock(@NotNull IElementType from, - @Nullable final IElementType to, - @NotNull final List result, - @NotNull ASTNode child, - @NotNull final WrappingStrategy wrappingStrategy, - final boolean doAlign) { - final Indent externalIndent = Indent.getNoneIndent(); - final Indent internalIndent = Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS); - final Indent internalIndentEnforcedToChildren = Indent.getIndent(Indent.Type.CONTINUATION, myIndentSettings.USE_RELATIVE_INDENTS, true); - AlignmentStrategy alignmentStrategy = AlignmentStrategy.wrap(createAlignment(doAlign, null), JavaTokenType.COMMA); - setChildIndent(internalIndent); - setChildAlignment(alignmentStrategy.getAlignment(null)); - boolean methodParametersBlock = true; - ASTNode lBracketParent = child.getTreeParent(); - if (lBracketParent != null) { - ASTNode methodCandidate = lBracketParent.getTreeParent(); - methodParametersBlock = methodCandidate != null && (methodCandidate.getElementType() == JavaElementType.METHOD - || methodCandidate.getElementType() == JavaElementType.METHOD_CALL_EXPRESSION); - } - Alignment bracketAlignment = methodParametersBlock && mySettings.ALIGN_MULTILINE_METHOD_BRACKETS ? Alignment.createAlignment() : null; - AlignmentStrategy anonymousClassStrategy = doAlign ? alignmentStrategy - : AlignmentStrategy.wrap(Alignment.createAlignment(), - false, - JavaTokenType.NEW_KEYWORD, - JavaElementType.NEW_EXPRESSION, - JavaTokenType.RBRACE); - setChildIndent(internalIndent); - setChildAlignment(alignmentStrategy.getAlignment(null)); - - boolean isAfterIncomplete = false; - - ASTNode prev = child; - boolean afterAnonymousClass = false; - while (child != null) { - isAfterIncomplete = isAfterIncomplete || child.getElementType() == TokenType.ERROR_ELEMENT || - child.getElementType() == JavaElementType.EMPTY_EXPRESSION; - if (!FormatterUtil.containsWhiteSpacesOnly(child) && child.getTextLength() > 0) { - if (child.getElementType() == from) { - result.add(createJavaBlock(child, mySettings, externalIndent, null, bracketAlignment)); - } - else if (child.getElementType() == to) { - result.add(createJavaBlock(child, mySettings, - isAfterIncomplete && !afterAnonymousClass ? internalIndent : externalIndent, - null, - isAfterIncomplete ? alignmentStrategy.getAlignment(null) : bracketAlignment)); - return child; - } - else { - final IElementType elementType = child.getElementType(); - final boolean enforceIndent = shouldEnforceIndentToChildren(child); - Indent indentToUse = enforceIndent ? internalIndentEnforcedToChildren : internalIndent; - AlignmentStrategy alignmentStrategyToUse = canUseAnonymousClassAlignment(child) ? anonymousClassStrategy : alignmentStrategy; - processChild(result, child, alignmentStrategyToUse.getAlignment(elementType), wrappingStrategy.getWrap(elementType), indentToUse); - if (to == null) {//process only one statement - return child; - } - } - isAfterIncomplete = false; - if (child.getElementType() != JavaTokenType.COMMA) { - afterAnonymousClass = isAnonymousClass(child); - } - } - prev = child; - child = child.getTreeNext(); - } - - return prev; - } - - private static boolean canUseAnonymousClassAlignment(@NotNull ASTNode child) { - // The general idea is to handle situations like below: - // test(new Runnable() { - // public void run() { - // } - // }, new Runnable() { - // public void run() { - // } - // } - // ); - // I.e. we want to align subsequent anonymous class argument to the previous one if it's not preceded by another argument - // at the same line, e.g.: - // test("this is a long argument", new Runnable() { - // public void run() { - // } - // }, new Runnable() { - // public void run() { - // } - // } - // ); - if (!isAnonymousClass(child)) { - return false; - } - - for (ASTNode node = child.getTreePrev(); node != null; node = node.getTreePrev()) { - if (node.getElementType() == TokenType.WHITE_SPACE) { - if (StringUtil.countNewLines(node.getChars()) > 0) { - return false; - } - } - else if (node.getElementType() == JavaTokenType.LPARENTH) { - // First method call argument. - return true; - } - else if (node.getElementType() != JavaTokenType.COMMA && !isAnonymousClass(node)) { - return false; - } - } - return true; - } - - private boolean shouldEnforceIndentToChildren(@NotNull ASTNode node) { - // Filter only anonymous class instances as method call arguments - if (myNode.getElementType() != JavaElementType.EXPRESSION_LIST) { - return false; - } - ASTNode parent = myNode.getTreeParent(); - if (parent == null || parent.getElementType() != JavaElementType.METHOD_CALL_EXPRESSION) { - return false; - } - if (!isAnonymousClass(node) || !JavaFormatterUtil.hasAnonymousClassesArguments((PsiExpressionList)myNode.getPsi(), 2)) { - return false; - } - - // Enforce indent only if anonymous class instance expression doesn't start new line and have anonymous class expression sibling. - ASTNode prev = node.getTreePrev(); - return prev != null && !(StringUtil.containsLineBreak(prev.getChars()) && prev.getElementType() != TokenType.WHITE_SPACE); - } - - private static boolean isAnonymousClass(@Nullable ASTNode node) { - if (node == null || node.getElementType() != JavaElementType.NEW_EXPRESSION) { - return false; - } - ASTNode lastChild = node.getLastChildNode(); - return lastChild != null && lastChild.getElementType() == JavaElementType.ANONYMOUS_CLASS; - } - - @Nullable - private ASTNode processEnumBlock(@NotNull List result, - @Nullable ASTNode child, - ASTNode last) - { - final WrappingStrategy wrappingStrategy = WrappingStrategy.createDoNotWrapCommaStrategy(Wrap - .createWrap(getWrapType(mySettings.ENUM_CONSTANTS_WRAP), true)); - while (child != null) { - if (!FormatterUtil.containsWhiteSpacesOnly(child) && child.getTextLength() > 0) { - result.add(createJavaBlock(child, mySettings, Indent.getNormalIndent(), - wrappingStrategy.getWrap(child.getElementType()), AlignmentStrategy.getNullStrategy())); - if (child == last) return child; - } - child = child.getTreeNext(); - } - return null; - } - - private void setChildAlignment(final Alignment alignment) { - myChildAlignment = alignment; - } - - private void setChildIndent(final Indent internalIndent) { - myChildIndent = internalIndent; - } - - @Nullable - private static Alignment createAlignmentOrDefault(@Nullable Alignment base, @Nullable final Alignment defaultAlignment) { - if (defaultAlignment == null) { - return base == null ? Alignment.createAlignment() : Alignment.createChildAlignment(base); - } - return defaultAlignment; - } - - private int getBraceStyle() { - final PsiElement psiNode = SourceTreeToPsiMap.treeElementToPsi(myNode); - if (psiNode instanceof PsiClass) { - return mySettings.CLASS_BRACE_STYLE; - } - if (psiNode instanceof PsiMethod - || psiNode instanceof PsiCodeBlock && psiNode.getParent() != null && psiNode.getParent() instanceof PsiMethod) { - return mySettings.METHOD_BRACE_STYLE; - } - return mySettings.BRACE_STYLE; - } - - protected Indent getCodeBlockInternalIndent(final int baseChildrenIndent) { - return getCodeBlockInternalIndent(baseChildrenIndent, false); - } - - protected Indent getCodeBlockInternalIndent(final int baseChildrenIndent, boolean enforceParentIndent) { - if (isTopLevelClass() && mySettings.DO_NOT_INDENT_TOP_LEVEL_CLASS_MEMBERS) { - return Indent.getNoneIndent(); - } - - final int braceStyle = getBraceStyle(); - return braceStyle == CommonCodeStyleSettings.NEXT_LINE_SHIFTED ? - createNormalIndent(baseChildrenIndent - 1, enforceParentIndent) - : createNormalIndent(baseChildrenIndent, enforceParentIndent); - } - - protected static Indent createNormalIndent(final int baseChildrenIndent) { - return createNormalIndent(baseChildrenIndent, false); - } - - protected static Indent createNormalIndent(final int baseChildrenIndent, boolean enforceIndentToChildren) { - if (baseChildrenIndent == 1) { - return Indent.getIndent(Indent.Type.NORMAL, false, enforceIndentToChildren); - } - else if (baseChildrenIndent <= 0) { - return Indent.getNoneIndent(); - } - else { - LOG.assertTrue(false); - return Indent.getIndent(Indent.Type.NORMAL, false, enforceIndentToChildren); - } - } - - private boolean isTopLevelClass() { - return myNode.getElementType() == JavaElementType.CLASS && - SourceTreeToPsiMap.treeElementToPsi(myNode.getTreeParent()) instanceof PsiFile; - } - - protected Indent getCodeBlockExternalIndent() { - final int braceStyle = getBraceStyle(); - if (braceStyle == CommonCodeStyleSettings.END_OF_LINE || braceStyle == CommonCodeStyleSettings.NEXT_LINE || - braceStyle == CommonCodeStyleSettings.NEXT_LINE_IF_WRAPPED) { - return Indent.getNoneIndent(); - } - return Indent.getNormalIndent(); - } - - protected Indent getCodeBlockChildExternalIndent(final int newChildIndex) { - final int braceStyle = getBraceStyle(); - if (!isAfterCodeBlock(newChildIndex)) { - return Indent.getNormalIndent(); - } - if (braceStyle == CommonCodeStyleSettings.NEXT_LINE || - braceStyle == CommonCodeStyleSettings.NEXT_LINE_IF_WRAPPED || - braceStyle == CommonCodeStyleSettings.END_OF_LINE) { - return Indent.getNoneIndent(); - } - return Indent.getNormalIndent(); - } - - private boolean isAfterCodeBlock(final int newChildIndex) { - if (newChildIndex == 0) return false; - Block blockBefore = getSubBlocks().get(newChildIndex - 1); - return blockBefore instanceof CodeBlockBlock; - } - - /** - * Note: this method is considered to be a legacy heritage and is assumed to be removed as soon as formatting processing - * is refactored - * - * @param elementType target element type - * @return null all the time - */ - @Nullable - @Override - public Wrap getReservedWrap(IElementType elementType) { - return null; - } - - /** - * Defines contract for associating operation type and particular wrap instance. I.e. given wrap object may be returned - * from subsequent {@link #getReservedWrap(IElementType)} call if given operation type is used as an argument there. - *

- * Default implementation ({@link AbstractJavaBlock#setReservedWrap(Wrap, IElementType)}) does nothing. - *

- * Note: this method is considered to be a legacy heritage and is assumed to be removed as soon as formatting processing - * is refactored - * - * @param reservedWrap reserved wrap instance - * @param operationType target operation type to associate with the given wrap instance - */ - protected void setReservedWrap(final Wrap reservedWrap, final IElementType operationType) { - } - - @Nullable - protected static ASTNode getTreeNode(final Block child2) { - if (child2 instanceof JavaBlock) { - return ((JavaBlock)child2).getFirstTreeNode(); - } - if (child2 instanceof LeafBlock) { - return ((LeafBlock)child2).getTreeNode(); - } - return null; - } - - @Override - @NotNull - public ChildAttributes getChildAttributes(final int newChildIndex) { - if (myUseChildAttributes) { - return new ChildAttributes(myChildIndent, myChildAlignment); - } - if (isAfter(newChildIndex, new IElementType[]{JavaDocElementType.DOC_COMMENT})) { - return new ChildAttributes(Indent.getNoneIndent(), myChildAlignment); - } - return super.getChildAttributes(newChildIndex); - } - - @Override - @Nullable - protected Indent getChildIndent() { - return getChildIndent(myNode, myIndentSettings); - } - - @NotNull - public CommonCodeStyleSettings getSettings() { - return mySettings; - } - - protected boolean isAfter(final int newChildIndex, @NotNull final IElementType[] elementTypes) { - if (newChildIndex == 0) return false; - final Block previousBlock = getSubBlocks().get(newChildIndex - 1); - if (!(previousBlock instanceof AbstractBlock)) return false; - final IElementType previousElementType = ((AbstractBlock)previousBlock).getNode().getElementType(); - for (IElementType elementType : elementTypes) { - if (previousElementType == elementType) return true; - } - return false; - } - - @Nullable - protected Alignment getUsedAlignment(final int newChildIndex) { - final List subBlocks = getSubBlocks(); - for (int i = 0; i < newChildIndex; i++) { - if (i >= subBlocks.size()) return null; - final Block block = subBlocks.get(i); - final Alignment alignment = block.getAlignment(); - if (alignment != null) return alignment; - } - return null; - } - - @Override - public boolean isLeaf() { - return ShiftIndentInsideHelper.mayShiftIndentInside(myNode); - } - - @Nullable - protected ASTNode composeCodeBlock(@NotNull final List result, - ASTNode child, - final Indent indent, - final int childrenIndent, - @Nullable final Wrap childWrap) { - final ArrayList localResult = new ArrayList(); - processChild(localResult, child, AlignmentStrategy.getNullStrategy(), null, Indent.getNoneIndent()); - child = child.getTreeNext(); - - AlignmentStrategy varDeclarationAlignmentStrategy - = AlignmentStrategy.createAlignmentPerTypeStrategy(VAR_DECLARATION_ELEMENT_TYPES_TO_ALIGN, JavaElementType.FIELD, true); - - while (child != null) { - // We consider that subsequent fields shouldn't be aligned if they are separated by blank line(s). - if (!FormatterUtil.containsWhiteSpacesOnly(child)) { - if (!ElementType.JAVA_COMMENT_BIT_SET.contains(child.getElementType()) && !shouldUseVarDeclarationAlignment(child)) { - // Reset var declaration alignment. - varDeclarationAlignmentStrategy = AlignmentStrategy.createAlignmentPerTypeStrategy( - VAR_DECLARATION_ELEMENT_TYPES_TO_ALIGN, JavaElementType.FIELD, true - ); - } - final boolean rBrace = isRBrace(child); - Indent childIndent = rBrace ? Indent.getNoneIndent() : getCodeBlockInternalIndent(childrenIndent, false); - if (!rBrace && child.getElementType() == JavaElementType.CODE_BLOCK - && (getBraceStyle() == CommonCodeStyleSettings.NEXT_LINE_SHIFTED - || getBraceStyle() == CommonCodeStyleSettings.NEXT_LINE_SHIFTED2)) - { - childIndent = Indent.getNormalIndent(); - } - AlignmentStrategy alignmentStrategyToUse = ALIGN_IN_COLUMNS_ELEMENT_TYPES.contains(child.getElementType()) - ? varDeclarationAlignmentStrategy : AlignmentStrategy.getNullStrategy(); - child = processChild(localResult, child, alignmentStrategyToUse, childWrap, childIndent); - if (rBrace) { - result.add(createCodeBlockBlock(localResult, indent, childrenIndent)); - return child; - } - } - - if (child != null) { - child = child.getTreeNext(); - } - } - result.add(createCodeBlockBlock(localResult, indent, childrenIndent)); - return null; - } - - /** - * Allows to answer if special 'variable declaration alignment' strategy should be used for the given node. - * I.e. given node is supposed to be parent node of sub-nodes that should be aligned 'by-columns'. - *

- * The main idea of that strategy is to provide alignment in columns like the one below: - *

-   *     public int    i   = 1;
-   *     public double ddd = 2;
-   * 
- * - * @param node node - * @return - */ - protected boolean shouldUseVarDeclarationAlignment(@NotNull ASTNode node) { - return mySettings.ALIGN_GROUP_FIELD_DECLARATIONS && ALIGN_IN_COLUMNS_ELEMENT_TYPES.contains(node.getElementType()) - && (!myAlignmentInColumnsHelper.useDifferentVarDeclarationAlignment( - node, ALIGNMENT_IN_COLUMNS_CONFIG, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS) - || compoundFieldPart(node)); - } - - /** - * Allows to answer if given node corresponds to part of composite field definition. Example: - *

- *

-   *   int i1, i2 = 2;
-   * 
- *

- * Parsing such a code produces two fields - {@code 'int i1'} and {@code 'i2 = 2'}. This method returns true - * for the second one. - * - * @param node node to check - * @return true if given node is a non-first part of composite field definition; false otherwise - */ - protected static boolean compoundFieldPart(@NotNull ASTNode node) { - if (node.getElementType() != JavaElementType.FIELD) { - return false; - } - ASTNode firstChild = node.getFirstChildNode(); - if (firstChild == null || firstChild.getElementType() != JavaTokenType.IDENTIFIER) { - return false; - } - - ASTNode prev = node.getTreePrev(); - return prev == null || !JavaJspElementType.WHITE_SPACE_BIT_SET.contains(prev.getElementType()) - || StringUtil.countNewLines(prev.getChars()) <= 1; - } - - @NotNull - public SyntheticCodeBlock createCodeBlockBlock(final List localResult, final Indent indent, final int childrenIndent) { - final SyntheticCodeBlock result = new SyntheticCodeBlock(localResult, null, getSettings(), indent, null); - result.setChildAttributes(new ChildAttributes(getCodeBlockInternalIndent(childrenIndent), null)); - return result; - } -} +/* + * 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.psi.formatter.java; + +import com.intellij.formatting.*; +import com.intellij.formatting.alignment.AlignmentInColumnsConfig; +import com.intellij.formatting.alignment.AlignmentInColumnsHelper; +import com.intellij.formatting.alignment.AlignmentStrategy; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.fileTypes.StdFileTypes; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; +import com.intellij.psi.formatter.FormatterUtil; +import com.intellij.psi.formatter.common.AbstractBlock; +import com.intellij.psi.formatter.java.wrap.JavaWrapManager; +import com.intellij.psi.formatter.java.wrap.ReservedWrapsProvider; +import com.intellij.psi.impl.source.SourceTreeToPsiMap; +import com.intellij.psi.impl.source.codeStyle.ShiftIndentInsideHelper; +import com.intellij.psi.impl.source.tree.*; +import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; +import com.intellij.psi.impl.source.tree.java.ClassElement; +import com.intellij.psi.jsp.JspElementType; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; +import com.intellij.util.text.CharArrayUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlock, ReservedWrapsProvider { + + /** + * Holds types of the elements for which 'align in column' rule may be preserved. + * + * @see CodeStyleSettings#ALIGN_GROUP_FIELD_DECLARATIONS + */ + protected static final Set ALIGN_IN_COLUMNS_ELEMENT_TYPES = Collections.unmodifiableSet(new HashSet( + Arrays.asList(JavaElementType.FIELD))); + + private static final Logger LOG = Logger.getInstance("#com.intellij.psi.formatter.java.AbstractJavaBlock"); + + /** + * Shared thread-safe config object to use during 'align in column' processing. + * + * @see CodeStyleSettings#ALIGN_GROUP_FIELD_DECLARATIONS + */ + private static final AlignmentInColumnsConfig ALIGNMENT_IN_COLUMNS_CONFIG = new AlignmentInColumnsConfig( + TokenSet.create(JavaTokenType.IDENTIFIER), JavaJspElementType.WHITE_SPACE_BIT_SET, ElementType.JAVA_COMMENT_BIT_SET, + TokenSet.create(JavaTokenType.EQ), TokenSet.create(JavaElementType.FIELD)); + + /** + * Enumerates types of variable declaration sub-elements that should be aligned in columns. + */ + private static final Set VAR_DECLARATION_ELEMENT_TYPES_TO_ALIGN = new HashSet(Arrays.asList( + JavaElementType.MODIFIER_LIST, JavaElementType.TYPE, JavaTokenType.IDENTIFIER, JavaTokenType.EQ + )); + + @NotNull protected final CommonCodeStyleSettings mySettings; + protected final CommonCodeStyleSettings.IndentOptions myIndentSettings; + private final Indent myIndent; + protected Indent myChildIndent; + protected Alignment myChildAlignment; + protected boolean myUseChildAttributes = false; + @NotNull protected final AlignmentStrategy myAlignmentStrategy; + private boolean myIsAfterClassKeyword = false; + private Wrap myAnnotationWrap = null; + + protected Alignment myReservedAlignment; + protected Alignment myReservedAlignment2; + + private final JavaWrapManager myWrapManager; + private final AlignmentInColumnsHelper myAlignmentInColumnsHelper; + + protected AbstractJavaBlock(@NotNull final ASTNode node, + final Wrap wrap, + final Alignment alignment, + final Indent indent, + @NotNull final CommonCodeStyleSettings settings) { + this(node, wrap, indent, settings, JavaWrapManager.INSTANCE, AlignmentStrategy.wrap(alignment), AlignmentInColumnsHelper.INSTANCE); + } + + protected AbstractJavaBlock(@NotNull final ASTNode node, + final Wrap wrap, + @NotNull final AlignmentStrategy alignmentStrategy, + final Indent indent, + @NotNull final CommonCodeStyleSettings settings) { + this(node, wrap, indent, settings, JavaWrapManager.INSTANCE, alignmentStrategy, AlignmentInColumnsHelper.INSTANCE); + } + + protected AbstractJavaBlock(@NotNull final ASTNode node, + final Wrap wrap, + final Indent indent, + @NotNull final CommonCodeStyleSettings settings, + final JavaWrapManager wrapManager, + @NotNull final AlignmentStrategy alignmentStrategy, + AlignmentInColumnsHelper alignmentInColumnsHelper) { + super(node, wrap, createBlockAlignment(alignmentStrategy, node)); + mySettings = settings; + myIndentSettings = settings.getIndentOptions(); + myIndent = indent; + myWrapManager = wrapManager; + myAlignmentStrategy = alignmentStrategy; + myAlignmentInColumnsHelper = alignmentInColumnsHelper; + } + + @Nullable + private static Alignment createBlockAlignment(@NotNull AlignmentStrategy strategy, @NotNull ASTNode node) { + // There is a possible case that 'implements' section is incomplete (e.g. ends with comma). We may want to align lbrace + // to the first implemented interface reference then. + if (node.getElementType() == JavaElementType.IMPLEMENTS_LIST) { + return null; + } + return strategy.getAlignment(node.getElementType()); + } + + @NotNull + public static Block createJavaBlock(@NotNull final ASTNode child, + @NotNull final CommonCodeStyleSettings settings, + @Nullable final Indent indent, + @Nullable Wrap wrap, + Alignment alignment) { + return createJavaBlock(child, settings, indent, wrap, AlignmentStrategy.wrap(alignment)); + } + + @NotNull + public static Block createJavaBlock(@NotNull final ASTNode child, + @NotNull final CommonCodeStyleSettings settings, + final Indent indent, + @Nullable Wrap wrap, + @NotNull AlignmentStrategy alignmentStrategy) { + return createJavaBlock(child, settings, indent, wrap, alignmentStrategy, -1); + } + + @NotNull + public static Block createJavaBlock(@NotNull final ASTNode child, + @NotNull final CommonCodeStyleSettings settings, + @Nullable final Indent indent, + Wrap wrap, + @NotNull AlignmentStrategy alignmentStrategy, + int startOffset) { + Indent actualIndent = indent == null ? getDefaultSubtreeIndent(child, settings.getRootSettings().getIndentOptions(StdFileTypes.JAVA)) : indent; + final IElementType elementType = child.getElementType(); + Alignment alignment = alignmentStrategy.getAlignment(elementType); + + if (child.getPsi() instanceof PsiWhiteSpace) { + String text = child.getText(); + int start = CharArrayUtil.shiftForward(text, 0, " \t\n"); + int end = CharArrayUtil.shiftBackward(text, text.length() - 1, " \t\n") + 1; + LOG.assertTrue(start < end); + return new PartialWhitespaceBlock(child, new TextRange(start + child.getStartOffset(), end + child.getStartOffset()), + wrap, alignment, actualIndent, settings); + } + if (child.getPsi() instanceof PsiClass) { + return new CodeBlockBlock(child, wrap, alignment, actualIndent, settings); + } + if (isBlockType(elementType)) { + return new BlockContainingJavaBlock(child, wrap, alignment, actualIndent, settings); + } + if (isStatement(child, child.getTreeParent())) { + return new CodeBlockBlock(child, wrap, alignment, actualIndent, settings); + } + if (child instanceof PsiComment && child instanceof PsiLanguageInjectionHost && InjectedLanguageUtil + .hasInjections((PsiLanguageInjectionHost)child)) { + return new CommentWithInjectionBlock(child, wrap, alignment, indent, settings); + } + if (child instanceof LeafElement) { + final LeafBlock block = new LeafBlock(child, wrap, alignment, actualIndent); + block.setStartOffset(startOffset); + return block; + } + else if (isLikeExtendsList(elementType)) { + return new ExtendsListBlock(child, wrap, alignmentStrategy, settings); + } + else if (elementType == JavaElementType.CODE_BLOCK) { + return new CodeBlockBlock(child, wrap, alignment, actualIndent, settings); + } + else if (elementType == JavaElementType.LABELED_STATEMENT) { + return new LabeledJavaBlock(child, wrap, alignment, actualIndent, settings); + } + else if (elementType == JavaDocElementType.DOC_COMMENT) { + return new DocCommentBlock(child, wrap, alignment, actualIndent, settings); + } + else { + final SimpleJavaBlock simpleJavaBlock = new SimpleJavaBlock(child, wrap, alignmentStrategy, actualIndent, settings); + simpleJavaBlock.setStartOffset(startOffset); + return simpleJavaBlock; + } + } + + @NotNull + public static Block createJavaBlock(@NotNull ASTNode child, @NotNull CommonCodeStyleSettings settings) { + return createJavaBlock(child, settings, getDefaultSubtreeIndent(child, settings.getRootSettings().getIndentOptions(StdFileTypes.JAVA)), + null, AlignmentStrategy.getNullStrategy()); + } + + private static boolean isLikeExtendsList(final IElementType elementType) { + return elementType == JavaElementType.EXTENDS_LIST + || elementType == JavaElementType.IMPLEMENTS_LIST + || elementType == JavaElementType.THROWS_LIST; + } + + private static boolean isBlockType(final IElementType elementType) { + return elementType == JavaElementType.SWITCH_STATEMENT + || elementType == JavaElementType.FOR_STATEMENT + || elementType == JavaElementType.WHILE_STATEMENT + || elementType == JavaElementType.DO_WHILE_STATEMENT + || elementType == JavaElementType.TRY_STATEMENT + || elementType == JavaElementType.CATCH_SECTION + || elementType == JavaElementType.IF_STATEMENT + || elementType == JavaElementType.METHOD + || elementType == JavaElementType.ARRAY_INITIALIZER_EXPRESSION + || elementType == JavaElementType.ANNOTATION_ARRAY_INITIALIZER + || elementType == JavaElementType.CLASS_INITIALIZER + || elementType == JavaElementType.SYNCHRONIZED_STATEMENT + || elementType == JavaElementType.FOREACH_STATEMENT; + } + + + @Nullable + private static Indent getDefaultSubtreeIndent(@NotNull ASTNode child, @NotNull CommonCodeStyleSettings.IndentOptions indentOptions) { + final ASTNode parent = child.getTreeParent(); + final IElementType childNodeType = child.getElementType(); + if (childNodeType == JavaElementType.ANNOTATION) { + if (parent.getPsi() instanceof PsiArrayInitializerMemberValue) { + return Indent.getNormalIndent(); + } + return Indent.getNoneIndent(); + } + + final ASTNode prevElement = FormatterUtil.getPreviousNonWhitespaceSibling(child); + if (prevElement != null && prevElement.getElementType() == JavaElementType.MODIFIER_LIST) { + return Indent.getNoneIndent(); + } + + if (childNodeType == JavaDocElementType.DOC_TAG) return Indent.getNoneIndent(); + if (childNodeType == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS) return Indent.getSpaceIndent(1); + if (child.getPsi() instanceof PsiFile) return Indent.getNoneIndent(); + if (parent != null) { + final Indent defaultChildIndent = getChildIndent(parent, indentOptions); + if (defaultChildIndent != null) return defaultChildIndent; + } + + return null; + } + + @Nullable + private static Indent getChildIndent(@NotNull ASTNode parent, @NotNull CommonCodeStyleSettings.IndentOptions indentOptions) { + final IElementType parentType = parent.getElementType(); + if (parentType == JavaElementType.MODIFIER_LIST) return Indent.getNoneIndent(); + if (parentType == JspElementType.JSP_CODE_BLOCK) return Indent.getNormalIndent(); + if (parentType == JspElementType.JSP_CLASS_LEVEL_DECLARATION_STATEMENT) return Indent.getNormalIndent(); + if (parentType == TokenType.DUMMY_HOLDER) return Indent.getNoneIndent(); + if (parentType == JavaElementType.CLASS) return Indent.getNoneIndent(); + if (parentType == JavaElementType.IF_STATEMENT) return Indent.getNoneIndent(); + if (parentType == JavaElementType.TRY_STATEMENT) return Indent.getNoneIndent(); + if (parentType == JavaElementType.CATCH_SECTION) return Indent.getNoneIndent(); + if (parentType == JavaElementType.FOR_STATEMENT) return Indent.getNoneIndent(); + if (parentType == JavaElementType.FOREACH_STATEMENT) return Indent.getNoneIndent(); + if (parentType == JavaElementType.BLOCK_STATEMENT) return Indent.getNoneIndent(); + if (parentType == JavaElementType.DO_WHILE_STATEMENT) return Indent.getNoneIndent(); + if (parentType == JavaElementType.WHILE_STATEMENT) return Indent.getNoneIndent(); + if (parentType == JavaElementType.SWITCH_STATEMENT) return Indent.getNoneIndent(); + if (parentType == JavaElementType.METHOD) return Indent.getNoneIndent(); + if (parentType == JavaDocElementType.DOC_COMMENT) return Indent.getNoneIndent(); + if (parentType == JavaDocElementType.DOC_TAG) return Indent.getNoneIndent(); + if (parentType == JavaDocElementType.DOC_INLINE_TAG) return Indent.getNoneIndent(); + if (parentType == JavaElementType.IMPORT_LIST) return Indent.getNoneIndent(); + if (parentType == JavaElementType.FIELD) return Indent.getContinuationWithoutFirstIndent(indentOptions.USE_RELATIVE_INDENTS); + if (parentType == JavaElementType.EXPRESSION_STATEMENT) return Indent.getNoneIndent(); + if (SourceTreeToPsiMap.treeElementToPsi(parent) instanceof PsiFile) { + return Indent.getNoneIndent(); + } + return null; + } + + protected static boolean isRBrace(@NotNull final ASTNode child) { + return child.getElementType() == JavaTokenType.RBRACE; + } + + @Nullable + @Override + public Spacing getSpacing(Block child1, @NotNull Block child2) { + return JavaSpacePropertyProcessor.getSpacing(getTreeNode(child2), mySettings); + } + + @Override + public ASTNode getFirstTreeNode() { + return myNode; + } + + @Override + public Indent getIndent() { + return myIndent; + } + + protected static boolean isStatement(final ASTNode child, @Nullable final ASTNode parentNode) { + if (parentNode != null) { + final IElementType parentType = parentNode.getElementType(); + if (parentType == JavaElementType.CODE_BLOCK) return false; + final int role = ((CompositeElement)parentNode).getChildRole(child); + if (parentType == JavaElementType.IF_STATEMENT) return role == ChildRole.THEN_BRANCH || role == ChildRole.ELSE_BRANCH; + if (parentType == JavaElementType.FOR_STATEMENT) return role == ChildRole.LOOP_BODY; + if (parentType == JavaElementType.WHILE_STATEMENT) return role == ChildRole.LOOP_BODY; + if (parentType == JavaElementType.DO_WHILE_STATEMENT) return role == ChildRole.LOOP_BODY; + if (parentType == JavaElementType.FOREACH_STATEMENT) return role == ChildRole.LOOP_BODY; + } + return false; + } + + @Nullable + protected Wrap createChildWrap() { + return myWrapManager.createChildBlockWrap(this, getSettings(), this); + } + + @Nullable + protected Alignment createChildAlignment() { + IElementType nodeType = myNode.getElementType(); + if (nodeType == JavaElementType.POLYADIC_EXPRESSION) nodeType = JavaElementType.BINARY_EXPRESSION; + if (nodeType == JavaElementType.ASSIGNMENT_EXPRESSION) { + if (myNode.getTreeParent() != null + && myNode.getTreeParent().getElementType() == JavaElementType.ASSIGNMENT_EXPRESSION + && myAlignment != null) { + return myAlignment; + } + return createAlignment(mySettings.ALIGN_MULTILINE_ASSIGNMENT, null); + } + if (nodeType == JavaElementType.PARENTH_EXPRESSION) { + return createAlignment(mySettings.ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION, null); + } + if (nodeType == JavaElementType.CONDITIONAL_EXPRESSION) { + return createAlignment(mySettings.ALIGN_MULTILINE_TERNARY_OPERATION, null); + } + if (nodeType == JavaElementType.FOR_STATEMENT) { + return createAlignment(mySettings.ALIGN_MULTILINE_FOR, null); + } + if (nodeType == JavaElementType.EXTENDS_LIST || nodeType == JavaElementType.IMPLEMENTS_LIST) { + return createAlignment(mySettings.ALIGN_MULTILINE_EXTENDS_LIST, null); + } + if (nodeType == JavaElementType.THROWS_LIST) { + return createAlignment(mySettings.ALIGN_MULTILINE_THROWS_LIST, null); + } + if (nodeType == JavaElementType.PARAMETER_LIST) { + return createAlignment(mySettings.ALIGN_MULTILINE_PARAMETERS, null); + } + if (nodeType == JavaElementType.RESOURCE_LIST) { + return createAlignment(mySettings.ALIGN_MULTILINE_RESOURCES, null); + } + if (nodeType == JavaElementType.BINARY_EXPRESSION) { + Alignment defaultAlignment = null; + if (shouldInheritAlignment()) { + defaultAlignment = myAlignment; + } + return createAlignment(mySettings.ALIGN_MULTILINE_BINARY_OPERATION, defaultAlignment); + } + if (nodeType == JavaElementType.CLASS || nodeType == JavaElementType.METHOD) { + return Alignment.createAlignment(); + } + return null; + } + + @Nullable + protected Alignment createChildAlignment2(@Nullable Alignment base) { + final IElementType nodeType = myNode.getElementType(); + if (nodeType == JavaElementType.CONDITIONAL_EXPRESSION) { + return base == null ? createAlignment(mySettings.ALIGN_MULTILINE_TERNARY_OPERATION, null) : createAlignment(base, mySettings.ALIGN_MULTILINE_TERNARY_OPERATION, null); + } + return null; + } + + @Nullable + protected Alignment chooseAlignment(@Nullable Alignment alignment, @Nullable Alignment alignment2, @NotNull ASTNode child) { + if (preferSlaveAlignment(child)) { + return alignment2; + } + return alignment; + } + + private boolean preferSlaveAlignment(@NotNull final ASTNode child) { + final IElementType nodeType = myNode.getElementType(); + + if (nodeType == JavaElementType.CONDITIONAL_EXPRESSION) { + IElementType childType = child.getElementType(); + return childType == JavaTokenType.QUEST || childType ==JavaTokenType.COLON; + } + else { + return false; + } + } + + private boolean shouldInheritAlignment() { + if (myNode instanceof PsiPolyadicExpression) { + final ASTNode treeParent = myNode.getTreeParent(); + if (treeParent instanceof PsiPolyadicExpression) { + return JavaFormatterUtil.areSamePriorityBinaryExpressions(myNode, treeParent); + } + } + return false; + } + + + @Nullable + protected ASTNode processChild(@NotNull final List result, + @NotNull ASTNode child, + Alignment defaultAlignment, + final Wrap defaultWrap, + final Indent childIndent) { + return processChild(result, child, AlignmentStrategy.wrap(defaultAlignment), defaultWrap, childIndent, -1); + } + + @Nullable + protected ASTNode processChild(@NotNull final List result, + @NotNull ASTNode child, + @NotNull AlignmentStrategy alignmentStrategy, + @Nullable final Wrap defaultWrap, + final Indent childIndent) { + return processChild(result, child, alignmentStrategy, defaultWrap, childIndent, -1); + } + + @Nullable + protected ASTNode processChild(@NotNull final List result, + @NotNull ASTNode child, + @NotNull AlignmentStrategy alignmentStrategy, + final Wrap defaultWrap, + final Indent childIndent, + int childOffset) { + final IElementType childType = child.getElementType(); + if (childType == JavaTokenType.CLASS_KEYWORD || childType == JavaTokenType.INTERFACE_KEYWORD) { + myIsAfterClassKeyword = true; + } + if (childType == JavaElementType.METHOD_CALL_EXPRESSION) { + result.add(createMethodCallExpressionBlock(child, + arrangeChildWrap(child, defaultWrap), + arrangeChildAlignment(child, alignmentStrategy))); + } + else { + IElementType nodeType = myNode.getElementType(); + if (nodeType == JavaElementType.POLYADIC_EXPRESSION) nodeType = JavaElementType.BINARY_EXPRESSION; + + if (childType == JavaTokenType.LBRACE && nodeType == JavaElementType.ARRAY_INITIALIZER_EXPRESSION) { + final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.ARRAY_INITIALIZER_WRAP), false); + child = processParenthesisBlock(JavaTokenType.LBRACE, JavaTokenType.RBRACE, + result, + child, + WrappingStrategy.createDoNotWrapCommaStrategy(wrap), + mySettings.ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION); + } + else if (childType == JavaTokenType.LBRACE && nodeType == JavaElementType.ANNOTATION_ARRAY_INITIALIZER) { + final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.ARRAY_INITIALIZER_WRAP), false); + child = processParenthesisBlock(JavaTokenType.LBRACE, JavaTokenType.RBRACE, + result, + child, + WrappingStrategy.createDoNotWrapCommaStrategy(wrap), + mySettings.ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION); + } + else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.EXPRESSION_LIST) { + final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.CALL_PARAMETERS_WRAP), false); + if (mySettings.PREFER_PARAMETERS_WRAP) { + wrap.ignoreParentWraps(); + } + child = processParenthesisBlock(result, + child, + WrappingStrategy.createDoNotWrapCommaStrategy(wrap), + mySettings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS); + } + else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.PARAMETER_LIST) { + final Wrap wrap; + Wrap reservedWrap = getReservedWrap(JavaElementType.MODIFIER_LIST); + // There is a possible case that particular annotated method definition is too long. We may wrap either after annotation + // or after opening lbrace then. Our strategy is to wrap after annotation whenever possible. + if (reservedWrap == null) { + wrap = Wrap.createWrap(getWrapType(mySettings.METHOD_PARAMETERS_WRAP), false); + } + else { + wrap = Wrap.createChildWrap(reservedWrap, getWrapType(mySettings.METHOD_PARAMETERS_WRAP), false); + } + child = processParenthesisBlock(result, child, + WrappingStrategy.createDoNotWrapCommaStrategy(wrap), + mySettings.ALIGN_MULTILINE_PARAMETERS); + } + else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.RESOURCE_LIST) { + final Wrap reservedWrap = getReservedWrap(JavaElementType.MODIFIER_LIST); + final Wrap wrap = reservedWrap != null + ? Wrap.createChildWrap(reservedWrap, getWrapType(mySettings.RESOURCE_LIST_WRAP), false) + : Wrap.createWrap(getWrapType(mySettings.RESOURCE_LIST_WRAP), false); + child = processParenthesisBlock(result, child, WrappingStrategy.createDoNotWrapCommaStrategy(wrap), + mySettings.ALIGN_MULTILINE_RESOURCES); + } + else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.ANNOTATION_PARAMETER_LIST) { + final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.CALL_PARAMETERS_WRAP), false); + child = processParenthesisBlock(result, child, + WrappingStrategy.createDoNotWrapCommaStrategy(wrap), + mySettings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS); + } + else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.PARENTH_EXPRESSION) { + child = processParenthesisBlock(result, child, + WrappingStrategy.DO_NOT_WRAP, + mySettings.ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION); + } + else if (childType == JavaElementType.ENUM_CONSTANT && myNode instanceof ClassElement) { + child = processEnumBlock(result, child, ((ClassElement)myNode).findEnumConstantListDelimiterPlace()); + } + else if (mySettings.TERNARY_OPERATION_SIGNS_ON_NEXT_LINE && isTernaryOperationSign(child)) { + child = processTernaryOperationRange(result, child, defaultWrap, childIndent); + } + else if (childType == JavaElementType.FIELD) { + child = processField(result, child, alignmentStrategy, defaultWrap, childIndent); + } + else if (childType == JavaElementType.LOCAL_VARIABLE + || childType == JavaElementType.DECLARATION_STATEMENT && myNode.getElementType() == JavaElementType.METHOD) + { + result.add(new SimpleJavaBlock(child, defaultWrap, alignmentStrategy, childIndent, mySettings)); + } + else { + AlignmentStrategy alignmentStrategyToUse = AlignmentStrategy.wrap(arrangeChildAlignment(child, alignmentStrategy)); + if (myAlignmentStrategy.getAlignment(nodeType, childType) != null + && (nodeType == JavaElementType.IMPLEMENTS_LIST || nodeType == JavaElementType.CLASS)) + { + alignmentStrategyToUse = myAlignmentStrategy; + } + final Block block = createJavaBlock( + child, mySettings, childIndent, arrangeChildWrap(child, defaultWrap), alignmentStrategyToUse, childOffset + ); + + if (childType == JavaElementType.MODIFIER_LIST && containsAnnotations(child)) { + myAnnotationWrap = Wrap.createWrap(getWrapType(getAnnotationWrapType(child)), true); + } + + if (block instanceof AbstractJavaBlock) { + final AbstractJavaBlock javaBlock = (AbstractJavaBlock)block; + if (nodeType == JavaElementType.METHOD_CALL_EXPRESSION && childType == JavaElementType.REFERENCE_EXPRESSION + || nodeType == JavaElementType.REFERENCE_EXPRESSION && childType == JavaElementType.METHOD_CALL_EXPRESSION) + { + javaBlock.setReservedWrap(getReservedWrap(nodeType), nodeType); + javaBlock.setReservedWrap(getReservedWrap(childType), childType); + } + else if (nodeType == JavaElementType.BINARY_EXPRESSION) { + javaBlock.setReservedWrap(defaultWrap, nodeType); + } + else if (childType == JavaElementType.MODIFIER_LIST) { + javaBlock.setReservedWrap(myAnnotationWrap, JavaElementType.MODIFIER_LIST); + if (!lastChildIsAnnotation(child)) { + myAnnotationWrap = null; + } + } + else if (childType == JavaElementType.PARAMETER_LIST && nodeType == JavaElementType.METHOD) { + // We prefer wrapping after method annotation to wrapping method parameter list, hence, deliver target wrap object + // to child block if necessary. + if (!result.isEmpty()) { + Block firstChildBlock = result.get(0); + if (firstChildBlock instanceof AbstractJavaBlock) { + AbstractJavaBlock childJavaBlock = (AbstractJavaBlock)firstChildBlock; + if (firstChildIsAnnotation(childJavaBlock.getNode())) { + javaBlock.setReservedWrap(childJavaBlock.getReservedWrap(JavaElementType.MODIFIER_LIST), JavaElementType.MODIFIER_LIST); + } + } + } + } + } + + result.add(block); + } + } + + + return child; + } + + private ASTNode processField(@NotNull final List result, + ASTNode child, + @NotNull final AlignmentStrategy alignmentStrategy, + final Wrap defaultWrap, + final Indent childIndent) { + ASTNode lastFieldInGroup = findLastFieldInGroup(child); + if (lastFieldInGroup == child) { + result.add(createJavaBlock(child, getSettings(), childIndent, arrangeChildWrap(child, defaultWrap), alignmentStrategy)); + return child; + } + else { + final ArrayList localResult = new ArrayList(); + while (child != null) { + if (!FormatterUtil.containsWhiteSpacesOnly(child)) { + localResult.add(createJavaBlock(child, + getSettings(), + Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS), + arrangeChildWrap(child, defaultWrap), + alignmentStrategy) + ); + } + if (child == lastFieldInGroup) break; + + child = child.getTreeNext(); + } + if (!localResult.isEmpty()) { + result.add(new SyntheticCodeBlock(localResult, null, getSettings(), childIndent, null)); + } + return lastFieldInGroup; + } + } + + /** + * Serves for processing composite field definitions as a single formatting block. + *

+ * 'Composite field definition' looks like {@code 'int i1, i2 = 2'}. It produces two nodes of type + * {@link JavaElementType#FIELD} - {@code 'int i1'} and {@code 'i2 = 2'}. This method returns the second node if the first one + * is given (the given node is returned for 'single' fields). + * + * @param child child field node to check + * @return last child field node at the field group identified by the given node if any; given child otherwise + */ + @NotNull + private static ASTNode findLastFieldInGroup(@NotNull final ASTNode child) { + PsiElement psi = child.getPsi(); + if (psi == null) { + return child; + } + final PsiTypeElement typeElement = ((PsiVariable)psi).getTypeElement(); + if (typeElement == null) return child; + + ASTNode lastChildNode = child.getLastChildNode(); + if (lastChildNode == null) return child; + + if (lastChildNode.getElementType() == JavaTokenType.SEMICOLON) return child; + + ASTNode currentResult = child; + ASTNode currentNode = child.getTreeNext(); + + while (currentNode != null) { + if (currentNode.getElementType() == TokenType.WHITE_SPACE + || currentNode.getElementType() == JavaTokenType.COMMA + || StdTokenSets.COMMENT_BIT_SET.contains(currentNode.getElementType())) { + } + else if (currentNode.getElementType() == JavaElementType.FIELD) { + if (compoundFieldPart(currentNode)) { + currentResult = currentNode; + } + else { + return currentResult; + } + } + else { + return currentResult; + } + + currentNode = currentNode.getTreeNext(); + } + return currentResult; + } + + @Nullable + private ASTNode processTernaryOperationRange(@NotNull final List result, + @NotNull final ASTNode child, + final Wrap defaultWrap, + final Indent childIndent) { + final ArrayList localResult = new ArrayList(); + final Wrap wrap = arrangeChildWrap(child, defaultWrap); + final Alignment alignment = myReservedAlignment; + final Alignment alignment2 = myReservedAlignment2; + localResult.add(new LeafBlock(child, wrap, chooseAlignment(alignment, alignment2, child), childIndent)); + + ASTNode current = child.getTreeNext(); + while (current != null) { + if (!FormatterUtil.containsWhiteSpacesOnly(current) && current.getTextLength() > 0) { + if (isTernaryOperationSign(current)) break; + current = processChild(localResult, current, chooseAlignment(alignment, alignment2, current), defaultWrap, childIndent); + } + if (current != null) { + current = current.getTreeNext(); + } + } + + result.add(new SyntheticCodeBlock(localResult, chooseAlignment(alignment, alignment2, child), getSettings(), null, wrap)); + + if (current == null) { + return null; + } + return current.getTreePrev(); + } + + private boolean isTernaryOperationSign(@NotNull final ASTNode child) { + if (myNode.getElementType() != JavaElementType.CONDITIONAL_EXPRESSION) return false; + final int role = ((CompositeElement)child.getTreeParent()).getChildRole(child); + return role == ChildRole.OPERATION_SIGN || role == ChildRole.COLON; + } + + @NotNull + private Block createMethodCallExpressionBlock(@NotNull final ASTNode node, final Wrap blockWrap, final Alignment alignment) { + final ArrayList nodes = new ArrayList(); + final ArrayList subBlocks = new ArrayList(); + collectNodes(nodes, node); + + final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.METHOD_CALL_CHAIN_WRAP), false); + + // We use this alignment object to align chained method calls to the first method invocation place if necessary (see IDEA-30369) + Alignment chainedCallsAlignment = createAlignment(mySettings.ALIGN_MULTILINE_CHAINED_METHODS, null); + + // We want to align chained method calls only if method target is explicitly specified, i.e. we don't want to align methods + // chain like 'recursive().recursive().recursive()' but want to align calls like 'foo.recursive().recursive().recursive()' + boolean callPointDefined = false; + List lookAheadNodes = null; + boolean afterIdentifier = false; + + while (!nodes.isEmpty() || lookAheadNodes != null) { + final List subNodes; + if (lookAheadNodes == null) { + subNodes = readToNextDot(nodes); + } + else { + subNodes = new ArrayList(lookAheadNodes); + lookAheadNodes = null; + } + Alignment alignmentToUseForSubBlock = null; + + // Just create a no-aligned sub-block if we don't need to bother with it's alignment (either due to end-user + // setup or sub-block state). + if (chainedCallsAlignment == null || subNodes.isEmpty()) { + subBlocks.add(createSyntheticBlock(subNodes, wrap, alignmentToUseForSubBlock)); + continue; + } + + IElementType lastNodeType = subNodes.get(subNodes.size() - 1).getElementType(); + boolean currentSubBlockIsMethodCall = lastNodeType == JavaElementType.EXPRESSION_LIST; + + // Update information about chained method alignment point if necessary. I.e. we want to align only continuous method calls + // like 'foo.bar().bar().bar()' but not 'foo.bar().foo.bar()' + if (callPointDefined && !currentSubBlockIsMethodCall) { + chainedCallsAlignment = createAlignment(mySettings.ALIGN_MULTILINE_CHAINED_METHODS, null); + } + callPointDefined |= !currentSubBlockIsMethodCall; + + // We want to align method call only if call target is defined for the first chained method and current block is a method call. + if (callPointDefined && currentSubBlockIsMethodCall) { + alignmentToUseForSubBlock = chainedCallsAlignment; + } + else if (afterIdentifier && lastNodeType == JavaTokenType.IDENTIFIER) { + // Align method call to the last field access. Example: + // MyClass.staticField + // .foo(); + lookAheadNodes = readToNextDot(nodes); + if (!lookAheadNodes.isEmpty() && lookAheadNodes.get(lookAheadNodes.size() - 1).getElementType() == JavaElementType.EXPRESSION_LIST) { + alignmentToUseForSubBlock = chainedCallsAlignment; + } + } + afterIdentifier = lastNodeType == JavaTokenType.IDENTIFIER; + subBlocks.add(createSyntheticBlock(subNodes, wrap, alignmentToUseForSubBlock)); + } + + return new SyntheticCodeBlock(subBlocks, alignment, mySettings, + Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS), blockWrap); + } + + @NotNull + private Block createSyntheticBlock(@NotNull final List subNodes, final Wrap wrap, @Nullable final Alignment alignment) { + final ArrayList subBlocks = new ArrayList(); + final ASTNode firstNode = subNodes.get(0); + if (firstNode.getElementType() == JavaTokenType.DOT) { + subBlocks.add(createJavaBlock(firstNode, getSettings(), Indent.getNoneIndent(), null, AlignmentStrategy.getNullStrategy())); + subNodes.remove(0); + if (!subNodes.isEmpty()) { + subBlocks.add(createSyntheticBlock(subNodes, wrap, null)); + } + return new SyntheticCodeBlock(subBlocks, alignment, mySettings, + Indent.getContinuationIndent(myIndentSettings.USE_RELATIVE_INDENTS), wrap); + } + return new SyntheticCodeBlock(createJavaBlocks(subNodes), alignment, mySettings, + Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS), null); + } + + @NotNull + private List createJavaBlocks(@NotNull final List subNodes) { + final ArrayList result = new ArrayList(); + for (ASTNode node : subNodes) { + result.add(createJavaBlock(node, getSettings(), Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS), null, + AlignmentStrategy.getNullStrategy())); + } + return result; + } + + @NotNull + private static List readToNextDot(@NotNull List nodes) { + final ArrayList result = new ArrayList(); + result.add(nodes.remove(0)); + for (Iterator iterator = nodes.iterator(); iterator.hasNext();) { + ASTNode node = iterator.next(); + if (node.getElementType() == JavaTokenType.DOT) break; + result.add(node); + iterator.remove(); + } + return result; + } + + private static void collectNodes(@NotNull List nodes, @NotNull ASTNode node) { + ASTNode child = node.getFirstChildNode(); + while (child != null) { + if (!FormatterUtil.containsWhiteSpacesOnly(child)) { + if (child.getElementType() == JavaElementType.METHOD_CALL_EXPRESSION || child.getElementType() == + JavaElementType + .REFERENCE_EXPRESSION) { + collectNodes(nodes, child); + } + else { + nodes.add(child); + } + } + child = child.getTreeNext(); + } + } + + private static boolean firstChildIsAnnotation(@NotNull final ASTNode child) { + ASTNode current = child.getFirstChildNode(); + while (current != null && current.getElementType() == TokenType.WHITE_SPACE) { + current = current.getTreeNext(); + } + return current != null && current.getElementType() == JavaElementType.ANNOTATION; + } + + private static boolean lastChildIsAnnotation(@NotNull final ASTNode child) { + ASTNode current = child.getLastChildNode(); + while (current != null && current.getElementType() == TokenType.WHITE_SPACE) { + current = current.getTreePrev(); + } + return current != null && current.getElementType() == JavaElementType.ANNOTATION; + } + + private static boolean containsAnnotations(@NotNull final ASTNode child) { + PsiElement psi = child.getPsi(); + return psi instanceof PsiModifierList && ((PsiModifierList)psi).getAnnotations().length > 0; + } + + private int getAnnotationWrapType(@NotNull ASTNode child) { + final IElementType nodeType = myNode.getElementType(); + if (nodeType == JavaElementType.METHOD) { + return mySettings.METHOD_ANNOTATION_WRAP; + } + if (nodeType == JavaElementType.CLASS) { + // There is a possible case that current document state is invalid from language syntax point of view, e.g. the user starts + // typing field definition and re-formatting is triggered by 'auto insert javadoc' processing. Example: + // class Test { + // @NotNull Object + // } + // Here '@NotNull' has a 'class' node as a parent but we want to use field annotation setting value. Hence, we check if subsequent + // parsed info is valid. + for (ASTNode node = child.getTreeNext(); node != null; node = node.getTreeNext()) { + if (TokenType.WHITE_SPACE == node.getElementType() || node instanceof PsiTypeElement) { + continue; + } + if (node instanceof PsiErrorElement) { + return mySettings.FIELD_ANNOTATION_WRAP; + } + } + return mySettings.CLASS_ANNOTATION_WRAP; + } + if (nodeType == JavaElementType.FIELD) { + return mySettings.FIELD_ANNOTATION_WRAP; + } + if (nodeType == JavaElementType.PARAMETER) { + return mySettings.PARAMETER_ANNOTATION_WRAP; + } + if (nodeType == JavaElementType.LOCAL_VARIABLE) { + return mySettings.VARIABLE_ANNOTATION_WRAP; + } + return CommonCodeStyleSettings.DO_NOT_WRAP; + } + + @Nullable + private Alignment arrangeChildAlignment(@NotNull final ASTNode child, @NotNull final AlignmentStrategy alignmentStrategy) { + int role = getChildRole(child); + final IElementType nodeType = myNode.getElementType(); + Alignment defaultAlignment = alignmentStrategy.getAlignment(child.getElementType()); + + if (nodeType == JavaElementType.FOR_STATEMENT) { + if (role == ChildRole.FOR_INITIALIZATION || role == ChildRole.CONDITION || role == ChildRole.FOR_UPDATE) { + return defaultAlignment; + } + return null; + } + else if (nodeType == JavaElementType.EXTENDS_LIST || nodeType == JavaElementType.IMPLEMENTS_LIST) { + if (role == ChildRole.REFERENCE_IN_LIST || role == ChildRole.IMPLEMENTS_KEYWORD) { + return defaultAlignment; + } + return null; + } + else if (nodeType == JavaElementType.THROWS_LIST) { + if (role == ChildRole.REFERENCE_IN_LIST) { + return defaultAlignment; + } + return null; + } + else if (nodeType == JavaElementType.CLASS) { + if (role == ChildRole.CLASS_OR_INTERFACE_KEYWORD) return defaultAlignment; + if (myIsAfterClassKeyword) return null; + if (role == ChildRole.MODIFIER_LIST) return defaultAlignment; + return null; + } + else if (ALIGN_IN_COLUMNS_ELEMENT_TYPES.contains(nodeType)) { + return getVariableDeclarationSubElementAlignment(child); + } + else if (nodeType == JavaElementType.METHOD) { + if (role == ChildRole.MODIFIER_LIST) return defaultAlignment; + if (role == ChildRole.TYPE_PARAMETER_LIST) return defaultAlignment; + if (role == ChildRole.TYPE) return defaultAlignment; + if (role == ChildRole.NAME) return defaultAlignment; + if (role == ChildRole.THROWS_LIST && mySettings.ALIGN_THROWS_KEYWORD) return defaultAlignment; + return null; + } + + else if (nodeType == JavaElementType.ASSIGNMENT_EXPRESSION) { + if (role == ChildRole.LOPERAND) return defaultAlignment; + if (role == ChildRole.ROPERAND && child.getElementType() == JavaElementType.ASSIGNMENT_EXPRESSION) { + return defaultAlignment; + } + return null; + } + + else if (child.getElementType() == JavaTokenType.END_OF_LINE_COMMENT) { + ASTNode previous = child.getTreePrev(); + // There is a special case - comment block that is located at the very start of the line. We don't reformat such a blocks, + // hence, no alignment should be applied to them in order to avoid subsequent blocks aligned with the same alignment to + // be located at the left editor edge as well. + if (previous != null && previous.getElementType() == TokenType.WHITE_SPACE && previous.getChars().length() > 0 + && previous.getChars().charAt(previous.getChars().length() - 1) == '\n') { + return null; + } + return defaultAlignment; + } + + else if (nodeType == JavaElementType.MODIFIER_LIST) { + // There is a possible case that modifier list contains from more than one elements, e.g. 'private final'. It's also possible + // that the list is aligned. We want to apply alignment rule only to the first element then. + ASTNode previous = child.getTreePrev(); + if (previous == null || previous.getTreeParent() != myNode) { + return defaultAlignment; + } + return null; + } + + else { + return defaultAlignment; + } + } + + private static int getChildRole(@NotNull ASTNode child) { + return ((CompositeElement)child.getTreeParent()).getChildRole(child); + } + + /** + * Encapsulates alignment retrieval logic for variable declaration use-case assuming that given node is a child node + * of basic variable declaration node. + * + * @param child variable declaration child node which alignment is to be defined + * @return alignment to use for the given node + * @see CodeStyleSettings#ALIGN_GROUP_FIELD_DECLARATIONS + */ + @Nullable + private Alignment getVariableDeclarationSubElementAlignment(@NotNull ASTNode child) { + // The whole idea of variable declarations alignment is that complete declaration blocks which children are to be aligned hold + // reference to the same AlignmentStrategy object, hence, reuse the same Alignment objects. So, there is no point in checking + // if it's necessary to align sub-blocks if shared strategy is not defined. + if (!mySettings.ALIGN_GROUP_FIELD_DECLARATIONS) { + return null; + } + + IElementType childType = child.getElementType(); + + // We don't want to align subsequent identifiers in single-line declarations like 'int i1, i2, i3'. I.e. only 'i1' + // should be aligned then. + ASTNode previousNode = FormatterUtil.getPreviousNonWhitespaceSibling(child); + if (childType == JavaTokenType.IDENTIFIER && (previousNode == null || previousNode.getElementType() == JavaTokenType.COMMA)) { + return null; + } + + return myAlignmentStrategy.getAlignment(childType); + } + + /* + private boolean isAfterClassKeyword(final ASTNode child) { + ASTNode treePrev = child.getTreePrev(); + while (treePrev != null) { + if (treePrev.getElementType() == ElementType.CLASS_KEYWORD || + treePrev.getElementType() == ElementType.INTERFACE_KEYWORD) { + return true; + } + treePrev = treePrev.getTreePrev(); + } + return false; + } + + */ + + @Nullable + private static Alignment createAlignment(final boolean alignOption, @Nullable final Alignment defaultAlignment) { + return alignOption ? createAlignmentOrDefault(null, defaultAlignment) : defaultAlignment; + } + + @Nullable + private static Alignment createAlignment(Alignment base, final boolean alignOption, @Nullable final Alignment defaultAlignment) { + return alignOption ? createAlignmentOrDefault(base, defaultAlignment) : defaultAlignment; + } + + @Nullable + protected Wrap arrangeChildWrap(final ASTNode child, Wrap defaultWrap) { + if (myAnnotationWrap != null) { + try { + return myAnnotationWrap; + } + finally { + myAnnotationWrap = null; + } + } + return myWrapManager.arrangeChildWrap(child, myNode, getSettings(), defaultWrap, this); + } + + @NotNull + private static WrapType getWrapType(final int wrap) { + switch (wrap) { + case CommonCodeStyleSettings.WRAP_ALWAYS: + return WrapType.ALWAYS; + case CommonCodeStyleSettings.WRAP_AS_NEEDED: + return WrapType.NORMAL; + case CommonCodeStyleSettings.DO_NOT_WRAP: + return WrapType.NONE; + default: + return WrapType.CHOP_DOWN_IF_LONG; + } + } + + @NotNull + private ASTNode processParenthesisBlock(@NotNull List result, + @NotNull ASTNode child, + @NotNull WrappingStrategy wrappingStrategy, + final boolean doAlign) { + + myUseChildAttributes = true; + + final IElementType from = JavaTokenType.LPARENTH; + final IElementType to = JavaTokenType.RPARENTH; + + return processParenthesisBlock(from, to, result, child, wrappingStrategy, doAlign); + } + + + @NotNull + private ASTNode processParenthesisBlock(@NotNull IElementType from, + @Nullable final IElementType to, + @NotNull final List result, + @NotNull ASTNode child, + @NotNull final WrappingStrategy wrappingStrategy, + final boolean doAlign) { + final Indent externalIndent = Indent.getNoneIndent(); + final Indent internalIndent = Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS); + final Indent internalIndentEnforcedToChildren = Indent.getIndent(Indent.Type.CONTINUATION, myIndentSettings.USE_RELATIVE_INDENTS, true); + AlignmentStrategy alignmentStrategy = AlignmentStrategy.wrap(createAlignment(doAlign, null), JavaTokenType.COMMA); + setChildIndent(internalIndent); + setChildAlignment(alignmentStrategy.getAlignment(null)); + boolean methodParametersBlock = true; + ASTNode lBracketParent = child.getTreeParent(); + if (lBracketParent != null) { + ASTNode methodCandidate = lBracketParent.getTreeParent(); + methodParametersBlock = methodCandidate != null && (methodCandidate.getElementType() == JavaElementType.METHOD + || methodCandidate.getElementType() == JavaElementType.METHOD_CALL_EXPRESSION); + } + Alignment bracketAlignment = methodParametersBlock && mySettings.ALIGN_MULTILINE_METHOD_BRACKETS ? Alignment.createAlignment() : null; + AlignmentStrategy anonymousClassStrategy = doAlign ? alignmentStrategy + : AlignmentStrategy.wrap(Alignment.createAlignment(), + false, + JavaTokenType.NEW_KEYWORD, + JavaElementType.NEW_EXPRESSION, + JavaTokenType.RBRACE); + setChildIndent(internalIndent); + setChildAlignment(alignmentStrategy.getAlignment(null)); + + boolean isAfterIncomplete = false; + + ASTNode prev = child; + boolean afterAnonymousClass = false; + while (child != null) { + isAfterIncomplete = isAfterIncomplete || child.getElementType() == TokenType.ERROR_ELEMENT || + child.getElementType() == JavaElementType.EMPTY_EXPRESSION; + if (!FormatterUtil.containsWhiteSpacesOnly(child) && child.getTextLength() > 0) { + if (child.getElementType() == from) { + result.add(createJavaBlock(child, mySettings, externalIndent, null, bracketAlignment)); + } + else if (child.getElementType() == to) { + result.add(createJavaBlock(child, mySettings, + isAfterIncomplete && !afterAnonymousClass ? internalIndent : externalIndent, + null, + isAfterIncomplete ? alignmentStrategy.getAlignment(null) : bracketAlignment)); + return child; + } + else { + final IElementType elementType = child.getElementType(); + final boolean enforceIndent = shouldEnforceIndentToChildren(child); + Indent indentToUse = enforceIndent ? internalIndentEnforcedToChildren : internalIndent; + AlignmentStrategy alignmentStrategyToUse = canUseAnonymousClassAlignment(child) ? anonymousClassStrategy : alignmentStrategy; + processChild(result, child, alignmentStrategyToUse.getAlignment(elementType), wrappingStrategy.getWrap(elementType), indentToUse); + if (to == null) {//process only one statement + return child; + } + } + isAfterIncomplete = false; + if (child.getElementType() != JavaTokenType.COMMA) { + afterAnonymousClass = isAnonymousClass(child); + } + } + prev = child; + child = child.getTreeNext(); + } + + return prev; + } + + private static boolean canUseAnonymousClassAlignment(@NotNull ASTNode child) { + // The general idea is to handle situations like below: + // test(new Runnable() { + // public void run() { + // } + // }, new Runnable() { + // public void run() { + // } + // } + // ); + // I.e. we want to align subsequent anonymous class argument to the previous one if it's not preceded by another argument + // at the same line, e.g.: + // test("this is a long argument", new Runnable() { + // public void run() { + // } + // }, new Runnable() { + // public void run() { + // } + // } + // ); + if (!isAnonymousClass(child)) { + return false; + } + + for (ASTNode node = child.getTreePrev(); node != null; node = node.getTreePrev()) { + if (node.getElementType() == TokenType.WHITE_SPACE) { + if (StringUtil.countNewLines(node.getChars()) > 0) { + return false; + } + } + else if (node.getElementType() == JavaTokenType.LPARENTH) { + // First method call argument. + return true; + } + else if (node.getElementType() != JavaTokenType.COMMA && !isAnonymousClass(node)) { + return false; + } + } + return true; + } + + private boolean shouldEnforceIndentToChildren(@NotNull ASTNode node) { + // Filter only anonymous class instances as method call arguments + if (myNode.getElementType() != JavaElementType.EXPRESSION_LIST) { + return false; + } + ASTNode parent = myNode.getTreeParent(); + if (parent == null || parent.getElementType() != JavaElementType.METHOD_CALL_EXPRESSION) { + return false; + } + if (!isAnonymousClass(node) || !JavaFormatterUtil.hasAnonymousClassesArguments((PsiExpressionList)myNode.getPsi(), 2)) { + return false; + } + + // Enforce indent only if anonymous class instance expression doesn't start new line and have anonymous class expression sibling. + ASTNode prev = node.getTreePrev(); + return prev != null && !(StringUtil.containsLineBreak(prev.getChars()) && prev.getElementType() != TokenType.WHITE_SPACE); + } + + private static boolean isAnonymousClass(@Nullable ASTNode node) { + if (node == null || node.getElementType() != JavaElementType.NEW_EXPRESSION) { + return false; + } + ASTNode lastChild = node.getLastChildNode(); + return lastChild != null && lastChild.getElementType() == JavaElementType.ANONYMOUS_CLASS; + } + + @Nullable + private ASTNode processEnumBlock(@NotNull List result, + @Nullable ASTNode child, + ASTNode last) + { + final WrappingStrategy wrappingStrategy = WrappingStrategy.createDoNotWrapCommaStrategy(Wrap + .createWrap(getWrapType(mySettings.ENUM_CONSTANTS_WRAP), true)); + while (child != null) { + if (!FormatterUtil.containsWhiteSpacesOnly(child) && child.getTextLength() > 0) { + result.add(createJavaBlock(child, mySettings, Indent.getNormalIndent(), + wrappingStrategy.getWrap(child.getElementType()), AlignmentStrategy.getNullStrategy())); + if (child == last) return child; + } + child = child.getTreeNext(); + } + return null; + } + + private void setChildAlignment(final Alignment alignment) { + myChildAlignment = alignment; + } + + private void setChildIndent(final Indent internalIndent) { + myChildIndent = internalIndent; + } + + @Nullable + private static Alignment createAlignmentOrDefault(@Nullable Alignment base, @Nullable final Alignment defaultAlignment) { + if (defaultAlignment == null) { + return base == null ? Alignment.createAlignment() : Alignment.createChildAlignment(base); + } + return defaultAlignment; + } + + private int getBraceStyle() { + final PsiElement psiNode = SourceTreeToPsiMap.treeElementToPsi(myNode); + if (psiNode instanceof PsiClass) { + return mySettings.CLASS_BRACE_STYLE; + } + if (psiNode instanceof PsiMethod + || psiNode instanceof PsiCodeBlock && psiNode.getParent() != null && psiNode.getParent() instanceof PsiMethod) { + return mySettings.METHOD_BRACE_STYLE; + } + return mySettings.BRACE_STYLE; + } + + protected Indent getCodeBlockInternalIndent(final int baseChildrenIndent) { + return getCodeBlockInternalIndent(baseChildrenIndent, false); + } + + protected Indent getCodeBlockInternalIndent(final int baseChildrenIndent, boolean enforceParentIndent) { + if (isTopLevelClass() && mySettings.DO_NOT_INDENT_TOP_LEVEL_CLASS_MEMBERS) { + return Indent.getNoneIndent(); + } + + final int braceStyle = getBraceStyle(); + return braceStyle == CommonCodeStyleSettings.NEXT_LINE_SHIFTED ? + createNormalIndent(baseChildrenIndent - 1, enforceParentIndent) + : createNormalIndent(baseChildrenIndent, enforceParentIndent); + } + + protected static Indent createNormalIndent(final int baseChildrenIndent) { + return createNormalIndent(baseChildrenIndent, false); + } + + protected static Indent createNormalIndent(final int baseChildrenIndent, boolean enforceIndentToChildren) { + if (baseChildrenIndent == 1) { + return Indent.getIndent(Indent.Type.NORMAL, false, enforceIndentToChildren); + } + else if (baseChildrenIndent <= 0) { + return Indent.getNoneIndent(); + } + else { + LOG.assertTrue(false); + return Indent.getIndent(Indent.Type.NORMAL, false, enforceIndentToChildren); + } + } + + private boolean isTopLevelClass() { + return myNode.getElementType() == JavaElementType.CLASS && + SourceTreeToPsiMap.treeElementToPsi(myNode.getTreeParent()) instanceof PsiFile; + } + + protected Indent getCodeBlockExternalIndent() { + final int braceStyle = getBraceStyle(); + if (braceStyle == CommonCodeStyleSettings.END_OF_LINE || braceStyle == CommonCodeStyleSettings.NEXT_LINE || + braceStyle == CommonCodeStyleSettings.NEXT_LINE_IF_WRAPPED) { + return Indent.getNoneIndent(); + } + return Indent.getNormalIndent(); + } + + protected Indent getCodeBlockChildExternalIndent(final int newChildIndex) { + final int braceStyle = getBraceStyle(); + if (!isAfterCodeBlock(newChildIndex)) { + return Indent.getNormalIndent(); + } + if (braceStyle == CommonCodeStyleSettings.NEXT_LINE || + braceStyle == CommonCodeStyleSettings.NEXT_LINE_IF_WRAPPED || + braceStyle == CommonCodeStyleSettings.END_OF_LINE) { + return Indent.getNoneIndent(); + } + return Indent.getNormalIndent(); + } + + private boolean isAfterCodeBlock(final int newChildIndex) { + if (newChildIndex == 0) return false; + Block blockBefore = getSubBlocks().get(newChildIndex - 1); + return blockBefore instanceof CodeBlockBlock; + } + + /** + * Note: this method is considered to be a legacy heritage and is assumed to be removed as soon as formatting processing + * is refactored + * + * @param elementType target element type + * @return null all the time + */ + @Nullable + @Override + public Wrap getReservedWrap(IElementType elementType) { + return null; + } + + /** + * Defines contract for associating operation type and particular wrap instance. I.e. given wrap object may be returned + * from subsequent {@link #getReservedWrap(IElementType)} call if given operation type is used as an argument there. + *

+ * Default implementation ({@link AbstractJavaBlock#setReservedWrap(Wrap, IElementType)}) does nothing. + *

+ * Note: this method is considered to be a legacy heritage and is assumed to be removed as soon as formatting processing + * is refactored + * + * @param reservedWrap reserved wrap instance + * @param operationType target operation type to associate with the given wrap instance + */ + protected void setReservedWrap(final Wrap reservedWrap, final IElementType operationType) { + } + + @Nullable + protected static ASTNode getTreeNode(final Block child2) { + if (child2 instanceof JavaBlock) { + return ((JavaBlock)child2).getFirstTreeNode(); + } + if (child2 instanceof LeafBlock) { + return ((LeafBlock)child2).getTreeNode(); + } + return null; + } + + @Override + @NotNull + public ChildAttributes getChildAttributes(final int newChildIndex) { + if (myUseChildAttributes) { + return new ChildAttributes(myChildIndent, myChildAlignment); + } + if (isAfter(newChildIndex, new IElementType[]{JavaDocElementType.DOC_COMMENT})) { + return new ChildAttributes(Indent.getNoneIndent(), myChildAlignment); + } + return super.getChildAttributes(newChildIndex); + } + + @Override + @Nullable + protected Indent getChildIndent() { + return getChildIndent(myNode, myIndentSettings); + } + + @NotNull + public CommonCodeStyleSettings getSettings() { + return mySettings; + } + + protected boolean isAfter(final int newChildIndex, @NotNull final IElementType[] elementTypes) { + if (newChildIndex == 0) return false; + final Block previousBlock = getSubBlocks().get(newChildIndex - 1); + if (!(previousBlock instanceof AbstractBlock)) return false; + final IElementType previousElementType = ((AbstractBlock)previousBlock).getNode().getElementType(); + for (IElementType elementType : elementTypes) { + if (previousElementType == elementType) return true; + } + return false; + } + + @Nullable + protected Alignment getUsedAlignment(final int newChildIndex) { + final List subBlocks = getSubBlocks(); + for (int i = 0; i < newChildIndex; i++) { + if (i >= subBlocks.size()) return null; + final Block block = subBlocks.get(i); + final Alignment alignment = block.getAlignment(); + if (alignment != null) return alignment; + } + return null; + } + + @Override + public boolean isLeaf() { + return ShiftIndentInsideHelper.mayShiftIndentInside(myNode); + } + + @Nullable + protected ASTNode composeCodeBlock(@NotNull final List result, + ASTNode child, + final Indent indent, + final int childrenIndent, + @Nullable final Wrap childWrap) { + final ArrayList localResult = new ArrayList(); + processChild(localResult, child, AlignmentStrategy.getNullStrategy(), null, Indent.getNoneIndent()); + child = child.getTreeNext(); + + AlignmentStrategy varDeclarationAlignmentStrategy + = AlignmentStrategy.createAlignmentPerTypeStrategy(VAR_DECLARATION_ELEMENT_TYPES_TO_ALIGN, JavaElementType.FIELD, true); + + while (child != null) { + // We consider that subsequent fields shouldn't be aligned if they are separated by blank line(s). + if (!FormatterUtil.containsWhiteSpacesOnly(child)) { + if (!ElementType.JAVA_COMMENT_BIT_SET.contains(child.getElementType()) && !shouldUseVarDeclarationAlignment(child)) { + // Reset var declaration alignment. + varDeclarationAlignmentStrategy = AlignmentStrategy.createAlignmentPerTypeStrategy( + VAR_DECLARATION_ELEMENT_TYPES_TO_ALIGN, JavaElementType.FIELD, true + ); + } + final boolean rBrace = isRBrace(child); + Indent childIndent = rBrace ? Indent.getNoneIndent() : getCodeBlockInternalIndent(childrenIndent, false); + if (!rBrace && child.getElementType() == JavaElementType.CODE_BLOCK + && (getBraceStyle() == CommonCodeStyleSettings.NEXT_LINE_SHIFTED + || getBraceStyle() == CommonCodeStyleSettings.NEXT_LINE_SHIFTED2)) + { + childIndent = Indent.getNormalIndent(); + } + AlignmentStrategy alignmentStrategyToUse = ALIGN_IN_COLUMNS_ELEMENT_TYPES.contains(child.getElementType()) + ? varDeclarationAlignmentStrategy : AlignmentStrategy.getNullStrategy(); + child = processChild(localResult, child, alignmentStrategyToUse, childWrap, childIndent); + if (rBrace) { + result.add(createCodeBlockBlock(localResult, indent, childrenIndent)); + return child; + } + } + + if (child != null) { + child = child.getTreeNext(); + } + } + result.add(createCodeBlockBlock(localResult, indent, childrenIndent)); + return null; + } + + /** + * Allows to answer if special 'variable declaration alignment' strategy should be used for the given node. + * I.e. given node is supposed to be parent node of sub-nodes that should be aligned 'by-columns'. + *

+ * The main idea of that strategy is to provide alignment in columns like the one below: + *

+   *     public int    i   = 1;
+   *     public double ddd = 2;
+   * 
+ * + * @param node node + * @return + */ + protected boolean shouldUseVarDeclarationAlignment(@NotNull ASTNode node) { + return mySettings.ALIGN_GROUP_FIELD_DECLARATIONS && ALIGN_IN_COLUMNS_ELEMENT_TYPES.contains(node.getElementType()) + && (!myAlignmentInColumnsHelper.useDifferentVarDeclarationAlignment( + node, ALIGNMENT_IN_COLUMNS_CONFIG, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS) + || compoundFieldPart(node)); + } + + /** + * Allows to answer if given node corresponds to part of composite field definition. Example: + *

+ *

+   *   int i1, i2 = 2;
+   * 
+ *

+ * Parsing such a code produces two fields - {@code 'int i1'} and {@code 'i2 = 2'}. This method returns true + * for the second one. + * + * @param node node to check + * @return true if given node is a non-first part of composite field definition; false otherwise + */ + protected static boolean compoundFieldPart(@NotNull ASTNode node) { + if (node.getElementType() != JavaElementType.FIELD) { + return false; + } + ASTNode firstChild = node.getFirstChildNode(); + if (firstChild == null || firstChild.getElementType() != JavaTokenType.IDENTIFIER) { + return false; + } + + ASTNode prev = node.getTreePrev(); + return prev == null || !JavaJspElementType.WHITE_SPACE_BIT_SET.contains(prev.getElementType()) + || StringUtil.countNewLines(prev.getChars()) <= 1; + } + + @NotNull + public SyntheticCodeBlock createCodeBlockBlock(final List localResult, final Indent indent, final int childrenIndent) { + final SyntheticCodeBlock result = new SyntheticCodeBlock(localResult, null, getSettings(), indent, null); + result.setChildAttributes(new ChildAttributes(getCodeBlockInternalIndent(childrenIndent), null)); + return result; + } +} diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/LeafBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/LeafBlock.java index 3cd284603f5e..f0d6406b6406 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/LeafBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/LeafBlock.java @@ -1,111 +1,111 @@ -/* - * 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.psi.formatter.java; - -import com.intellij.formatting.*; -import com.intellij.lang.ASTNode; -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.impl.source.codeStyle.ShiftIndentInsideHelper; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.List; - -public class LeafBlock implements ASTBlock{ - private int myStartOffset = -1; - private final ASTNode myNode; - private final Wrap myWrap; - private final Alignment myAlignment; - - private static final ArrayList EMPTY_SUB_BLOCKS = new ArrayList(); - private final Indent myIndent; - - public LeafBlock(final ASTNode node, - final Wrap wrap, - final Alignment alignment, - Indent indent) - { - myNode = node; - myWrap = wrap; - myAlignment = alignment; - myIndent = indent; - } - - @Override - public ASTNode getNode() { - return myNode; - } - - @Override - @NotNull - public TextRange getTextRange() { - if (myStartOffset != -1) { - return new TextRange(myStartOffset, myStartOffset + myNode.getTextLength()); - } - return myNode.getTextRange(); - } - - @Override - @NotNull - public List getSubBlocks() { - return EMPTY_SUB_BLOCKS; - } - - @Override - public Wrap getWrap() { - return myWrap; - } - - @Override - public Indent getIndent() { - return myIndent; - } - - @Override - public Alignment getAlignment() { - return myAlignment; - } - - @Override - public Spacing getSpacing(Block child1, @NotNull Block child2) { - return null; - } - - public ASTNode getTreeNode() { - return myNode; - } - - @Override - @NotNull - public ChildAttributes getChildAttributes(final int newChildIndex) { - return new ChildAttributes(getIndent(), null); - } - - @Override - public boolean isIncomplete() { - return false; - } - - @Override - public boolean isLeaf() { - return ShiftIndentInsideHelper.mayShiftIndentInside(myNode); - } - - public void setStartOffset(final int startOffset) { - myStartOffset = startOffset; - // if (startOffset != -1) assert startOffset == myNode.getTextRange().getStartOffset(); - } -} +/* + * 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.psi.formatter.java; + +import com.intellij.formatting.*; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.impl.source.codeStyle.ShiftIndentInsideHelper; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class LeafBlock implements ASTBlock{ + private int myStartOffset = -1; + private final ASTNode myNode; + private final Wrap myWrap; + private final Alignment myAlignment; + + private static final ArrayList EMPTY_SUB_BLOCKS = new ArrayList(); + private final Indent myIndent; + + public LeafBlock(final ASTNode node, + final Wrap wrap, + final Alignment alignment, + Indent indent) + { + myNode = node; + myWrap = wrap; + myAlignment = alignment; + myIndent = indent; + } + + @Override + public ASTNode getNode() { + return myNode; + } + + @Override + @NotNull + public TextRange getTextRange() { + if (myStartOffset != -1) { + return new TextRange(myStartOffset, myStartOffset + myNode.getTextLength()); + } + return myNode.getTextRange(); + } + + @Override + @NotNull + public List getSubBlocks() { + return EMPTY_SUB_BLOCKS; + } + + @Override + public Wrap getWrap() { + return myWrap; + } + + @Override + public Indent getIndent() { + return myIndent; + } + + @Override + public Alignment getAlignment() { + return myAlignment; + } + + @Override + public Spacing getSpacing(Block child1, @NotNull Block child2) { + return null; + } + + public ASTNode getTreeNode() { + return myNode; + } + + @Override + @NotNull + public ChildAttributes getChildAttributes(final int newChildIndex) { + return new ChildAttributes(getIndent(), null); + } + + @Override + public boolean isIncomplete() { + return false; + } + + @Override + public boolean isLeaf() { + return ShiftIndentInsideHelper.mayShiftIndentInside(myNode); + } + + public void setStartOffset(final int startOffset) { + myStartOffset = startOffset; + // if (startOffset != -1) assert startOffset == myNode.getTextRange().getStartOffset(); + } +} diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/SimpleJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/SimpleJavaBlock.java index 794ec4c2eea9..0a4c1054d9b3 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/SimpleJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/SimpleJavaBlock.java @@ -1,134 +1,134 @@ -/* - * 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.psi.formatter.java; - -import com.intellij.formatting.*; -import com.intellij.formatting.alignment.AlignmentStrategy; -import com.intellij.lang.ASTNode; -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiFile; -import com.intellij.psi.codeStyle.CommonCodeStyleSettings; -import com.intellij.psi.formatter.FormatterUtil; -import com.intellij.psi.impl.source.tree.JavaDocElementType; -import com.intellij.psi.impl.source.tree.JavaElementType; -import com.intellij.psi.impl.source.tree.StdTokenSets; -import com.intellij.psi.tree.IElementType; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class SimpleJavaBlock extends AbstractJavaBlock { - - private int myStartOffset = -1; - private final Map myReservedWrap = new HashMap(); - - public SimpleJavaBlock(final ASTNode node, final Wrap wrap, final AlignmentStrategy alignment, final Indent indent, CommonCodeStyleSettings settings) { - super(node, wrap, alignment, indent,settings); - } - - @Override - protected List buildChildren() { - ASTNode child = myNode.getFirstChildNode(); - int offset = myStartOffset != -1 ? myStartOffset : child != null ? child.getTextRange().getStartOffset():0; - final ArrayList result = new ArrayList(); - - Indent indent = null; - while (child != null) { - if (StdTokenSets.COMMENT_BIT_SET.contains(child.getElementType()) || child.getElementType() == JavaDocElementType.DOC_COMMENT) { - result.add(createJavaBlock(child, mySettings, Indent.getNoneIndent(), null, AlignmentStrategy.getNullStrategy())); - indent = Indent.getNoneIndent(); - } - else if (!FormatterUtil.containsWhiteSpacesOnly(child)) { - break; - } - - offset += child.getTextLength(); - child = child.getTreeNext(); - } - - myReservedAlignment = createChildAlignment(); - myReservedAlignment2 = createChildAlignment2(myReservedAlignment); - Wrap childWrap = createChildWrap(); - while (child != null) { - if (!FormatterUtil.containsWhiteSpacesOnly(child) && child.getTextLength() > 0){ - final ASTNode astNode = child; - AlignmentStrategy alignmentStrategyToUse = ALIGN_IN_COLUMNS_ELEMENT_TYPES.contains(myNode.getElementType()) - ? myAlignmentStrategy - : AlignmentStrategy.wrap(chooseAlignment(myReservedAlignment, myReservedAlignment2, child)); - child = processChild(result, astNode, alignmentStrategyToUse, childWrap, indent, offset); - if (astNode != child && child != null) { - offset = child.getTextRange().getStartOffset(); - } - if (indent != null - && !(myNode.getPsi() instanceof PsiFile) && child != null && child.getElementType() != JavaElementType.MODIFIER_LIST) - { - indent = Indent.getContinuationIndent(myIndentSettings.USE_RELATIVE_INDENTS); - } - } - if (child != null) { - offset += child.getTextLength(); - child = child.getTreeNext(); - } - } - - return result; - } - - @Override - @NotNull - public TextRange getTextRange() { - if (myStartOffset != -1) { - return new TextRange(myStartOffset, myStartOffset + myNode.getTextLength()); - } - return super.getTextRange(); - } - - @Override - @NotNull - public ChildAttributes getChildAttributes(final int newChildIndex) { - if (myNode.getElementType() == JavaElementType.CONDITIONAL_EXPRESSION && mySettings.ALIGN_MULTILINE_TERNARY_OPERATION) { - final Alignment usedAlignment = getUsedAlignment(newChildIndex); - if (usedAlignment != null) { - return new ChildAttributes(null, usedAlignment); - } else { - return super.getChildAttributes(newChildIndex); - } - } - else if (myNode.getElementType() == JavaElementType.SWITCH_LABEL_STATEMENT) { - return new ChildAttributes(Indent.getNormalIndent(), null); - } - else { - return super.getChildAttributes(newChildIndex); - } - } - - @Override - public Wrap getReservedWrap(final IElementType elementType) { - return myReservedWrap.get(elementType); - } - - @Override - protected void setReservedWrap(final Wrap reservedWrap, final IElementType operationType) { - myReservedWrap.put(operationType, reservedWrap); - } - - public void setStartOffset(final int startOffset) { - myStartOffset = startOffset; - } -} +/* + * 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.psi.formatter.java; + +import com.intellij.formatting.*; +import com.intellij.formatting.alignment.AlignmentStrategy; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiFile; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; +import com.intellij.psi.formatter.FormatterUtil; +import com.intellij.psi.impl.source.tree.JavaDocElementType; +import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.psi.impl.source.tree.StdTokenSets; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class SimpleJavaBlock extends AbstractJavaBlock { + + private int myStartOffset = -1; + private final Map myReservedWrap = new HashMap(); + + public SimpleJavaBlock(final ASTNode node, final Wrap wrap, final AlignmentStrategy alignment, final Indent indent, CommonCodeStyleSettings settings) { + super(node, wrap, alignment, indent,settings); + } + + @Override + protected List buildChildren() { + ASTNode child = myNode.getFirstChildNode(); + int offset = myStartOffset != -1 ? myStartOffset : child != null ? child.getTextRange().getStartOffset():0; + final ArrayList result = new ArrayList(); + + Indent indent = null; + while (child != null) { + if (StdTokenSets.COMMENT_BIT_SET.contains(child.getElementType()) || child.getElementType() == JavaDocElementType.DOC_COMMENT) { + result.add(createJavaBlock(child, mySettings, Indent.getNoneIndent(), null, AlignmentStrategy.getNullStrategy())); + indent = Indent.getNoneIndent(); + } + else if (!FormatterUtil.containsWhiteSpacesOnly(child)) { + break; + } + + offset += child.getTextLength(); + child = child.getTreeNext(); + } + + myReservedAlignment = createChildAlignment(); + myReservedAlignment2 = createChildAlignment2(myReservedAlignment); + Wrap childWrap = createChildWrap(); + while (child != null) { + if (!FormatterUtil.containsWhiteSpacesOnly(child) && child.getTextLength() > 0){ + final ASTNode astNode = child; + AlignmentStrategy alignmentStrategyToUse = ALIGN_IN_COLUMNS_ELEMENT_TYPES.contains(myNode.getElementType()) + ? myAlignmentStrategy + : AlignmentStrategy.wrap(chooseAlignment(myReservedAlignment, myReservedAlignment2, child)); + child = processChild(result, astNode, alignmentStrategyToUse, childWrap, indent, offset); + if (astNode != child && child != null) { + offset = child.getTextRange().getStartOffset(); + } + if (indent != null + && !(myNode.getPsi() instanceof PsiFile) && child != null && child.getElementType() != JavaElementType.MODIFIER_LIST) + { + indent = Indent.getContinuationIndent(myIndentSettings.USE_RELATIVE_INDENTS); + } + } + if (child != null) { + offset += child.getTextLength(); + child = child.getTreeNext(); + } + } + + return result; + } + + @Override + @NotNull + public TextRange getTextRange() { + if (myStartOffset != -1) { + return new TextRange(myStartOffset, myStartOffset + myNode.getTextLength()); + } + return super.getTextRange(); + } + + @Override + @NotNull + public ChildAttributes getChildAttributes(final int newChildIndex) { + if (myNode.getElementType() == JavaElementType.CONDITIONAL_EXPRESSION && mySettings.ALIGN_MULTILINE_TERNARY_OPERATION) { + final Alignment usedAlignment = getUsedAlignment(newChildIndex); + if (usedAlignment != null) { + return new ChildAttributes(null, usedAlignment); + } else { + return super.getChildAttributes(newChildIndex); + } + } + else if (myNode.getElementType() == JavaElementType.SWITCH_LABEL_STATEMENT) { + return new ChildAttributes(Indent.getNormalIndent(), null); + } + else { + return super.getChildAttributes(newChildIndex); + } + } + + @Override + public Wrap getReservedWrap(final IElementType elementType) { + return myReservedWrap.get(elementType); + } + + @Override + protected void setReservedWrap(final Wrap reservedWrap, final IElementType operationType) { + myReservedWrap.put(operationType, reservedWrap); + } + + public void setStartOffset(final int startOffset) { + myStartOffset = startOffset; + } +} diff --git a/java/java-impl/src/com/intellij/psi/impl/JavaRegExpHost.java b/java/java-impl/src/com/intellij/psi/impl/JavaRegExpHost.java index a8cfe2b010cd..6d05e6aff9dd 100644 --- a/java/java-impl/src/com/intellij/psi/impl/JavaRegExpHost.java +++ b/java/java-impl/src/com/intellij/psi/impl/JavaRegExpHost.java @@ -1,65 +1,65 @@ -/* - * 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.psi.impl; - -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtil; -import com.intellij.openapi.projectRoots.JavaSdk; -import com.intellij.openapi.projectRoots.JavaSdkVersion; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.roots.ModuleRootManager; -import org.intellij.lang.regexp.RegExpLanguageHost; -import org.intellij.lang.regexp.psi.RegExpGroup; - -/** - * @author yole - */ -public class JavaRegExpHost implements RegExpLanguageHost { - @Override - public boolean characterNeedsEscaping(char c) { - return c == ']' || c == '}'; - } - - @Override - public boolean supportsPerl5EmbeddedComments() { - return false; - } - - @Override - public boolean supportsPossessiveQuantifiers() { - return true; - } - - @Override - public boolean supportsPythonConditionalRefs() { - return false; - } - - @Override - public boolean supportsNamedGroupSyntax(RegExpGroup group) { - if (group.isRubyNamedGroup()) { - final Module module = ModuleUtil.findModuleForPsiElement(group); - if (module != null) { - final Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); - if (sdk != null && sdk.getSdkType() instanceof JavaSdk) { - final JavaSdkVersion version = JavaSdk.getInstance().getVersion(sdk); - return version != null && version.isAtLeast(JavaSdkVersion.JDK_1_7); - } - } - } - return false; - } -} +/* + * 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.psi.impl; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.projectRoots.JavaSdk; +import com.intellij.openapi.projectRoots.JavaSdkVersion; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.ModuleRootManager; +import org.intellij.lang.regexp.RegExpLanguageHost; +import org.intellij.lang.regexp.psi.RegExpGroup; + +/** + * @author yole + */ +public class JavaRegExpHost implements RegExpLanguageHost { + @Override + public boolean characterNeedsEscaping(char c) { + return c == ']' || c == '}'; + } + + @Override + public boolean supportsPerl5EmbeddedComments() { + return false; + } + + @Override + public boolean supportsPossessiveQuantifiers() { + return true; + } + + @Override + public boolean supportsPythonConditionalRefs() { + return false; + } + + @Override + public boolean supportsNamedGroupSyntax(RegExpGroup group) { + if (group.isRubyNamedGroup()) { + final Module module = ModuleUtil.findModuleForPsiElement(group); + if (module != null) { + final Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); + if (sdk != null && sdk.getSdkType() instanceof JavaSdk) { + final JavaSdkVersion version = JavaSdk.getInstance().getVersion(sdk); + return version != null && version.isAtLeast(JavaSdkVersion.JDK_1_7); + } + } + } + return false; + } +} diff --git a/java/java-impl/src/com/intellij/psi/impl/file/JavaDirectoryServiceImpl.java b/java/java-impl/src/com/intellij/psi/impl/file/JavaDirectoryServiceImpl.java index 3a5b37151950..5464c6cbd83d 100644 --- a/java/java-impl/src/com/intellij/psi/impl/file/JavaDirectoryServiceImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/file/JavaDirectoryServiceImpl.java @@ -1,219 +1,219 @@ -/* - * 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. - */ - -/* - * @author max - */ -package com.intellij.psi.impl.file; - -import com.intellij.core.CoreJavaDirectoryService; -import com.intellij.ide.fileTemplates.FileTemplate; -import com.intellij.ide.fileTemplates.FileTemplateManager; -import com.intellij.ide.fileTemplates.FileTemplateUtil; -import com.intellij.ide.fileTemplates.JavaTemplateUtil; -import com.intellij.ide.fileTemplates.ui.CreateFromTemplateDialog; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.fileTypes.StdFileTypes; -import com.intellij.openapi.module.LanguageLevelUtil; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.LanguageLevelProjectExtension; -import com.intellij.openapi.roots.ProjectFileIndex; -import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.pom.java.LanguageLevel; -import com.intellij.psi.*; -import com.intellij.psi.util.PsiUtil; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.NotNull; - -import java.util.Collections; -import java.util.Map; -import java.util.Properties; - -public class JavaDirectoryServiceImpl extends CoreJavaDirectoryService { - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.file.JavaDirectoryServiceImpl"); - - @Override - public PsiPackage getPackage(@NotNull PsiDirectory dir) { - ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(dir.getProject()).getFileIndex(); - String packageName = projectFileIndex.getPackageNameByDirectory(dir.getVirtualFile()); - if (packageName == null) return null; - return JavaPsiFacade.getInstance(dir.getProject()).findPackage(packageName); - } - - @Override - @NotNull - public PsiClass createClass(@NotNull PsiDirectory dir, @NotNull String name) throws IncorrectOperationException { - return createClassFromTemplate(dir, name, JavaTemplateUtil.INTERNAL_CLASS_TEMPLATE_NAME); - } - - @Override - @NotNull - public PsiClass createClass(@NotNull PsiDirectory dir, @NotNull String name, @NotNull String templateName) throws IncorrectOperationException { - return createClassFromTemplate(dir, name, templateName); - } - - @Override - public PsiClass createClass(@NotNull PsiDirectory dir, - @NotNull String name, - @NotNull String templateName, - boolean askForUndefinedVariables) throws IncorrectOperationException { - return createClass(dir, name, templateName, askForUndefinedVariables, Collections.emptyMap()); - } - - @Override - public PsiClass createClass(@NotNull PsiDirectory dir, - @NotNull String name, - @NotNull String templateName, - boolean askForUndefinedVariables, @NotNull final Map additionalProperties) throws IncorrectOperationException { - return createClassFromTemplate(dir, name, templateName, askForUndefinedVariables, additionalProperties); - } - - @Override - @NotNull - public PsiClass createInterface(@NotNull PsiDirectory dir, @NotNull String name) throws IncorrectOperationException { - String templateName = JavaTemplateUtil.INTERNAL_INTERFACE_TEMPLATE_NAME; - PsiClass someClass = createClassFromTemplate(dir, name, templateName); - if (!someClass.isInterface()) { - throw new IncorrectOperationException(getIncorrectTemplateMessage(templateName)); - } - return someClass; - } - - @Override - @NotNull - public PsiClass createEnum(@NotNull PsiDirectory dir, @NotNull String name) throws IncorrectOperationException { - String templateName = JavaTemplateUtil.INTERNAL_ENUM_TEMPLATE_NAME; - PsiClass someClass = createClassFromTemplate(dir, name, templateName); - if (!someClass.isEnum()) { - throw new IncorrectOperationException(getIncorrectTemplateMessage(templateName)); - } - return someClass; - } - - @Override - @NotNull - public PsiClass createAnnotationType(@NotNull PsiDirectory dir, @NotNull String name) throws IncorrectOperationException { - String templateName = JavaTemplateUtil.INTERNAL_ANNOTATION_TYPE_TEMPLATE_NAME; - PsiClass someClass = createClassFromTemplate(dir, name, templateName); - if (!someClass.isAnnotationType()) { - throw new IncorrectOperationException(getIncorrectTemplateMessage(templateName)); - } - return someClass; - } - - private static PsiClass createClassFromTemplate(@NotNull PsiDirectory dir, String name, String templateName) throws IncorrectOperationException { - return createClassFromTemplate(dir, name, templateName, false, Collections.emptyMap()); - } - - private static PsiClass createClassFromTemplate(@NotNull PsiDirectory dir, - String name, - String templateName, - boolean askToDefineVariables, @NotNull Map additionalProperties) throws IncorrectOperationException { - //checkCreateClassOrInterface(dir, name); - - FileTemplate template = FileTemplateManager.getInstance().getInternalTemplate(templateName); - - Properties defaultProperties = FileTemplateManager.getInstance().getDefaultProperties(dir.getProject()); - Properties properties = new Properties(defaultProperties); - properties.setProperty(FileTemplate.ATTRIBUTE_NAME, name); - for (Map.Entry entry : additionalProperties.entrySet()) { - properties.setProperty(entry.getKey(), entry.getValue()); - } - - String ext = StdFileTypes.JAVA.getDefaultExtension(); - String fileName = name + "." + ext; - - PsiElement element; - try { - element = askToDefineVariables ? new CreateFromTemplateDialog(dir.getProject(), dir, template, null, properties).create() - : FileTemplateUtil.createFromTemplate(template, fileName, properties, dir); - } - catch (IncorrectOperationException e) { - throw e; - } - catch (Exception e) { - LOG.error(e); - return null; - } - if (element == null) return null; - final PsiJavaFile file = (PsiJavaFile)element.getContainingFile(); - PsiClass[] classes = file.getClasses(); - if (classes.length < 1) { - throw new IncorrectOperationException(getIncorrectTemplateMessage(templateName)); - } - return classes[0]; - } - - private static String getIncorrectTemplateMessage(String templateName) { - return PsiBundle.message("psi.error.incorroect.class.template.message", - FileTemplateManager.getInstance().internalTemplateToSubject(templateName), templateName); - } - - @Override - public void checkCreateClass(@NotNull PsiDirectory dir, @NotNull String name) throws IncorrectOperationException { - checkCreateClassOrInterface(dir, name); - } - - public static void checkCreateClassOrInterface(@NotNull PsiDirectory directory, String name) throws IncorrectOperationException { - PsiUtil.checkIsIdentifier(directory.getManager(), name); - - String fileName = name + "." + StdFileTypes.JAVA.getDefaultExtension(); - directory.checkCreateFile(fileName); - - PsiNameHelper helper = JavaPsiFacade.getInstance(directory.getProject()).getNameHelper(); - PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(directory); - String qualifiedName = aPackage == null ? null : aPackage.getQualifiedName(); - if (!StringUtil.isEmpty(qualifiedName) && !helper.isQualifiedName(qualifiedName)) { - throw new IncorrectOperationException("Cannot create class in invalid package: '"+qualifiedName+"'"); - } - } - - @Override - public boolean isSourceRoot(@NotNull PsiDirectory dir) { - final VirtualFile file = dir.getVirtualFile(); - final VirtualFile sourceRoot = ProjectRootManager.getInstance(dir.getProject()).getFileIndex().getSourceRootForFile(file); - return file.equals(sourceRoot); - } - - private static final Key LANG_LEVEL_IN_DIRECTORY = new Key("LANG_LEVEL_IN_DIRECTORY"); - @Override - public LanguageLevel getLanguageLevel(@NotNull PsiDirectory dir) { - synchronized (PsiLock.LOCK) { - LanguageLevel level = dir.getUserData(LANG_LEVEL_IN_DIRECTORY); - if (level == null) { - level = getLanguageLevelInner(dir); - dir.putUserData(LANG_LEVEL_IN_DIRECTORY, level); - } - return level; - } - } - - private static LanguageLevel getLanguageLevelInner(@NotNull PsiDirectory dir) { - final VirtualFile virtualFile = dir.getVirtualFile(); - final Project project = dir.getProject(); - final Module module = ProjectRootManager.getInstance(project).getFileIndex().getModuleForFile(virtualFile); - if (module != null) { - return LanguageLevelUtil.getEffectiveLanguageLevel(module); - } - - return LanguageLevelProjectExtension.getInstance(project).getLanguageLevel(); - } - -} +/* + * 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. + */ + +/* + * @author max + */ +package com.intellij.psi.impl.file; + +import com.intellij.core.CoreJavaDirectoryService; +import com.intellij.ide.fileTemplates.FileTemplate; +import com.intellij.ide.fileTemplates.FileTemplateManager; +import com.intellij.ide.fileTemplates.FileTemplateUtil; +import com.intellij.ide.fileTemplates.JavaTemplateUtil; +import com.intellij.ide.fileTemplates.ui.CreateFromTemplateDialog; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.fileTypes.StdFileTypes; +import com.intellij.openapi.module.LanguageLevelUtil; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.LanguageLevelProjectExtension; +import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiUtil; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.Map; +import java.util.Properties; + +public class JavaDirectoryServiceImpl extends CoreJavaDirectoryService { + private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.file.JavaDirectoryServiceImpl"); + + @Override + public PsiPackage getPackage(@NotNull PsiDirectory dir) { + ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(dir.getProject()).getFileIndex(); + String packageName = projectFileIndex.getPackageNameByDirectory(dir.getVirtualFile()); + if (packageName == null) return null; + return JavaPsiFacade.getInstance(dir.getProject()).findPackage(packageName); + } + + @Override + @NotNull + public PsiClass createClass(@NotNull PsiDirectory dir, @NotNull String name) throws IncorrectOperationException { + return createClassFromTemplate(dir, name, JavaTemplateUtil.INTERNAL_CLASS_TEMPLATE_NAME); + } + + @Override + @NotNull + public PsiClass createClass(@NotNull PsiDirectory dir, @NotNull String name, @NotNull String templateName) throws IncorrectOperationException { + return createClassFromTemplate(dir, name, templateName); + } + + @Override + public PsiClass createClass(@NotNull PsiDirectory dir, + @NotNull String name, + @NotNull String templateName, + boolean askForUndefinedVariables) throws IncorrectOperationException { + return createClass(dir, name, templateName, askForUndefinedVariables, Collections.emptyMap()); + } + + @Override + public PsiClass createClass(@NotNull PsiDirectory dir, + @NotNull String name, + @NotNull String templateName, + boolean askForUndefinedVariables, @NotNull final Map additionalProperties) throws IncorrectOperationException { + return createClassFromTemplate(dir, name, templateName, askForUndefinedVariables, additionalProperties); + } + + @Override + @NotNull + public PsiClass createInterface(@NotNull PsiDirectory dir, @NotNull String name) throws IncorrectOperationException { + String templateName = JavaTemplateUtil.INTERNAL_INTERFACE_TEMPLATE_NAME; + PsiClass someClass = createClassFromTemplate(dir, name, templateName); + if (!someClass.isInterface()) { + throw new IncorrectOperationException(getIncorrectTemplateMessage(templateName)); + } + return someClass; + } + + @Override + @NotNull + public PsiClass createEnum(@NotNull PsiDirectory dir, @NotNull String name) throws IncorrectOperationException { + String templateName = JavaTemplateUtil.INTERNAL_ENUM_TEMPLATE_NAME; + PsiClass someClass = createClassFromTemplate(dir, name, templateName); + if (!someClass.isEnum()) { + throw new IncorrectOperationException(getIncorrectTemplateMessage(templateName)); + } + return someClass; + } + + @Override + @NotNull + public PsiClass createAnnotationType(@NotNull PsiDirectory dir, @NotNull String name) throws IncorrectOperationException { + String templateName = JavaTemplateUtil.INTERNAL_ANNOTATION_TYPE_TEMPLATE_NAME; + PsiClass someClass = createClassFromTemplate(dir, name, templateName); + if (!someClass.isAnnotationType()) { + throw new IncorrectOperationException(getIncorrectTemplateMessage(templateName)); + } + return someClass; + } + + private static PsiClass createClassFromTemplate(@NotNull PsiDirectory dir, String name, String templateName) throws IncorrectOperationException { + return createClassFromTemplate(dir, name, templateName, false, Collections.emptyMap()); + } + + private static PsiClass createClassFromTemplate(@NotNull PsiDirectory dir, + String name, + String templateName, + boolean askToDefineVariables, @NotNull Map additionalProperties) throws IncorrectOperationException { + //checkCreateClassOrInterface(dir, name); + + FileTemplate template = FileTemplateManager.getInstance().getInternalTemplate(templateName); + + Properties defaultProperties = FileTemplateManager.getInstance().getDefaultProperties(dir.getProject()); + Properties properties = new Properties(defaultProperties); + properties.setProperty(FileTemplate.ATTRIBUTE_NAME, name); + for (Map.Entry entry : additionalProperties.entrySet()) { + properties.setProperty(entry.getKey(), entry.getValue()); + } + + String ext = StdFileTypes.JAVA.getDefaultExtension(); + String fileName = name + "." + ext; + + PsiElement element; + try { + element = askToDefineVariables ? new CreateFromTemplateDialog(dir.getProject(), dir, template, null, properties).create() + : FileTemplateUtil.createFromTemplate(template, fileName, properties, dir); + } + catch (IncorrectOperationException e) { + throw e; + } + catch (Exception e) { + LOG.error(e); + return null; + } + if (element == null) return null; + final PsiJavaFile file = (PsiJavaFile)element.getContainingFile(); + PsiClass[] classes = file.getClasses(); + if (classes.length < 1) { + throw new IncorrectOperationException(getIncorrectTemplateMessage(templateName)); + } + return classes[0]; + } + + private static String getIncorrectTemplateMessage(String templateName) { + return PsiBundle.message("psi.error.incorroect.class.template.message", + FileTemplateManager.getInstance().internalTemplateToSubject(templateName), templateName); + } + + @Override + public void checkCreateClass(@NotNull PsiDirectory dir, @NotNull String name) throws IncorrectOperationException { + checkCreateClassOrInterface(dir, name); + } + + public static void checkCreateClassOrInterface(@NotNull PsiDirectory directory, String name) throws IncorrectOperationException { + PsiUtil.checkIsIdentifier(directory.getManager(), name); + + String fileName = name + "." + StdFileTypes.JAVA.getDefaultExtension(); + directory.checkCreateFile(fileName); + + PsiNameHelper helper = JavaPsiFacade.getInstance(directory.getProject()).getNameHelper(); + PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(directory); + String qualifiedName = aPackage == null ? null : aPackage.getQualifiedName(); + if (!StringUtil.isEmpty(qualifiedName) && !helper.isQualifiedName(qualifiedName)) { + throw new IncorrectOperationException("Cannot create class in invalid package: '"+qualifiedName+"'"); + } + } + + @Override + public boolean isSourceRoot(@NotNull PsiDirectory dir) { + final VirtualFile file = dir.getVirtualFile(); + final VirtualFile sourceRoot = ProjectRootManager.getInstance(dir.getProject()).getFileIndex().getSourceRootForFile(file); + return file.equals(sourceRoot); + } + + private static final Key LANG_LEVEL_IN_DIRECTORY = new Key("LANG_LEVEL_IN_DIRECTORY"); + @Override + public LanguageLevel getLanguageLevel(@NotNull PsiDirectory dir) { + synchronized (PsiLock.LOCK) { + LanguageLevel level = dir.getUserData(LANG_LEVEL_IN_DIRECTORY); + if (level == null) { + level = getLanguageLevelInner(dir); + dir.putUserData(LANG_LEVEL_IN_DIRECTORY, level); + } + return level; + } + } + + private static LanguageLevel getLanguageLevelInner(@NotNull PsiDirectory dir) { + final VirtualFile virtualFile = dir.getVirtualFile(); + final Project project = dir.getProject(); + final Module module = ProjectRootManager.getInstance(project).getFileIndex().getModuleForFile(virtualFile); + if (module != null) { + return LanguageLevelUtil.getEffectiveLanguageLevel(module); + } + + return LanguageLevelProjectExtension.getInstance(project).getLanguageLevel(); + } + +} diff --git a/java/java-impl/src/com/intellij/psi/util/CreateClassUtil.java b/java/java-impl/src/com/intellij/psi/util/CreateClassUtil.java index 9011b0726e6d..9a6695953817 100644 --- a/java/java-impl/src/com/intellij/psi/util/CreateClassUtil.java +++ b/java/java-impl/src/com/intellij/psi/util/CreateClassUtil.java @@ -1,246 +1,246 @@ -/* - * 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.psi.util; - -import com.intellij.ide.fileTemplates.FileTemplate; -import com.intellij.ide.fileTemplates.FileTemplateManager; -import com.intellij.ide.fileTemplates.JavaCreateFromTemplateHandler; -import com.intellij.ide.util.DirectoryChooserUtil; -import com.intellij.ide.util.PackageUtil; -import com.intellij.openapi.fileTypes.StdFileTypes; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ModuleRootManager; -import com.intellij.openapi.roots.impl.DirectoryIndex; -import com.intellij.openapi.roots.impl.DirectoryInfo; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.psi.*; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.text.StringTokenizer; -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.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -/** - * author: lesya - */ -public class CreateClassUtil { - private static final Logger LOG = Logger.getInstance("#com.intellij.j2ee.CreateClassUtil"); - - @NonNls public static final String DEFAULT_CLASS_TEMPLATE = "#DEFAULT_CLASS_TEMPLATE"; - @NonNls private static final String DO_NOT_CREATE_CLASS_TEMPLATE = "#DO_NOT_CREATE_CLASS_TEMPLATE"; - @NonNls private static final String CLASS_NAME_PROPERTY = "Class_Name"; - @NonNls private static final String INTERFACE_NAME_PROPERTY = "Interface_Name"; - - private CreateClassUtil() {} - - @Nullable - private static PsiClass createClassFromTemplate(@NotNull final Properties attributes, @Nullable final String templateName, - @NotNull final PsiDirectory directoryRoot, - @NotNull final String className) throws IncorrectOperationException { - if (templateName == null) return null; - if (templateName.equals(DO_NOT_CREATE_CLASS_TEMPLATE)) return null; - - final Project project = directoryRoot.getProject(); - try { - final PsiDirectory directory = createParentDirectories(directoryRoot, className); - final PsiFile psiFile = directory.findFile(className + "." + StdFileTypes.JAVA.getDefaultExtension()); - if (psiFile != null) { - psiFile.delete(); - } - - final String rawClassName = extractClassName(className); - final PsiFile existing = directory.findFile(rawClassName + ".java"); - if (existing instanceof PsiJavaFile) { - final PsiClass[] classes = ((PsiJavaFile)existing).getClasses(); - if (classes.length > 0) { - return classes[0]; - } - return null; - } - - final PsiClass aClass; - if (templateName.equals(DEFAULT_CLASS_TEMPLATE)) { - aClass = JavaDirectoryService.getInstance().createClass(directory, rawClassName); - } - else { - final FileTemplateManager fileTemplateManager = FileTemplateManager.getInstance(); - FileTemplate fileTemplate = fileTemplateManager.getJ2eeTemplate(templateName); - LOG.assertTrue(fileTemplate != null, templateName + " not found"); - final String text = fileTemplate.getText(attributes); - aClass = JavaCreateFromTemplateHandler.createClassOrInterface(project, directory, text, true, fileTemplate.getExtension()); - } - return (PsiClass)JavaCodeStyleManager.getInstance(project).shortenClassReferences(aClass); - } - catch (IOException e) { - throw new IncorrectOperationException(e.toString(), e); - } - } - - @NotNull - private static PsiDirectory createParentDirectories(@NotNull PsiDirectory directoryRoot, @NotNull String className) throws IncorrectOperationException { - final PsiPackage currentPackage = JavaDirectoryService.getInstance().getPackage(directoryRoot); - final String packagePrefix = currentPackage == null? null : currentPackage.getQualifiedName() + "."; - final String packageName = extractPackage(packagePrefix != null && className.startsWith(packagePrefix)? - className.substring(packagePrefix.length()) : className); - final StringTokenizer tokenizer = new StringTokenizer(packageName, "."); - while (tokenizer.hasMoreTokens()) { - String packagePart = tokenizer.nextToken(); - PsiDirectory subdirectory = directoryRoot.findSubdirectory(packagePart); - if (subdirectory == null) { - directoryRoot.checkCreateSubdirectory(packagePart); - subdirectory = directoryRoot.createSubdirectory(packagePart); - } - directoryRoot = subdirectory; - } - return directoryRoot; - } - - @Nullable - public static PsiDirectory getRootDirectory(PsiClass aClass) { - return getSourceRootDirectory(aClass.getContainingFile().getContainingDirectory()); - } - - @Nullable - private static PsiDirectory getSourceRootDirectory(PsiDirectory directory) { - PsiManager manager = directory.getManager(); - DirectoryIndex directoryIndex = DirectoryIndex.getInstance(manager.getProject()); - DirectoryInfo info = directoryIndex.getInfoForDirectory(directory.getVirtualFile()); - if (info == null || !info.hasSourceRoot()) return null; - return manager.findDirectory(info.getSourceRoot()); - } - - @Nullable - public static PsiDirectory obtainDirectoryRootForPackage(final Module module, final String packageName) { - final Project project = module.getProject(); - GlobalSearchScope scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module); - final PsiPackage aPackage = JavaPsiFacade.getInstance(project).findPackage(packageName); - if (aPackage != null) { - PsiDirectory[] directories = aPackage.getDirectories(scope); - if (directories.length == 1) return getSourceRootDirectory(directories[0]); - } - - final VirtualFile[] sourceRoots = ModuleRootManager.getInstance(module).getSourceRoots(); - List directoryList = new ArrayList(); - for (VirtualFile sourceRoot : sourceRoots) { - final PsiDirectory directory = PsiManager.getInstance(project).findDirectory(sourceRoot); - directoryList.add(directory); - } - PsiDirectory[] sourceDirectories = directoryList.toArray(new PsiDirectory[directoryList.size()]); - - return DirectoryChooserUtil.selectDirectory(project, sourceDirectories, null, File.separatorChar + packageName.replace('.', File.separatorChar)); - } - - @Nullable - public static PsiDirectory getRoot(Module module, String className) { - String aPackage = extractPackage(className); - PsiManager psiManager = PsiManager.getInstance(module.getProject()); - PsiPackage psiPackage = JavaPsiFacade.getInstance(psiManager.getProject()).findPackage(aPackage); - if (psiPackage == null) return null; - PsiDirectory[] directories = psiPackage.getDirectories(GlobalSearchScope.moduleScope(module)); - if (directories.length == 0) return null; - - return directories[0]; - } - - public static String extractClassName(String fqName) { - return StringUtil.getShortName(fqName); - } - - public static String extractPackage(String fqName) { - int i = fqName.lastIndexOf('.'); - return i == -1 ? "" : fqName.substring(0, i); - } - - public static String makeFQName(String aPackage, String className) { - String fq = aPackage; - if (!"".equals(aPackage)) { - fq += "."; - } - fq += className; - return fq; - } - - @Nullable - public static PsiClass createClassNamed(String newClassName, String templateName, @NotNull PsiDirectory directory) throws IncorrectOperationException { - return createClassNamed(newClassName, FileTemplateManager.getInstance().getDefaultProperties(directory.getProject()), templateName, directory); - } - - @Nullable - public static PsiClass createClassNamed(String newClassName, Map classProperties, String templateName, @NotNull PsiDirectory directory) - throws IncorrectOperationException { - Properties defaultProperties = FileTemplateManager.getInstance().getDefaultProperties(directory.getProject()); - Properties properties = new Properties(defaultProperties); - properties.putAll(classProperties); - - return createClassNamed(newClassName, properties, templateName, directory); - } - - @Nullable - private static PsiClass createClassNamed(@Nullable String newClassName, - @NotNull Properties properties, - String templateName, - @NotNull PsiDirectory directory) throws IncorrectOperationException { - if (newClassName == null) { - return null; - } - final String className = extractClassName(newClassName); - properties.setProperty(CLASS_NAME_PROPERTY, className); - properties.setProperty(INTERFACE_NAME_PROPERTY, className); - - return createClassFromTemplate(properties, templateName, directory, newClassName); - } - - @Nullable - public static PsiClass createClassFromCustomTemplate(@Nullable PsiDirectory classDirectory, - @Nullable final Module module, - final String className, - final String templateName) { - if (classDirectory == null && module != null) { - try { - classDirectory = PackageUtil.findOrCreateDirectoryForPackage(module, "", null, false); - } - catch (IncorrectOperationException e) { - return null; - } - } - if (classDirectory == null) { - return null; - } - try { - final Properties properties = ApplicationManager.getApplication().isUnitTestMode() ? - new Properties() : - FileTemplateManager.getInstance().getDefaultProperties(classDirectory.getProject()); - return createClassNamed(className, new Properties(properties), templateName, classDirectory); - } - catch (IncorrectOperationException e) { - LOG.error(e); - return null; - } - } -} +/* + * 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.psi.util; + +import com.intellij.ide.fileTemplates.FileTemplate; +import com.intellij.ide.fileTemplates.FileTemplateManager; +import com.intellij.ide.fileTemplates.JavaCreateFromTemplateHandler; +import com.intellij.ide.util.DirectoryChooserUtil; +import com.intellij.ide.util.PackageUtil; +import com.intellij.openapi.fileTypes.StdFileTypes; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.impl.DirectoryIndex; +import com.intellij.openapi.roots.impl.DirectoryInfo; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.text.StringTokenizer; +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.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +/** + * author: lesya + */ +public class CreateClassUtil { + private static final Logger LOG = Logger.getInstance("#com.intellij.j2ee.CreateClassUtil"); + + @NonNls public static final String DEFAULT_CLASS_TEMPLATE = "#DEFAULT_CLASS_TEMPLATE"; + @NonNls private static final String DO_NOT_CREATE_CLASS_TEMPLATE = "#DO_NOT_CREATE_CLASS_TEMPLATE"; + @NonNls private static final String CLASS_NAME_PROPERTY = "Class_Name"; + @NonNls private static final String INTERFACE_NAME_PROPERTY = "Interface_Name"; + + private CreateClassUtil() {} + + @Nullable + private static PsiClass createClassFromTemplate(@NotNull final Properties attributes, @Nullable final String templateName, + @NotNull final PsiDirectory directoryRoot, + @NotNull final String className) throws IncorrectOperationException { + if (templateName == null) return null; + if (templateName.equals(DO_NOT_CREATE_CLASS_TEMPLATE)) return null; + + final Project project = directoryRoot.getProject(); + try { + final PsiDirectory directory = createParentDirectories(directoryRoot, className); + final PsiFile psiFile = directory.findFile(className + "." + StdFileTypes.JAVA.getDefaultExtension()); + if (psiFile != null) { + psiFile.delete(); + } + + final String rawClassName = extractClassName(className); + final PsiFile existing = directory.findFile(rawClassName + ".java"); + if (existing instanceof PsiJavaFile) { + final PsiClass[] classes = ((PsiJavaFile)existing).getClasses(); + if (classes.length > 0) { + return classes[0]; + } + return null; + } + + final PsiClass aClass; + if (templateName.equals(DEFAULT_CLASS_TEMPLATE)) { + aClass = JavaDirectoryService.getInstance().createClass(directory, rawClassName); + } + else { + final FileTemplateManager fileTemplateManager = FileTemplateManager.getInstance(); + FileTemplate fileTemplate = fileTemplateManager.getJ2eeTemplate(templateName); + LOG.assertTrue(fileTemplate != null, templateName + " not found"); + final String text = fileTemplate.getText(attributes); + aClass = JavaCreateFromTemplateHandler.createClassOrInterface(project, directory, text, true, fileTemplate.getExtension()); + } + return (PsiClass)JavaCodeStyleManager.getInstance(project).shortenClassReferences(aClass); + } + catch (IOException e) { + throw new IncorrectOperationException(e.toString(), e); + } + } + + @NotNull + private static PsiDirectory createParentDirectories(@NotNull PsiDirectory directoryRoot, @NotNull String className) throws IncorrectOperationException { + final PsiPackage currentPackage = JavaDirectoryService.getInstance().getPackage(directoryRoot); + final String packagePrefix = currentPackage == null? null : currentPackage.getQualifiedName() + "."; + final String packageName = extractPackage(packagePrefix != null && className.startsWith(packagePrefix)? + className.substring(packagePrefix.length()) : className); + final StringTokenizer tokenizer = new StringTokenizer(packageName, "."); + while (tokenizer.hasMoreTokens()) { + String packagePart = tokenizer.nextToken(); + PsiDirectory subdirectory = directoryRoot.findSubdirectory(packagePart); + if (subdirectory == null) { + directoryRoot.checkCreateSubdirectory(packagePart); + subdirectory = directoryRoot.createSubdirectory(packagePart); + } + directoryRoot = subdirectory; + } + return directoryRoot; + } + + @Nullable + public static PsiDirectory getRootDirectory(PsiClass aClass) { + return getSourceRootDirectory(aClass.getContainingFile().getContainingDirectory()); + } + + @Nullable + private static PsiDirectory getSourceRootDirectory(PsiDirectory directory) { + PsiManager manager = directory.getManager(); + DirectoryIndex directoryIndex = DirectoryIndex.getInstance(manager.getProject()); + DirectoryInfo info = directoryIndex.getInfoForDirectory(directory.getVirtualFile()); + if (info == null || !info.hasSourceRoot()) return null; + return manager.findDirectory(info.getSourceRoot()); + } + + @Nullable + public static PsiDirectory obtainDirectoryRootForPackage(final Module module, final String packageName) { + final Project project = module.getProject(); + GlobalSearchScope scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module); + final PsiPackage aPackage = JavaPsiFacade.getInstance(project).findPackage(packageName); + if (aPackage != null) { + PsiDirectory[] directories = aPackage.getDirectories(scope); + if (directories.length == 1) return getSourceRootDirectory(directories[0]); + } + + final VirtualFile[] sourceRoots = ModuleRootManager.getInstance(module).getSourceRoots(); + List directoryList = new ArrayList(); + for (VirtualFile sourceRoot : sourceRoots) { + final PsiDirectory directory = PsiManager.getInstance(project).findDirectory(sourceRoot); + directoryList.add(directory); + } + PsiDirectory[] sourceDirectories = directoryList.toArray(new PsiDirectory[directoryList.size()]); + + return DirectoryChooserUtil.selectDirectory(project, sourceDirectories, null, File.separatorChar + packageName.replace('.', File.separatorChar)); + } + + @Nullable + public static PsiDirectory getRoot(Module module, String className) { + String aPackage = extractPackage(className); + PsiManager psiManager = PsiManager.getInstance(module.getProject()); + PsiPackage psiPackage = JavaPsiFacade.getInstance(psiManager.getProject()).findPackage(aPackage); + if (psiPackage == null) return null; + PsiDirectory[] directories = psiPackage.getDirectories(GlobalSearchScope.moduleScope(module)); + if (directories.length == 0) return null; + + return directories[0]; + } + + public static String extractClassName(String fqName) { + return StringUtil.getShortName(fqName); + } + + public static String extractPackage(String fqName) { + int i = fqName.lastIndexOf('.'); + return i == -1 ? "" : fqName.substring(0, i); + } + + public static String makeFQName(String aPackage, String className) { + String fq = aPackage; + if (!"".equals(aPackage)) { + fq += "."; + } + fq += className; + return fq; + } + + @Nullable + public static PsiClass createClassNamed(String newClassName, String templateName, @NotNull PsiDirectory directory) throws IncorrectOperationException { + return createClassNamed(newClassName, FileTemplateManager.getInstance().getDefaultProperties(directory.getProject()), templateName, directory); + } + + @Nullable + public static PsiClass createClassNamed(String newClassName, Map classProperties, String templateName, @NotNull PsiDirectory directory) + throws IncorrectOperationException { + Properties defaultProperties = FileTemplateManager.getInstance().getDefaultProperties(directory.getProject()); + Properties properties = new Properties(defaultProperties); + properties.putAll(classProperties); + + return createClassNamed(newClassName, properties, templateName, directory); + } + + @Nullable + private static PsiClass createClassNamed(@Nullable String newClassName, + @NotNull Properties properties, + String templateName, + @NotNull PsiDirectory directory) throws IncorrectOperationException { + if (newClassName == null) { + return null; + } + final String className = extractClassName(newClassName); + properties.setProperty(CLASS_NAME_PROPERTY, className); + properties.setProperty(INTERFACE_NAME_PROPERTY, className); + + return createClassFromTemplate(properties, templateName, directory, newClassName); + } + + @Nullable + public static PsiClass createClassFromCustomTemplate(@Nullable PsiDirectory classDirectory, + @Nullable final Module module, + final String className, + final String templateName) { + if (classDirectory == null && module != null) { + try { + classDirectory = PackageUtil.findOrCreateDirectoryForPackage(module, "", null, false); + } + catch (IncorrectOperationException e) { + return null; + } + } + if (classDirectory == null) { + return null; + } + try { + final Properties properties = ApplicationManager.getApplication().isUnitTestMode() ? + new Properties() : + FileTemplateManager.getInstance().getDefaultProperties(classDirectory.getProject()); + return createClassNamed(className, new Properties(properties), templateName, classDirectory); + } + catch (IncorrectOperationException e) { + LOG.error(e); + return null; + } + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaMethodDescriptor.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaMethodDescriptor.java index 99aa9764cdc8..ded6621b7fad 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaMethodDescriptor.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaMethodDescriptor.java @@ -1,95 +1,95 @@ -/* - * Copyright 2000-2010 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES 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.changeSignature; - -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiParameter; -import com.intellij.psi.PsiTypeElement; -import com.intellij.util.VisibilityUtil; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; - -public class JavaMethodDescriptor implements MethodDescriptor { - - private final PsiMethod myMethod; - - public JavaMethodDescriptor(PsiMethod method) { - myMethod = method; - } - - @Override - public String getName() { - return myMethod.getName(); - } - - @Override - public List getParameters() { - final ArrayList result = new ArrayList(); - final PsiParameter[] parameters = myMethod.getParameterList().getParameters(); - for (int i = 0; i < parameters.length; i++) { - PsiParameter parameter = parameters[i]; - ParameterInfoImpl info = new ParameterInfoImpl(i, parameter.getName(), parameter.getType()); - info.defaultValue = ""; - result.add(info); - } - return result; - } - - @Override - public String getVisibility() { - return VisibilityUtil.getVisibilityModifier(myMethod.getModifierList()); - } - - @Override - public PsiMethod getMethod() { - return myMethod; - } - - @Override - public int getParametersCount() { - return myMethod.getParameterList().getParametersCount(); - } - - @Nullable - public String getReturnTypeText() { - final PsiTypeElement typeElement = myMethod.getReturnTypeElement(); - return typeElement != null ? typeElement.getText() : null; - } - - @Override - public boolean canChangeVisibility() { - PsiClass containingClass = myMethod.getContainingClass(); - return containingClass != null && !containingClass.isInterface(); - } - - @Override - public boolean canChangeParameters() { - return true; - } - - @Override - public ReadWriteOption canChangeReturnType() { - return myMethod.isConstructor() ? ReadWriteOption.None : ReadWriteOption.ReadWrite; - } - - @Override - public boolean canChangeName() { - return !myMethod.isConstructor(); - } -} +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.changeSignature; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiParameter; +import com.intellij.psi.PsiTypeElement; +import com.intellij.util.VisibilityUtil; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class JavaMethodDescriptor implements MethodDescriptor { + + private final PsiMethod myMethod; + + public JavaMethodDescriptor(PsiMethod method) { + myMethod = method; + } + + @Override + public String getName() { + return myMethod.getName(); + } + + @Override + public List getParameters() { + final ArrayList result = new ArrayList(); + final PsiParameter[] parameters = myMethod.getParameterList().getParameters(); + for (int i = 0; i < parameters.length; i++) { + PsiParameter parameter = parameters[i]; + ParameterInfoImpl info = new ParameterInfoImpl(i, parameter.getName(), parameter.getType()); + info.defaultValue = ""; + result.add(info); + } + return result; + } + + @Override + public String getVisibility() { + return VisibilityUtil.getVisibilityModifier(myMethod.getModifierList()); + } + + @Override + public PsiMethod getMethod() { + return myMethod; + } + + @Override + public int getParametersCount() { + return myMethod.getParameterList().getParametersCount(); + } + + @Nullable + public String getReturnTypeText() { + final PsiTypeElement typeElement = myMethod.getReturnTypeElement(); + return typeElement != null ? typeElement.getText() : null; + } + + @Override + public boolean canChangeVisibility() { + PsiClass containingClass = myMethod.getContainingClass(); + return containingClass != null && !containingClass.isInterface(); + } + + @Override + public boolean canChangeParameters() { + return true; + } + + @Override + public ReadWriteOption canChangeReturnType() { + return myMethod.isConstructor() ? ReadWriteOption.None : ReadWriteOption.ReadWrite; + } + + @Override + public boolean canChangeName() { + return !myMethod.isConstructor(); + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java index 24a17f8e7238..8923b587e423 100644 --- a/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java @@ -1,364 +1,364 @@ -/* - * 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.refactoring.rename; - -import com.intellij.ide.util.SuperMethodWarningUtil; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Pass; -import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.PsiElementProcessor; -import com.intellij.psi.search.SearchScope; -import com.intellij.psi.search.searches.ClassInheritorsSearch; -import com.intellij.psi.search.searches.MethodReferencesSearch; -import com.intellij.psi.search.searches.OverridingMethodsSearch; -import com.intellij.psi.util.MethodSignature; -import com.intellij.psi.util.MethodSignatureUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.refactoring.HelpID; -import com.intellij.refactoring.JavaRefactoringSettings; -import com.intellij.refactoring.RefactoringBundle; -import com.intellij.refactoring.listeners.RefactoringElementListener; -import com.intellij.refactoring.util.ConflictsUtil; -import com.intellij.refactoring.util.MoveRenameUsageInfo; -import com.intellij.refactoring.util.RefactoringUIUtil; -import com.intellij.refactoring.util.RefactoringUtil; -import com.intellij.usageView.UsageInfo; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.Processor; -import com.intellij.util.containers.HashSet; -import com.intellij.util.containers.MultiMap; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -public class RenameJavaMethodProcessor extends RenameJavaMemberProcessor { - private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.rename.RenameJavaMethodProcessor"); - - public boolean canProcessElement(@NotNull final PsiElement element) { - return element instanceof PsiMethod; - } - - public void renameElement(final PsiElement psiElement, - final String newName, - final UsageInfo[] usages, - @Nullable RefactoringElementListener listener) throws IncorrectOperationException { - PsiMethod method = (PsiMethod) psiElement; - Set methodAndOverriders = new HashSet(); - Set containingClasses = new HashSet(); - LinkedHashSet renamedReferences = new LinkedHashSet(); - List outerHides = new ArrayList(); - List staticImportHides = new ArrayList(); - - methodAndOverriders.add(method); - containingClasses.add(method.getContainingClass()); - - // do actual rename of overriding/implementing methods and of references to all them - for (UsageInfo usage : usages) { - PsiElement element = usage.getElement(); - if (element == null) continue; - - if (usage instanceof MemberHidesStaticImportUsageInfo) { - staticImportHides.add((MemberHidesStaticImportUsageInfo)usage); - } else if (usage instanceof MemberHidesOuterMemberUsageInfo) { - PsiJavaCodeReferenceElement collidingRef = (PsiJavaCodeReferenceElement)element; - PsiMethod resolved = (PsiMethod)collidingRef.resolve(); - outerHides.add(new MemberHidesOuterMemberUsageInfo(element, resolved)); - } - else if (!(element instanceof PsiMethod)) { - final PsiReference ref; - if (usage instanceof MoveRenameUsageInfo) { - ref = usage.getReference(); - } - else { - ref = element.getReference(); - } - if (ref instanceof PsiImportStaticReferenceElement && ((PsiImportStaticReferenceElement)ref).multiResolve(false).length > 1) { - continue; - } - if (ref != null) { - PsiElement e = processRef(ref, newName); - if (e != null) { - renamedReferences.add(e); - } - } - } - else { - PsiMethod overrider = (PsiMethod)element; - methodAndOverriders.add(overrider); - containingClasses.add(overrider.getContainingClass()); - } - } - - // do actual rename of method - method.setName(newName); - for (UsageInfo usage : usages) { - PsiElement element = usage.getElement(); - if (element instanceof PsiMethod) { - ((PsiMethod)element).setName(newName); - } - } - if (listener != null) { - listener.elementRenamed(method); - } - - for (PsiElement element: renamedReferences) { - fixNameCollisionsWithInnerClassMethod(element, newName, methodAndOverriders, containingClasses, - method.hasModifierProperty(PsiModifier.STATIC)); - } - qualifyOuterMemberReferences(outerHides); - qualifyStaticImportReferences(staticImportHides); - } - - /** - * handles rename of refs - * @param ref - * @param newName - * @return - */ - @Nullable - protected PsiElement processRef(PsiReference ref, String newName) { - return ref.handleElementRename(newName); - } - - private static void fixNameCollisionsWithInnerClassMethod(final PsiElement element, final String newName, - final Set methodAndOverriders, final Set containingClasses, - final boolean isStatic) throws IncorrectOperationException { - if (!(element instanceof PsiReferenceExpression)) return; - PsiElement elem = ((PsiReferenceExpression)element).resolve(); - - if (elem instanceof PsiMethod) { - PsiMethod actualMethod = (PsiMethod) elem; - if (!methodAndOverriders.contains(actualMethod)) { - PsiClass outerClass = PsiTreeUtil.getParentOfType(element, PsiClass.class); - while (outerClass != null) { - if (containingClasses.contains(outerClass)) { - qualifyMember(element, newName, outerClass, isStatic); - break; - } - outerClass = PsiTreeUtil.getParentOfType(outerClass, PsiClass.class); - } - } - } - } - - @NotNull - public Collection findReferences(final PsiElement element) { - GlobalSearchScope projectScope = GlobalSearchScope.projectScope(element.getProject()); - return MethodReferencesSearch.search((PsiMethod)element, projectScope, true).findAll(); - } - - public void findCollisions(final PsiElement element, final String newName, final Map allRenames, - final List result) { - final PsiMethod methodToRename = (PsiMethod)element; - findSubmemberHidesMemberCollisions(methodToRename, newName, result); - findMemberHidesOuterMemberCollisions((PsiMethod) element, newName, result); - findCollisionsAgainstNewName(methodToRename, newName, result); - findHidingMethodWithOtherSignature(methodToRename, newName, result); - final PsiClass containingClass = methodToRename.getContainingClass(); - if (containingClass != null) { - final PsiMethod patternMethod = (PsiMethod)methodToRename.copy(); - try { - patternMethod.setName(newName); - final PsiMethod methodInBaseClass = containingClass.findMethodBySignature(patternMethod, true); - if (methodInBaseClass != null && methodInBaseClass.getContainingClass() != containingClass) { - if (methodInBaseClass.hasModifierProperty(PsiModifier.FINAL)) { - result.add(new UnresolvableCollisionUsageInfo(methodInBaseClass, methodToRename) { - @Override - public String getDescription() { - return "Renaming method will override final \"" + RefactoringUIUtil.getDescription(methodInBaseClass, true) + "\""; - } - }); - } - } - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } - } - - private void findHidingMethodWithOtherSignature(final PsiMethod methodToRename, final String newName, final List result) { - final PsiClass containingClass = methodToRename.getContainingClass(); - if (containingClass != null) { - final PsiMethod prototype = getPrototypeWithNewName(methodToRename, newName); - if (prototype == null || containingClass.findMethodBySignature(prototype, true) != null) return; - - final PsiMethod[] methodsByName = containingClass.findMethodsByName(newName, true); - if (methodsByName.length > 0) { - - for (UsageInfo info : result) { - final PsiElement element = info.getElement(); - if (element instanceof PsiReferenceExpression) { - if (((PsiReferenceExpression)element).resolve() == methodToRename) { - final PsiMethodCallExpression copy = (PsiMethodCallExpression)JavaPsiFacade.getElementFactory(element.getProject()) - .createExpressionFromText(element.getParent().getText(), element); - final PsiReferenceExpression expression = (PsiReferenceExpression)processRef(copy.getMethodExpression(), newName); - if (expression == null) continue; - final JavaResolveResult resolveResult = expression.advancedResolve(true); - final PsiMember resolveResultElement = (PsiMember)resolveResult.getElement(); - if (resolveResult.isValidResult() && resolveResultElement != null) { - result.add(new UnresolvableCollisionUsageInfo(element, methodToRename) { - @Override - public String getDescription() { - return "Method call would be linked to \"" + RefactoringUIUtil.getDescription(resolveResultElement, true) + - "\" after rename"; - } - }); - break; - } - } - } - } - } - } - } - - private static PsiMethod getPrototypeWithNewName(PsiMethod methodToRename, String newName) { - final PsiMethod prototype = (PsiMethod)methodToRename.copy(); - try { - prototype.setName(newName); - } - catch (IncorrectOperationException e) { - LOG.error(e); - return null; - } - return prototype; - } - - public void findExistingNameConflicts(final PsiElement element, final String newName, final MultiMap conflicts) { - if (element instanceof PsiCompiledElement) return; - final PsiMethod refactoredMethod = (PsiMethod)element; - if (newName.equals(refactoredMethod.getName())) return; - final PsiMethod prototype = getPrototypeWithNewName(refactoredMethod, newName); - if (prototype == null) return; - - ConflictsUtil.checkMethodConflicts( - refactoredMethod.getContainingClass(), - refactoredMethod, - prototype, - conflicts); - } - - @Override - public void prepareRenaming(PsiElement element, final String newName, final Map allRenames, SearchScope scope) { - final PsiMethod method = (PsiMethod) element; - OverridingMethodsSearch.search(method, scope, true).forEach(new Processor() { - public boolean process(PsiMethod overrider) { - final String overriderName = overrider.getName(); - final String baseName = method.getName(); - final String newOverriderName = RefactoringUtil.suggestNewOverriderName(overriderName, baseName, newName); - if (newOverriderName != null) { - RenameProcessor.assertNonCompileElement(overrider); - allRenames.put(overrider, newOverriderName); - } - return true; - } - }); - } - - @NonNls - public String getHelpID(final PsiElement element) { - return HelpID.RENAME_METHOD; - } - - public boolean isToSearchInComments(final PsiElement psiElement) { - return JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD; - } - - public void setToSearchInComments(final PsiElement element, final boolean enabled) { - JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD = enabled; - } - - @Nullable - public PsiElement substituteElementToRename(PsiElement element, Editor editor) { - PsiMethod psiMethod = (PsiMethod)element; - if (psiMethod.isConstructor()) { - PsiClass containingClass = psiMethod.getContainingClass(); - if (containingClass == null) return null; - if (Comparing.strEqual(psiMethod.getName(), containingClass.getName())) { - element = containingClass; - if (!PsiElementRenameHandler.canRename(element.getProject(), editor, element)) { - return null; - } - return element; - } - } - return SuperMethodWarningUtil.checkSuperMethod(psiMethod, RefactoringBundle.message("to.rename")); - } - - @Override - public void substituteElementToRename(@NotNull PsiElement element, - @NotNull final Editor editor, - @NotNull final Pass renameCallback) { - final PsiMethod psiMethod = (PsiMethod)element; - if (psiMethod.isConstructor()) { - final PsiClass containingClass = psiMethod.getContainingClass(); - if (containingClass == null) return; - if (!Comparing.strEqual(psiMethod.getName(), containingClass.getName())) { - renameCallback.pass(psiMethod); - return; - } - super.substituteElementToRename(element, editor, renameCallback); - } - else { - SuperMethodWarningUtil.checkSuperMethod(psiMethod, "Rename", new PsiElementProcessor() { - @Override - public boolean execute(@NotNull PsiMethod method) { - if (!PsiElementRenameHandler.canRename(method.getProject(), editor, method)) return false; - renameCallback.pass(method); - return false; - } - }, editor); - } - } - - private static void findSubmemberHidesMemberCollisions(final PsiMethod method, final String newName, final List result) { - final PsiClass containingClass = method.getContainingClass(); - if (containingClass == null) return; - if (method.hasModifierProperty(PsiModifier.PRIVATE)) return; - Collection inheritors = ClassInheritorsSearch.search(containingClass, true).findAll(); - - MethodSignature oldSignature = method.getSignature(PsiSubstitutor.EMPTY); - MethodSignature newSignature = MethodSignatureUtil.createMethodSignature(newName, oldSignature.getParameterTypes(), - oldSignature.getTypeParameters(), - oldSignature.getSubstitutor(), - method.isConstructor()); - for (PsiClass inheritor : inheritors) { - PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(containingClass, inheritor, PsiSubstitutor.EMPTY); - final PsiMethod[] methodsByName = inheritor.findMethodsByName(newName, false); - for (PsiMethod conflictingMethod : methodsByName) { - if (newSignature.equals(conflictingMethod.getSignature(superSubstitutor))) { - result.add(new SubmemberHidesMemberUsageInfo(conflictingMethod, method)); - break; - } - } - } - } - - public boolean isToSearchForTextOccurrences(final PsiElement element) { - return JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD; - } - - public void setToSearchForTextOccurrences(final PsiElement element, final boolean enabled) { - JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD = enabled; - } -} +/* + * 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.refactoring.rename; + +import com.intellij.ide.util.SuperMethodWarningUtil; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Pass; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.PsiElementProcessor; +import com.intellij.psi.search.SearchScope; +import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.psi.search.searches.MethodReferencesSearch; +import com.intellij.psi.search.searches.OverridingMethodsSearch; +import com.intellij.psi.util.MethodSignature; +import com.intellij.psi.util.MethodSignatureUtil; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.refactoring.HelpID; +import com.intellij.refactoring.JavaRefactoringSettings; +import com.intellij.refactoring.RefactoringBundle; +import com.intellij.refactoring.listeners.RefactoringElementListener; +import com.intellij.refactoring.util.ConflictsUtil; +import com.intellij.refactoring.util.MoveRenameUsageInfo; +import com.intellij.refactoring.util.RefactoringUIUtil; +import com.intellij.refactoring.util.RefactoringUtil; +import com.intellij.usageView.UsageInfo; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.Processor; +import com.intellij.util.containers.HashSet; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public class RenameJavaMethodProcessor extends RenameJavaMemberProcessor { + private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.rename.RenameJavaMethodProcessor"); + + public boolean canProcessElement(@NotNull final PsiElement element) { + return element instanceof PsiMethod; + } + + public void renameElement(final PsiElement psiElement, + final String newName, + final UsageInfo[] usages, + @Nullable RefactoringElementListener listener) throws IncorrectOperationException { + PsiMethod method = (PsiMethod) psiElement; + Set methodAndOverriders = new HashSet(); + Set containingClasses = new HashSet(); + LinkedHashSet renamedReferences = new LinkedHashSet(); + List outerHides = new ArrayList(); + List staticImportHides = new ArrayList(); + + methodAndOverriders.add(method); + containingClasses.add(method.getContainingClass()); + + // do actual rename of overriding/implementing methods and of references to all them + for (UsageInfo usage : usages) { + PsiElement element = usage.getElement(); + if (element == null) continue; + + if (usage instanceof MemberHidesStaticImportUsageInfo) { + staticImportHides.add((MemberHidesStaticImportUsageInfo)usage); + } else if (usage instanceof MemberHidesOuterMemberUsageInfo) { + PsiJavaCodeReferenceElement collidingRef = (PsiJavaCodeReferenceElement)element; + PsiMethod resolved = (PsiMethod)collidingRef.resolve(); + outerHides.add(new MemberHidesOuterMemberUsageInfo(element, resolved)); + } + else if (!(element instanceof PsiMethod)) { + final PsiReference ref; + if (usage instanceof MoveRenameUsageInfo) { + ref = usage.getReference(); + } + else { + ref = element.getReference(); + } + if (ref instanceof PsiImportStaticReferenceElement && ((PsiImportStaticReferenceElement)ref).multiResolve(false).length > 1) { + continue; + } + if (ref != null) { + PsiElement e = processRef(ref, newName); + if (e != null) { + renamedReferences.add(e); + } + } + } + else { + PsiMethod overrider = (PsiMethod)element; + methodAndOverriders.add(overrider); + containingClasses.add(overrider.getContainingClass()); + } + } + + // do actual rename of method + method.setName(newName); + for (UsageInfo usage : usages) { + PsiElement element = usage.getElement(); + if (element instanceof PsiMethod) { + ((PsiMethod)element).setName(newName); + } + } + if (listener != null) { + listener.elementRenamed(method); + } + + for (PsiElement element: renamedReferences) { + fixNameCollisionsWithInnerClassMethod(element, newName, methodAndOverriders, containingClasses, + method.hasModifierProperty(PsiModifier.STATIC)); + } + qualifyOuterMemberReferences(outerHides); + qualifyStaticImportReferences(staticImportHides); + } + + /** + * handles rename of refs + * @param ref + * @param newName + * @return + */ + @Nullable + protected PsiElement processRef(PsiReference ref, String newName) { + return ref.handleElementRename(newName); + } + + private static void fixNameCollisionsWithInnerClassMethod(final PsiElement element, final String newName, + final Set methodAndOverriders, final Set containingClasses, + final boolean isStatic) throws IncorrectOperationException { + if (!(element instanceof PsiReferenceExpression)) return; + PsiElement elem = ((PsiReferenceExpression)element).resolve(); + + if (elem instanceof PsiMethod) { + PsiMethod actualMethod = (PsiMethod) elem; + if (!methodAndOverriders.contains(actualMethod)) { + PsiClass outerClass = PsiTreeUtil.getParentOfType(element, PsiClass.class); + while (outerClass != null) { + if (containingClasses.contains(outerClass)) { + qualifyMember(element, newName, outerClass, isStatic); + break; + } + outerClass = PsiTreeUtil.getParentOfType(outerClass, PsiClass.class); + } + } + } + } + + @NotNull + public Collection findReferences(final PsiElement element) { + GlobalSearchScope projectScope = GlobalSearchScope.projectScope(element.getProject()); + return MethodReferencesSearch.search((PsiMethod)element, projectScope, true).findAll(); + } + + public void findCollisions(final PsiElement element, final String newName, final Map allRenames, + final List result) { + final PsiMethod methodToRename = (PsiMethod)element; + findSubmemberHidesMemberCollisions(methodToRename, newName, result); + findMemberHidesOuterMemberCollisions((PsiMethod) element, newName, result); + findCollisionsAgainstNewName(methodToRename, newName, result); + findHidingMethodWithOtherSignature(methodToRename, newName, result); + final PsiClass containingClass = methodToRename.getContainingClass(); + if (containingClass != null) { + final PsiMethod patternMethod = (PsiMethod)methodToRename.copy(); + try { + patternMethod.setName(newName); + final PsiMethod methodInBaseClass = containingClass.findMethodBySignature(patternMethod, true); + if (methodInBaseClass != null && methodInBaseClass.getContainingClass() != containingClass) { + if (methodInBaseClass.hasModifierProperty(PsiModifier.FINAL)) { + result.add(new UnresolvableCollisionUsageInfo(methodInBaseClass, methodToRename) { + @Override + public String getDescription() { + return "Renaming method will override final \"" + RefactoringUIUtil.getDescription(methodInBaseClass, true) + "\""; + } + }); + } + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + } + + private void findHidingMethodWithOtherSignature(final PsiMethod methodToRename, final String newName, final List result) { + final PsiClass containingClass = methodToRename.getContainingClass(); + if (containingClass != null) { + final PsiMethod prototype = getPrototypeWithNewName(methodToRename, newName); + if (prototype == null || containingClass.findMethodBySignature(prototype, true) != null) return; + + final PsiMethod[] methodsByName = containingClass.findMethodsByName(newName, true); + if (methodsByName.length > 0) { + + for (UsageInfo info : result) { + final PsiElement element = info.getElement(); + if (element instanceof PsiReferenceExpression) { + if (((PsiReferenceExpression)element).resolve() == methodToRename) { + final PsiMethodCallExpression copy = (PsiMethodCallExpression)JavaPsiFacade.getElementFactory(element.getProject()) + .createExpressionFromText(element.getParent().getText(), element); + final PsiReferenceExpression expression = (PsiReferenceExpression)processRef(copy.getMethodExpression(), newName); + if (expression == null) continue; + final JavaResolveResult resolveResult = expression.advancedResolve(true); + final PsiMember resolveResultElement = (PsiMember)resolveResult.getElement(); + if (resolveResult.isValidResult() && resolveResultElement != null) { + result.add(new UnresolvableCollisionUsageInfo(element, methodToRename) { + @Override + public String getDescription() { + return "Method call would be linked to \"" + RefactoringUIUtil.getDescription(resolveResultElement, true) + + "\" after rename"; + } + }); + break; + } + } + } + } + } + } + } + + private static PsiMethod getPrototypeWithNewName(PsiMethod methodToRename, String newName) { + final PsiMethod prototype = (PsiMethod)methodToRename.copy(); + try { + prototype.setName(newName); + } + catch (IncorrectOperationException e) { + LOG.error(e); + return null; + } + return prototype; + } + + public void findExistingNameConflicts(final PsiElement element, final String newName, final MultiMap conflicts) { + if (element instanceof PsiCompiledElement) return; + final PsiMethod refactoredMethod = (PsiMethod)element; + if (newName.equals(refactoredMethod.getName())) return; + final PsiMethod prototype = getPrototypeWithNewName(refactoredMethod, newName); + if (prototype == null) return; + + ConflictsUtil.checkMethodConflicts( + refactoredMethod.getContainingClass(), + refactoredMethod, + prototype, + conflicts); + } + + @Override + public void prepareRenaming(PsiElement element, final String newName, final Map allRenames, SearchScope scope) { + final PsiMethod method = (PsiMethod) element; + OverridingMethodsSearch.search(method, scope, true).forEach(new Processor() { + public boolean process(PsiMethod overrider) { + final String overriderName = overrider.getName(); + final String baseName = method.getName(); + final String newOverriderName = RefactoringUtil.suggestNewOverriderName(overriderName, baseName, newName); + if (newOverriderName != null) { + RenameProcessor.assertNonCompileElement(overrider); + allRenames.put(overrider, newOverriderName); + } + return true; + } + }); + } + + @NonNls + public String getHelpID(final PsiElement element) { + return HelpID.RENAME_METHOD; + } + + public boolean isToSearchInComments(final PsiElement psiElement) { + return JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD; + } + + public void setToSearchInComments(final PsiElement element, final boolean enabled) { + JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD = enabled; + } + + @Nullable + public PsiElement substituteElementToRename(PsiElement element, Editor editor) { + PsiMethod psiMethod = (PsiMethod)element; + if (psiMethod.isConstructor()) { + PsiClass containingClass = psiMethod.getContainingClass(); + if (containingClass == null) return null; + if (Comparing.strEqual(psiMethod.getName(), containingClass.getName())) { + element = containingClass; + if (!PsiElementRenameHandler.canRename(element.getProject(), editor, element)) { + return null; + } + return element; + } + } + return SuperMethodWarningUtil.checkSuperMethod(psiMethod, RefactoringBundle.message("to.rename")); + } + + @Override + public void substituteElementToRename(@NotNull PsiElement element, + @NotNull final Editor editor, + @NotNull final Pass renameCallback) { + final PsiMethod psiMethod = (PsiMethod)element; + if (psiMethod.isConstructor()) { + final PsiClass containingClass = psiMethod.getContainingClass(); + if (containingClass == null) return; + if (!Comparing.strEqual(psiMethod.getName(), containingClass.getName())) { + renameCallback.pass(psiMethod); + return; + } + super.substituteElementToRename(element, editor, renameCallback); + } + else { + SuperMethodWarningUtil.checkSuperMethod(psiMethod, "Rename", new PsiElementProcessor() { + @Override + public boolean execute(@NotNull PsiMethod method) { + if (!PsiElementRenameHandler.canRename(method.getProject(), editor, method)) return false; + renameCallback.pass(method); + return false; + } + }, editor); + } + } + + private static void findSubmemberHidesMemberCollisions(final PsiMethod method, final String newName, final List result) { + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) return; + if (method.hasModifierProperty(PsiModifier.PRIVATE)) return; + Collection inheritors = ClassInheritorsSearch.search(containingClass, true).findAll(); + + MethodSignature oldSignature = method.getSignature(PsiSubstitutor.EMPTY); + MethodSignature newSignature = MethodSignatureUtil.createMethodSignature(newName, oldSignature.getParameterTypes(), + oldSignature.getTypeParameters(), + oldSignature.getSubstitutor(), + method.isConstructor()); + for (PsiClass inheritor : inheritors) { + PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(containingClass, inheritor, PsiSubstitutor.EMPTY); + final PsiMethod[] methodsByName = inheritor.findMethodsByName(newName, false); + for (PsiMethod conflictingMethod : methodsByName) { + if (newSignature.equals(conflictingMethod.getSignature(superSubstitutor))) { + result.add(new SubmemberHidesMemberUsageInfo(conflictingMethod, method)); + break; + } + } + } + } + + public boolean isToSearchForTextOccurrences(final PsiElement element) { + return JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD; + } + + public void setToSearchForTextOccurrences(final PsiElement element, final boolean enabled) { + JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD = enabled; + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/ui/JavaComboBoxVisibilityPanel.java b/java/java-impl/src/com/intellij/refactoring/ui/JavaComboBoxVisibilityPanel.java index 1f7824686c11..a29853f86fb6 100644 --- a/java/java-impl/src/com/intellij/refactoring/ui/JavaComboBoxVisibilityPanel.java +++ b/java/java-impl/src/com/intellij/refactoring/ui/JavaComboBoxVisibilityPanel.java @@ -1,38 +1,38 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES 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.ui; - -import com.intellij.psi.PsiModifier; - -import static com.intellij.util.VisibilityUtil.toPresentableText; - -/** - * @author Konstantin Bulenkov - */ -public class JavaComboBoxVisibilityPanel extends ComboBoxVisibilityPanel implements PsiModifier { - private static final String[] MODIFIERS = {PRIVATE, PACKAGE_LOCAL, PROTECTED, PUBLIC}; - - private static final String[] PRESENTABLE_NAMES = { - toPresentableText(PRIVATE), - toPresentableText(PACKAGE_LOCAL), - toPresentableText(PROTECTED), - toPresentableText(PUBLIC) - }; - - public JavaComboBoxVisibilityPanel() { - super(MODIFIERS, PRESENTABLE_NAMES); - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.ui; + +import com.intellij.psi.PsiModifier; + +import static com.intellij.util.VisibilityUtil.toPresentableText; + +/** + * @author Konstantin Bulenkov + */ +public class JavaComboBoxVisibilityPanel extends ComboBoxVisibilityPanel implements PsiModifier { + private static final String[] MODIFIERS = {PRIVATE, PACKAGE_LOCAL, PROTECTED, PUBLIC}; + + private static final String[] PRESENTABLE_NAMES = { + toPresentableText(PRIVATE), + toPresentableText(PACKAGE_LOCAL), + toPresentableText(PROTECTED), + toPresentableText(PUBLIC) + }; + + public JavaComboBoxVisibilityPanel() { + super(MODIFIERS, PRESENTABLE_NAMES); + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/ui/JavaVisibilityPanel.java b/java/java-impl/src/com/intellij/refactoring/ui/JavaVisibilityPanel.java index 7169e60a95a1..414c44212367 100644 --- a/java/java-impl/src/com/intellij/refactoring/ui/JavaVisibilityPanel.java +++ b/java/java-impl/src/com/intellij/refactoring/ui/JavaVisibilityPanel.java @@ -1,167 +1,167 @@ -/* - * 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. - */ - -/* - * Created by IntelliJ IDEA. - * User: dsl - * Date: 07.06.2002 - * Time: 18:16:19 - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ -package com.intellij.refactoring.ui; - -import com.intellij.psi.PsiModifier; -import com.intellij.refactoring.RefactoringBundle; -import com.intellij.ui.IdeBorderFactory; -import com.intellij.util.VisibilityUtil; -import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import javax.swing.event.ChangeEvent; -import java.awt.*; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; - -public class JavaVisibilityPanel extends VisibilityPanelBase { - private JRadioButton myRbAsIs; - private JRadioButton myRbEscalate; - private final JRadioButton myRbPrivate; - private final JRadioButton myRbProtected; - private final JRadioButton myRbPackageLocal; - private final JRadioButton myRbPublic; - - public JavaVisibilityPanel(boolean hasAsIs, final boolean hasEscalate) { - setBorder(IdeBorderFactory.createTitledBorder(RefactoringBundle.message("visibility.border.title"), true, - new Insets(IdeBorderFactory.TITLED_BORDER_TOP_INSET, - UIUtil.DEFAULT_HGAP, - IdeBorderFactory.TITLED_BORDER_BOTTOM_INSET, - IdeBorderFactory.TITLED_BORDER_RIGHT_INSET))); - setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - ButtonGroup bg = new ButtonGroup(); - - ItemListener listener = new ItemListener() { - public void itemStateChanged(ItemEvent e) { - if (e.getStateChange() == ItemEvent.SELECTED) { - myEventDispatcher.getMulticaster().stateChanged(new ChangeEvent(this)); - } - } - }; - - if (hasEscalate) { - myRbEscalate = new JRadioButton(); - myRbEscalate.setText(RefactoringBundle.getEscalateVisibility()); - myRbEscalate.addItemListener(listener); - add(myRbEscalate); - bg.add(myRbEscalate); - } - - if (hasAsIs) { - myRbAsIs = new JRadioButton(); - myRbAsIs.setText(RefactoringBundle.getVisibilityAsIs()); - myRbAsIs.addItemListener(listener); - add(myRbAsIs); - bg.add(myRbAsIs); - } - - - myRbPrivate = new JRadioButton(); - myRbPrivate.setText(RefactoringBundle.getVisibilityPrivate()); - myRbPrivate.addItemListener(listener); - myRbPrivate.setFocusable(false); - add(myRbPrivate); - bg.add(myRbPrivate); - - myRbPackageLocal = new JRadioButton(); - myRbPackageLocal.setText(RefactoringBundle.getVisibilityPackageLocal()); - myRbPackageLocal.addItemListener(listener); - myRbPackageLocal.setFocusable(false); - add(myRbPackageLocal); - bg.add(myRbPackageLocal); - - myRbProtected = new JRadioButton(); - myRbProtected.setText(RefactoringBundle.getVisibilityProtected()); - myRbProtected.addItemListener(listener); - myRbProtected.setFocusable(false); - add(myRbProtected); - bg.add(myRbProtected); - - myRbPublic = new JRadioButton(); - myRbPublic.setText(RefactoringBundle.getVisibilityPublic()); - myRbPublic.addItemListener(listener); - myRbPublic.setFocusable(false); - add(myRbPublic); - bg.add(myRbPublic); - } - - - @Nullable - public String getVisibility() { - if (myRbPublic.isSelected()) { - return PsiModifier.PUBLIC; - } - if (myRbPackageLocal.isSelected()) { - return PsiModifier.PACKAGE_LOCAL; - } - if (myRbProtected.isSelected()) { - return PsiModifier.PROTECTED; - } - if (myRbPrivate.isSelected()) { - return PsiModifier.PRIVATE; - } - if (myRbEscalate != null && myRbEscalate.isSelected()) { - return VisibilityUtil.ESCALATE_VISIBILITY; - } - - return null; - } - - public void setVisibility(@Nullable String visibility) { - if (PsiModifier.PUBLIC.equals(visibility)) { - myRbPublic.setSelected(true); - } - else if (PsiModifier.PROTECTED.equals(visibility)) { - myRbProtected.setSelected(true); - } - else if (PsiModifier.PACKAGE_LOCAL.equals(visibility)) { - myRbPackageLocal.setSelected(true); - } - else if (PsiModifier.PRIVATE.equals(visibility)) { - myRbPrivate.setSelected(true); - } - else if (myRbEscalate != null) { - myRbEscalate.setSelected(true); - } - else if (myRbAsIs != null) { - myRbAsIs.setSelected(true); - } - } - - public void disableAllButPublic() { - myRbPrivate.setEnabled(false); - myRbProtected.setEnabled(false); - myRbPackageLocal.setEnabled(false); - if (myRbEscalate != null) { - myRbEscalate.setEnabled(false); - } - if (myRbAsIs != null) { - myRbAsIs.setEnabled(false); - } - myRbPublic.setEnabled(true); - myRbPublic.setSelected(true); - } -} +/* + * 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. + */ + +/* + * Created by IntelliJ IDEA. + * User: dsl + * Date: 07.06.2002 + * Time: 18:16:19 + * To change template for new class use + * Code Style | Class Templates options (Tools | IDE Options). + */ +package com.intellij.refactoring.ui; + +import com.intellij.psi.PsiModifier; +import com.intellij.refactoring.RefactoringBundle; +import com.intellij.ui.IdeBorderFactory; +import com.intellij.util.VisibilityUtil; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import java.awt.*; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +public class JavaVisibilityPanel extends VisibilityPanelBase { + private JRadioButton myRbAsIs; + private JRadioButton myRbEscalate; + private final JRadioButton myRbPrivate; + private final JRadioButton myRbProtected; + private final JRadioButton myRbPackageLocal; + private final JRadioButton myRbPublic; + + public JavaVisibilityPanel(boolean hasAsIs, final boolean hasEscalate) { + setBorder(IdeBorderFactory.createTitledBorder(RefactoringBundle.message("visibility.border.title"), true, + new Insets(IdeBorderFactory.TITLED_BORDER_TOP_INSET, + UIUtil.DEFAULT_HGAP, + IdeBorderFactory.TITLED_BORDER_BOTTOM_INSET, + IdeBorderFactory.TITLED_BORDER_RIGHT_INSET))); + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + ButtonGroup bg = new ButtonGroup(); + + ItemListener listener = new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + myEventDispatcher.getMulticaster().stateChanged(new ChangeEvent(this)); + } + } + }; + + if (hasEscalate) { + myRbEscalate = new JRadioButton(); + myRbEscalate.setText(RefactoringBundle.getEscalateVisibility()); + myRbEscalate.addItemListener(listener); + add(myRbEscalate); + bg.add(myRbEscalate); + } + + if (hasAsIs) { + myRbAsIs = new JRadioButton(); + myRbAsIs.setText(RefactoringBundle.getVisibilityAsIs()); + myRbAsIs.addItemListener(listener); + add(myRbAsIs); + bg.add(myRbAsIs); + } + + + myRbPrivate = new JRadioButton(); + myRbPrivate.setText(RefactoringBundle.getVisibilityPrivate()); + myRbPrivate.addItemListener(listener); + myRbPrivate.setFocusable(false); + add(myRbPrivate); + bg.add(myRbPrivate); + + myRbPackageLocal = new JRadioButton(); + myRbPackageLocal.setText(RefactoringBundle.getVisibilityPackageLocal()); + myRbPackageLocal.addItemListener(listener); + myRbPackageLocal.setFocusable(false); + add(myRbPackageLocal); + bg.add(myRbPackageLocal); + + myRbProtected = new JRadioButton(); + myRbProtected.setText(RefactoringBundle.getVisibilityProtected()); + myRbProtected.addItemListener(listener); + myRbProtected.setFocusable(false); + add(myRbProtected); + bg.add(myRbProtected); + + myRbPublic = new JRadioButton(); + myRbPublic.setText(RefactoringBundle.getVisibilityPublic()); + myRbPublic.addItemListener(listener); + myRbPublic.setFocusable(false); + add(myRbPublic); + bg.add(myRbPublic); + } + + + @Nullable + public String getVisibility() { + if (myRbPublic.isSelected()) { + return PsiModifier.PUBLIC; + } + if (myRbPackageLocal.isSelected()) { + return PsiModifier.PACKAGE_LOCAL; + } + if (myRbProtected.isSelected()) { + return PsiModifier.PROTECTED; + } + if (myRbPrivate.isSelected()) { + return PsiModifier.PRIVATE; + } + if (myRbEscalate != null && myRbEscalate.isSelected()) { + return VisibilityUtil.ESCALATE_VISIBILITY; + } + + return null; + } + + public void setVisibility(@Nullable String visibility) { + if (PsiModifier.PUBLIC.equals(visibility)) { + myRbPublic.setSelected(true); + } + else if (PsiModifier.PROTECTED.equals(visibility)) { + myRbProtected.setSelected(true); + } + else if (PsiModifier.PACKAGE_LOCAL.equals(visibility)) { + myRbPackageLocal.setSelected(true); + } + else if (PsiModifier.PRIVATE.equals(visibility)) { + myRbPrivate.setSelected(true); + } + else if (myRbEscalate != null) { + myRbEscalate.setSelected(true); + } + else if (myRbAsIs != null) { + myRbAsIs.setSelected(true); + } + } + + public void disableAllButPublic() { + myRbPrivate.setEnabled(false); + myRbProtected.setEnabled(false); + myRbPackageLocal.setEnabled(false); + if (myRbEscalate != null) { + myRbEscalate.setEnabled(false); + } + if (myRbAsIs != null) { + myRbAsIs.setEnabled(false); + } + myRbPublic.setEnabled(true); + myRbPublic.setSelected(true); + } +} diff --git a/java/java-indexing-api/src/com/intellij/psi/search/searches/OverridingMethodsSearch.java b/java/java-indexing-api/src/com/intellij/psi/search/searches/OverridingMethodsSearch.java index e0b97e716a2b..4a5f5389e892 100644 --- a/java/java-indexing-api/src/com/intellij/psi/search/searches/OverridingMethodsSearch.java +++ b/java/java-indexing-api/src/com/intellij/psi/search/searches/OverridingMethodsSearch.java @@ -1,97 +1,97 @@ -/* - * 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.psi.search.searches; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.openapi.util.Computable; -import com.intellij.psi.PsiAnonymousClass; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiModifier; -import com.intellij.psi.search.SearchScope; -import com.intellij.util.EmptyQuery; -import com.intellij.util.Query; -import com.intellij.util.QueryExecutor; - -/** - * @author max - */ -public class OverridingMethodsSearch extends ExtensibleQueryFactory { - public static ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.overridingMethodsSearch"); - public static final OverridingMethodsSearch INSTANCE = new OverridingMethodsSearch(); - - public static class SearchParameters { - private final PsiMethod myMethod; - private final SearchScope myScope; - private final boolean myCheckDeep; - - public SearchParameters(final PsiMethod aClass, SearchScope scope, final boolean checkDeep) { - myMethod = aClass; - myScope = scope; - myCheckDeep = checkDeep; - } - - public PsiMethod getMethod() { - return myMethod; - } - - public boolean isCheckDeep() { - return myCheckDeep; - } - - public SearchScope getScope() { - return myScope; - } - } - - private OverridingMethodsSearch() { - } - - public static Query search(final PsiMethod method, SearchScope scope, final boolean checkDeep) { - if (ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public Boolean compute() { - return cannotBeOverriden(method); - } - })) return EmptyQuery.getEmptyQuery(); // Optimization - return INSTANCE.createUniqueResultsQuery(new SearchParameters(method, scope, checkDeep)); - } - - private static boolean cannotBeOverriden(final PsiMethod method) { - final PsiClass parentClass = method.getContainingClass(); - return parentClass == null - || method.isConstructor() - || method.hasModifierProperty(PsiModifier.STATIC) - || method.hasModifierProperty(PsiModifier.FINAL) - || method.hasModifierProperty(PsiModifier.PRIVATE) - || parentClass instanceof PsiAnonymousClass - || parentClass.hasModifierProperty(PsiModifier.FINAL); - } - - public static Query search(final PsiMethod method, final boolean checkDeep) { - return search(method, ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public SearchScope compute() { - return method.getUseScope(); - } - }), checkDeep); - } - - public static Query search(final PsiMethod method) { - return search(method, true); - } -} +/* + * 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.psi.search.searches; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.util.Computable; +import com.intellij.psi.PsiAnonymousClass; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.search.SearchScope; +import com.intellij.util.EmptyQuery; +import com.intellij.util.Query; +import com.intellij.util.QueryExecutor; + +/** + * @author max + */ +public class OverridingMethodsSearch extends ExtensibleQueryFactory { + public static ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.overridingMethodsSearch"); + public static final OverridingMethodsSearch INSTANCE = new OverridingMethodsSearch(); + + public static class SearchParameters { + private final PsiMethod myMethod; + private final SearchScope myScope; + private final boolean myCheckDeep; + + public SearchParameters(final PsiMethod aClass, SearchScope scope, final boolean checkDeep) { + myMethod = aClass; + myScope = scope; + myCheckDeep = checkDeep; + } + + public PsiMethod getMethod() { + return myMethod; + } + + public boolean isCheckDeep() { + return myCheckDeep; + } + + public SearchScope getScope() { + return myScope; + } + } + + private OverridingMethodsSearch() { + } + + public static Query search(final PsiMethod method, SearchScope scope, final boolean checkDeep) { + if (ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Boolean compute() { + return cannotBeOverriden(method); + } + })) return EmptyQuery.getEmptyQuery(); // Optimization + return INSTANCE.createUniqueResultsQuery(new SearchParameters(method, scope, checkDeep)); + } + + private static boolean cannotBeOverriden(final PsiMethod method) { + final PsiClass parentClass = method.getContainingClass(); + return parentClass == null + || method.isConstructor() + || method.hasModifierProperty(PsiModifier.STATIC) + || method.hasModifierProperty(PsiModifier.FINAL) + || method.hasModifierProperty(PsiModifier.PRIVATE) + || parentClass instanceof PsiAnonymousClass + || parentClass.hasModifierProperty(PsiModifier.FINAL); + } + + public static Query search(final PsiMethod method, final boolean checkDeep) { + return search(method, ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public SearchScope compute() { + return method.getUseScope(); + } + }), checkDeep); + } + + public static Query search(final PsiMethod method) { + return search(method, true); + } +} diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaOverridingMethodsSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaOverridingMethodsSearcher.java index 536553f125d2..9ccebc275493 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaOverridingMethodsSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaOverridingMethodsSearcher.java @@ -1,80 +1,80 @@ -package com.intellij.psi.impl.search; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.util.Computable; -import com.intellij.psi.*; -import com.intellij.psi.search.SearchScope; -import com.intellij.psi.search.searches.ClassInheritorsSearch; -import com.intellij.psi.search.searches.OverridingMethodsSearch; -import com.intellij.psi.util.MethodSignature; -import com.intellij.psi.util.MethodSignatureUtil; -import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.Processor; -import com.intellij.util.QueryExecutor; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * @author max - */ -public class JavaOverridingMethodsSearcher implements QueryExecutor { - @Override - public boolean execute(@NotNull final OverridingMethodsSearch.SearchParameters p, @NotNull final Processor consumer) { - final PsiMethod method = p.getMethod(); - final SearchScope scope = p.getScope(); - - final PsiClass parentClass = ApplicationManager.getApplication().runReadAction(new Computable() { - @Nullable - @Override - public PsiClass compute() { - return method.getContainingClass(); - } - }); - assert parentClass != null; - Processor inheritorsProcessor = new Processor() { - @Override - public boolean process(final PsiClass inheritor) { - PsiMethod found = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - @Nullable - public PsiMethod compute() { - return findOverridingMethod(inheritor, parentClass, method); - } - }); - return found == null || consumer.process(found) && p.isCheckDeep(); - } - }; - - return ClassInheritorsSearch.search(parentClass, scope, true).forEach(inheritorsProcessor); - } - - @Nullable - private static PsiMethod findOverridingMethod(PsiClass inheritor, @NotNull PsiClass parentClass, PsiMethod method) { - PsiSubstitutor substitutor = inheritor.isInheritor(parentClass, true) ? - TypeConversionUtil.getSuperClassSubstitutor(parentClass, inheritor, PsiSubstitutor.EMPTY) : - PsiSubstitutor.EMPTY; - MethodSignature signature = method.getSignature(substitutor); - PsiMethod found = MethodSignatureUtil.findMethodBySuperSignature(inheritor, signature, false); - if (found != null && isAcceptable(found, method)) { - return found; - } - - if (parentClass.isInterface() && !inheritor.isInterface()) { //check for sibling implementation - final PsiClass superClass = inheritor.getSuperClass(); - if (superClass != null && !superClass.isInheritor(parentClass, true)) { - PsiMethod derived = MethodSignatureUtil.findMethodInSuperClassBySignatureInDerived(inheritor, superClass, signature, true); - if (derived != null && isAcceptable(derived, method)) { - return derived; - } - } - } - return null; - } - - private static boolean isAcceptable(final PsiMethod found, final PsiMethod method) { - return !found.hasModifierProperty(PsiModifier.STATIC) && - (!method.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) || - JavaPsiFacade.getInstance(found.getProject()) - .arePackagesTheSame(method.getContainingClass(), found.getContainingClass())); - } -} +package com.intellij.psi.impl.search; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.Computable; +import com.intellij.psi.*; +import com.intellij.psi.search.SearchScope; +import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.psi.search.searches.OverridingMethodsSearch; +import com.intellij.psi.util.MethodSignature; +import com.intellij.psi.util.MethodSignatureUtil; +import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.util.Processor; +import com.intellij.util.QueryExecutor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author max + */ +public class JavaOverridingMethodsSearcher implements QueryExecutor { + @Override + public boolean execute(@NotNull final OverridingMethodsSearch.SearchParameters p, @NotNull final Processor consumer) { + final PsiMethod method = p.getMethod(); + final SearchScope scope = p.getScope(); + + final PsiClass parentClass = ApplicationManager.getApplication().runReadAction(new Computable() { + @Nullable + @Override + public PsiClass compute() { + return method.getContainingClass(); + } + }); + assert parentClass != null; + Processor inheritorsProcessor = new Processor() { + @Override + public boolean process(final PsiClass inheritor) { + PsiMethod found = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + @Nullable + public PsiMethod compute() { + return findOverridingMethod(inheritor, parentClass, method); + } + }); + return found == null || consumer.process(found) && p.isCheckDeep(); + } + }; + + return ClassInheritorsSearch.search(parentClass, scope, true).forEach(inheritorsProcessor); + } + + @Nullable + private static PsiMethod findOverridingMethod(PsiClass inheritor, @NotNull PsiClass parentClass, PsiMethod method) { + PsiSubstitutor substitutor = inheritor.isInheritor(parentClass, true) ? + TypeConversionUtil.getSuperClassSubstitutor(parentClass, inheritor, PsiSubstitutor.EMPTY) : + PsiSubstitutor.EMPTY; + MethodSignature signature = method.getSignature(substitutor); + PsiMethod found = MethodSignatureUtil.findMethodBySuperSignature(inheritor, signature, false); + if (found != null && isAcceptable(found, method)) { + return found; + } + + if (parentClass.isInterface() && !inheritor.isInterface()) { //check for sibling implementation + final PsiClass superClass = inheritor.getSuperClass(); + if (superClass != null && !superClass.isInheritor(parentClass, true)) { + PsiMethod derived = MethodSignatureUtil.findMethodInSuperClassBySignatureInDerived(inheritor, superClass, signature, true); + if (derived != null && isAcceptable(derived, method)) { + return derived; + } + } + } + return null; + } + + private static boolean isAcceptable(final PsiMethod found, final PsiMethod method) { + return !found.hasModifierProperty(PsiModifier.STATIC) && + (!method.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) || + JavaPsiFacade.getInstance(found.getProject()) + .arePackagesTheSame(method.getContainingClass(), found.getContainingClass())); + } +} diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/MethodSuperSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/MethodSuperSearcher.java index 8568dae67d92..d65e80e7f997 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/MethodSuperSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/MethodSuperSearcher.java @@ -1,71 +1,71 @@ -package com.intellij.psi.impl.search; - -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.psi.*; -import com.intellij.psi.search.searches.SuperMethodsSearch; -import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; -import com.intellij.psi.util.MethodSignatureUtil; -import com.intellij.util.Processor; -import com.intellij.util.QueryExecutor; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -/** - * @author ven - */ -public class MethodSuperSearcher implements QueryExecutor { - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.search.MethodSuperSearcher"); - - @Override - public boolean execute(@NotNull final SuperMethodsSearch.SearchParameters queryParameters, @NotNull final Processor consumer) { - final PsiClass parentClass = queryParameters.getPsiClass(); - final PsiMethod method = queryParameters.getMethod(); - HierarchicalMethodSignature signature = method.getHierarchicalMethodSignature(); - - final boolean checkBases = queryParameters.isCheckBases(); - final boolean allowStaticMethod = queryParameters.isAllowStaticMethod(); - final List supers = signature.getSuperSignatures(); - for (HierarchicalMethodSignature superSignature : supers) { - if (MethodSignatureUtil.isSubsignature(superSignature, signature)) { - if (!addSuperMethods(superSignature, method, parentClass, allowStaticMethod, checkBases, consumer)) return false; - } - } - - return true; - } - - private static boolean addSuperMethods(final HierarchicalMethodSignature signature, - final PsiMethod method, - final PsiClass parentClass, - final boolean allowStaticMethod, - final boolean checkBases, - final Processor consumer) { - PsiMethod signatureMethod = signature.getMethod(); - PsiClass hisClass = signatureMethod.getContainingClass(); - if (parentClass == null || InheritanceUtil.isInheritorOrSelf(parentClass, hisClass, true)) { - if (isAcceptable(signatureMethod, method, allowStaticMethod)) { - if (parentClass != null && !parentClass.equals(hisClass) && !checkBases) { - return true; - } - LOG.assertTrue(signatureMethod != method, method); // method != method.getsuper() - return consumer.process(signature); //no need to check super classes - } - } - for (HierarchicalMethodSignature superSignature : signature.getSuperSignatures()) { - if (MethodSignatureUtil.isSubsignature(superSignature, signature)) { - addSuperMethods(superSignature, method, parentClass, allowStaticMethod, checkBases, consumer); - } - } - - return true; - } - - private static boolean isAcceptable(final PsiMethod superMethod, final PsiMethod method, final boolean allowStaticMethod) { - boolean hisStatic = superMethod.hasModifierProperty(PsiModifier.STATIC); - return hisStatic == method.hasModifierProperty(PsiModifier.STATIC) && - (allowStaticMethod || !hisStatic) && - JavaPsiFacade.getInstance(method.getProject()).getResolveHelper().isAccessible(superMethod, method, null); - } -} +package com.intellij.psi.impl.search; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.psi.*; +import com.intellij.psi.search.searches.SuperMethodsSearch; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; +import com.intellij.psi.util.MethodSignatureUtil; +import com.intellij.util.Processor; +import com.intellij.util.QueryExecutor; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author ven + */ +public class MethodSuperSearcher implements QueryExecutor { + private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.search.MethodSuperSearcher"); + + @Override + public boolean execute(@NotNull final SuperMethodsSearch.SearchParameters queryParameters, @NotNull final Processor consumer) { + final PsiClass parentClass = queryParameters.getPsiClass(); + final PsiMethod method = queryParameters.getMethod(); + HierarchicalMethodSignature signature = method.getHierarchicalMethodSignature(); + + final boolean checkBases = queryParameters.isCheckBases(); + final boolean allowStaticMethod = queryParameters.isAllowStaticMethod(); + final List supers = signature.getSuperSignatures(); + for (HierarchicalMethodSignature superSignature : supers) { + if (MethodSignatureUtil.isSubsignature(superSignature, signature)) { + if (!addSuperMethods(superSignature, method, parentClass, allowStaticMethod, checkBases, consumer)) return false; + } + } + + return true; + } + + private static boolean addSuperMethods(final HierarchicalMethodSignature signature, + final PsiMethod method, + final PsiClass parentClass, + final boolean allowStaticMethod, + final boolean checkBases, + final Processor consumer) { + PsiMethod signatureMethod = signature.getMethod(); + PsiClass hisClass = signatureMethod.getContainingClass(); + if (parentClass == null || InheritanceUtil.isInheritorOrSelf(parentClass, hisClass, true)) { + if (isAcceptable(signatureMethod, method, allowStaticMethod)) { + if (parentClass != null && !parentClass.equals(hisClass) && !checkBases) { + return true; + } + LOG.assertTrue(signatureMethod != method, method); // method != method.getsuper() + return consumer.process(signature); //no need to check super classes + } + } + for (HierarchicalMethodSignature superSignature : signature.getSuperSignatures()) { + if (MethodSignatureUtil.isSubsignature(superSignature, signature)) { + addSuperMethods(superSignature, method, parentClass, allowStaticMethod, checkBases, consumer); + } + } + + return true; + } + + private static boolean isAcceptable(final PsiMethod superMethod, final PsiMethod method, final boolean allowStaticMethod) { + boolean hisStatic = superMethod.hasModifierProperty(PsiModifier.STATIC); + return hisStatic == method.hasModifierProperty(PsiModifier.STATIC) && + (allowStaticMethod || !hisStatic) && + JavaPsiFacade.getInstance(method.getProject()).getResolveHelper().isAccessible(superMethod, method, null); + } +} diff --git a/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java b/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java index 9f24c2a5085c..174438533371 100644 --- a/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java +++ b/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java @@ -1,213 +1,213 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * @author max - */ -package com.intellij.psi.codeStyle; - -import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.project.Project; -import com.intellij.psi.*; -import com.intellij.util.IncorrectOperationException; -import org.intellij.lang.annotations.MagicConstant; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collection; - -public abstract class JavaCodeStyleManager { - public static JavaCodeStyleManager getInstance(Project project) { - return ServiceManager.getService(project, JavaCodeStyleManager.class); - } - - public static final int DO_NOT_ADD_IMPORTS = 0x1000; - public static final int UNCOMPLETE_CODE = 0x2000; - - public abstract boolean addImport(@NotNull PsiJavaFile file, @NotNull PsiClass refClass); - public abstract PsiElement shortenClassReferences(@NotNull PsiElement element, @MagicConstant(flags = {DO_NOT_ADD_IMPORTS, UNCOMPLETE_CODE}) int flags) throws IncorrectOperationException; - - @NotNull public abstract String getPrefixByVariableKind(VariableKind variableKind); - @NotNull public abstract String getSuffixByVariableKind(VariableKind variableKind); - - public abstract int findEntryIndex(@NotNull PsiImportStatementBase statement); - - /** - * Replaces fully-qualified class names in the contents of the specified element with - * non-qualified names and adds import statements as necessary. - * - * @param element the element to shorten references in. - * @return the element in the PSI tree after the shorten references operation corresponding - * to the original element. - * @throws com.intellij.util.IncorrectOperationException if the file to shorten references in is read-only. - */ - public abstract PsiElement shortenClassReferences(@NotNull PsiElement element) throws IncorrectOperationException; - - /** - * Replaces fully-qualified class names in a part of contents of the specified element with - * non-qualified names and adds import statements as necessary. - * - * @param element the element to shorten references in. - * @param startOffset the start offset in the element of the part where class references are - * shortened. - * @param endOffset the end offset in the element of the part where class references are - * shortened. - * @throws IncorrectOperationException if the file to shorten references in is read-only. - */ - public abstract void shortenClassReferences(@NotNull PsiElement element, int startOffset, int endOffset) throws IncorrectOperationException; - - /** - * Optimizes imports in the specified Java or JSP file. - * - * @param file the file to optimize the imports in. - * @throws IncorrectOperationException if the file is read-only. - */ - public abstract void optimizeImports(@NotNull PsiFile file) throws IncorrectOperationException; - - /** - * Calculates the import list that would be substituted in the specified Java or JSP - * file if an Optimize Imports operation was performed on it. - * - * @param file the file to calculate the import list for. - * @return the calculated import list. - */ - public abstract PsiImportList prepareOptimizeImportsResult(@NotNull PsiJavaFile file); - - /** - * Returns the kind of the specified variable (local, parameter, field, static field or static - * final field). - * - * @param variable the variable to get the kind for. - * @return the variable kind. - */ - public VariableKind getVariableKind(@NotNull PsiVariable variable){ - if (variable instanceof PsiField) { - if (variable.hasModifierProperty(PsiModifier.STATIC)) { - if (variable.hasModifierProperty(PsiModifier.FINAL)) { - return VariableKind.STATIC_FINAL_FIELD; - } - return VariableKind.STATIC_FIELD; - } - return VariableKind.FIELD; - } - else { - if (variable instanceof PsiParameter) { - if (((PsiParameter)variable).getDeclarationScope() instanceof PsiForeachStatement) { - return VariableKind.LOCAL_VARIABLE; - } - return VariableKind.PARAMETER; - } - return VariableKind.LOCAL_VARIABLE; - } - } - - public SuggestedNameInfo suggestVariableName(@NotNull final VariableKind kind, - @Nullable final String propertyName, - @Nullable final PsiExpression expr, - @Nullable PsiType type) { - return suggestVariableName(kind, propertyName, expr, type, true); - } - - - public abstract SuggestedNameInfo suggestVariableName(@NotNull VariableKind kind, - @Nullable String propertyName, - @Nullable PsiExpression expr, - @Nullable PsiType type, - boolean correctKeywords); - /** - * Generates a stripped-down name (with no code style defined prefixes or suffixes, usable as - * a property name) from the specified name of a variable of the specified kind. - * - * @param name the name of the variable. - * @param variableKind the kind of the variable. - * @return the stripped-down name. - */ - public abstract String variableNameToPropertyName(@NonNls String name, VariableKind variableKind); - - /** - * Appends code style defined prefixes and/or suffixes for the specified variable kind - * to the specified variable name. - * - * @param propertyName the base name of the variable. - * @param variableKind the kind of the variable. - * @return the variable name. - */ - public abstract String propertyNameToVariableName(@NonNls String propertyName, VariableKind variableKind); - - /** - * Suggests a unique name for the variable used at the specified location. - * - * @param baseName the base name for the variable. - * @param place the location where the variable will be used. - * @param lookForward if true, the existing variables are searched in both directions; if false - only backward - * @return the generated unique name, - */ - public abstract String suggestUniqueVariableName(@NonNls String baseName, PsiElement place, boolean lookForward); - - /** - * Suggests a unique name for the variable used at the specified location. - * - * @param baseNameInfo the base name info for the variable. - * @param place the location where the variable will be used. - * @param lookForward if true, the existing variables are searched in both directions; if false - only backward - * @return the generated unique name - */ - @NotNull - public SuggestedNameInfo suggestUniqueVariableName(@NotNull SuggestedNameInfo baseNameInfo, - PsiElement place, - boolean lookForward) { - return suggestUniqueVariableName(baseNameInfo, place, false, lookForward); - } - - /** - * Suggests a unique name for the variable used at the specified location. - * - * - * @param baseNameInfo the base name info for the variable. - * @param place the location where the variable will be used. - * @param ignorePlaceName if true and place is PsiNamedElement, place.getName() would be still treated as unique name - * @param lookForward if true, the existing variables are searched in both directions; if false - only backward @return the generated unique name, - * @return the generated unique name - */ - @NotNull public abstract SuggestedNameInfo suggestUniqueVariableName(@NotNull SuggestedNameInfo baseNameInfo, - PsiElement place, - boolean ignorePlaceName, - boolean lookForward); - - /** - * Replaces all references to Java classes in the contents of the specified element, - * except for references to classes in the same package or in implicitly imported packages, - * with full-qualified references. - * - * @param element the element to replace the references in. - * @return the element in the PSI tree after the qualify operation corresponding to the - * original element. - */ - public abstract PsiElement qualifyClassReferences(@NotNull PsiElement element); - - /** - * Removes unused import statements from the specified Java file. - * - * @param file the file to remove the import statements from. - * @throws IncorrectOperationException if the operation fails for some reason (for example, - * the file is read-only). - */ - public abstract void removeRedundantImports(@NotNull PsiJavaFile file) throws IncorrectOperationException; - - @Nullable - public abstract Collection findRedundantImports(PsiJavaFile file); -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @author max + */ +package com.intellij.psi.codeStyle; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +public abstract class JavaCodeStyleManager { + public static JavaCodeStyleManager getInstance(Project project) { + return ServiceManager.getService(project, JavaCodeStyleManager.class); + } + + public static final int DO_NOT_ADD_IMPORTS = 0x1000; + public static final int UNCOMPLETE_CODE = 0x2000; + + public abstract boolean addImport(@NotNull PsiJavaFile file, @NotNull PsiClass refClass); + public abstract PsiElement shortenClassReferences(@NotNull PsiElement element, @MagicConstant(flags = {DO_NOT_ADD_IMPORTS, UNCOMPLETE_CODE}) int flags) throws IncorrectOperationException; + + @NotNull public abstract String getPrefixByVariableKind(VariableKind variableKind); + @NotNull public abstract String getSuffixByVariableKind(VariableKind variableKind); + + public abstract int findEntryIndex(@NotNull PsiImportStatementBase statement); + + /** + * Replaces fully-qualified class names in the contents of the specified element with + * non-qualified names and adds import statements as necessary. + * + * @param element the element to shorten references in. + * @return the element in the PSI tree after the shorten references operation corresponding + * to the original element. + * @throws com.intellij.util.IncorrectOperationException if the file to shorten references in is read-only. + */ + public abstract PsiElement shortenClassReferences(@NotNull PsiElement element) throws IncorrectOperationException; + + /** + * Replaces fully-qualified class names in a part of contents of the specified element with + * non-qualified names and adds import statements as necessary. + * + * @param element the element to shorten references in. + * @param startOffset the start offset in the element of the part where class references are + * shortened. + * @param endOffset the end offset in the element of the part where class references are + * shortened. + * @throws IncorrectOperationException if the file to shorten references in is read-only. + */ + public abstract void shortenClassReferences(@NotNull PsiElement element, int startOffset, int endOffset) throws IncorrectOperationException; + + /** + * Optimizes imports in the specified Java or JSP file. + * + * @param file the file to optimize the imports in. + * @throws IncorrectOperationException if the file is read-only. + */ + public abstract void optimizeImports(@NotNull PsiFile file) throws IncorrectOperationException; + + /** + * Calculates the import list that would be substituted in the specified Java or JSP + * file if an Optimize Imports operation was performed on it. + * + * @param file the file to calculate the import list for. + * @return the calculated import list. + */ + public abstract PsiImportList prepareOptimizeImportsResult(@NotNull PsiJavaFile file); + + /** + * Returns the kind of the specified variable (local, parameter, field, static field or static + * final field). + * + * @param variable the variable to get the kind for. + * @return the variable kind. + */ + public VariableKind getVariableKind(@NotNull PsiVariable variable){ + if (variable instanceof PsiField) { + if (variable.hasModifierProperty(PsiModifier.STATIC)) { + if (variable.hasModifierProperty(PsiModifier.FINAL)) { + return VariableKind.STATIC_FINAL_FIELD; + } + return VariableKind.STATIC_FIELD; + } + return VariableKind.FIELD; + } + else { + if (variable instanceof PsiParameter) { + if (((PsiParameter)variable).getDeclarationScope() instanceof PsiForeachStatement) { + return VariableKind.LOCAL_VARIABLE; + } + return VariableKind.PARAMETER; + } + return VariableKind.LOCAL_VARIABLE; + } + } + + public SuggestedNameInfo suggestVariableName(@NotNull final VariableKind kind, + @Nullable final String propertyName, + @Nullable final PsiExpression expr, + @Nullable PsiType type) { + return suggestVariableName(kind, propertyName, expr, type, true); + } + + + public abstract SuggestedNameInfo suggestVariableName(@NotNull VariableKind kind, + @Nullable String propertyName, + @Nullable PsiExpression expr, + @Nullable PsiType type, + boolean correctKeywords); + /** + * Generates a stripped-down name (with no code style defined prefixes or suffixes, usable as + * a property name) from the specified name of a variable of the specified kind. + * + * @param name the name of the variable. + * @param variableKind the kind of the variable. + * @return the stripped-down name. + */ + public abstract String variableNameToPropertyName(@NonNls String name, VariableKind variableKind); + + /** + * Appends code style defined prefixes and/or suffixes for the specified variable kind + * to the specified variable name. + * + * @param propertyName the base name of the variable. + * @param variableKind the kind of the variable. + * @return the variable name. + */ + public abstract String propertyNameToVariableName(@NonNls String propertyName, VariableKind variableKind); + + /** + * Suggests a unique name for the variable used at the specified location. + * + * @param baseName the base name for the variable. + * @param place the location where the variable will be used. + * @param lookForward if true, the existing variables are searched in both directions; if false - only backward + * @return the generated unique name, + */ + public abstract String suggestUniqueVariableName(@NonNls String baseName, PsiElement place, boolean lookForward); + + /** + * Suggests a unique name for the variable used at the specified location. + * + * @param baseNameInfo the base name info for the variable. + * @param place the location where the variable will be used. + * @param lookForward if true, the existing variables are searched in both directions; if false - only backward + * @return the generated unique name + */ + @NotNull + public SuggestedNameInfo suggestUniqueVariableName(@NotNull SuggestedNameInfo baseNameInfo, + PsiElement place, + boolean lookForward) { + return suggestUniqueVariableName(baseNameInfo, place, false, lookForward); + } + + /** + * Suggests a unique name for the variable used at the specified location. + * + * + * @param baseNameInfo the base name info for the variable. + * @param place the location where the variable will be used. + * @param ignorePlaceName if true and place is PsiNamedElement, place.getName() would be still treated as unique name + * @param lookForward if true, the existing variables are searched in both directions; if false - only backward @return the generated unique name, + * @return the generated unique name + */ + @NotNull public abstract SuggestedNameInfo suggestUniqueVariableName(@NotNull SuggestedNameInfo baseNameInfo, + PsiElement place, + boolean ignorePlaceName, + boolean lookForward); + + /** + * Replaces all references to Java classes in the contents of the specified element, + * except for references to classes in the same package or in implicitly imported packages, + * with full-qualified references. + * + * @param element the element to replace the references in. + * @return the element in the PSI tree after the qualify operation corresponding to the + * original element. + */ + public abstract PsiElement qualifyClassReferences(@NotNull PsiElement element); + + /** + * Removes unused import statements from the specified Java file. + * + * @param file the file to remove the import statements from. + * @throws IncorrectOperationException if the operation fails for some reason (for example, + * the file is read-only). + */ + public abstract void removeRedundantImports(@NotNull PsiJavaFile file) throws IncorrectOperationException; + + @Nullable + public abstract Collection findRedundantImports(PsiJavaFile file); +} diff --git a/java/java-psi-api/src/com/intellij/psi/search/searches/SuperMethodsSearch.java b/java/java-psi-api/src/com/intellij/psi/search/searches/SuperMethodsSearch.java index 153feb82314a..877094929876 100644 --- a/java/java-psi-api/src/com/intellij/psi/search/searches/SuperMethodsSearch.java +++ b/java/java-psi-api/src/com/intellij/psi/search/searches/SuperMethodsSearch.java @@ -1,77 +1,77 @@ -/* - * 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.psi.search.searches; - -import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; -import com.intellij.psi.util.MethodSignatureUtil; -import com.intellij.util.Query; -import com.intellij.util.QueryExecutor; -import org.jetbrains.annotations.Nullable; - -/** - * @author max - */ -public class SuperMethodsSearch extends ExtensibleQueryFactory { - public static ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.superMethodsSearch"); - public static final SuperMethodsSearch SUPER_METHODS_SEARCH_INSTANCE = new SuperMethodsSearch(); - - public static class SearchParameters { - private final PsiMethod myMethod; - //null means any class would be matched - @Nullable private final PsiClass myClass; - private final boolean myCheckBases; - private final boolean myAllowStaticMethod; - - public SearchParameters(final PsiMethod method, - @Nullable final PsiClass aClass, - final boolean checkBases, - final boolean allowStaticMethod) { - myCheckBases = checkBases; - myClass = aClass; - myMethod = method; - myAllowStaticMethod = allowStaticMethod; - } - - public final boolean isCheckBases() { - return myCheckBases; - } - - public final PsiMethod getMethod() { - return myMethod; - } - - @Nullable - public final PsiClass getPsiClass() { - return myClass; - } - - public final boolean isAllowStaticMethod() { - return myAllowStaticMethod; - } - } - - private SuperMethodsSearch() { - } - - public static Query search(final PsiMethod derivedMethod, @Nullable final PsiClass psiClass, boolean checkBases, boolean allowStaticMethod) { - final SearchParameters parameters = new SearchParameters(derivedMethod, psiClass, checkBases, allowStaticMethod); - return SUPER_METHODS_SEARCH_INSTANCE.createUniqueResultsQuery(parameters, MethodSignatureUtil.METHOD_BASED_HASHING_STRATEGY); - } - -} +/* + * 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.psi.search.searches; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; +import com.intellij.psi.util.MethodSignatureUtil; +import com.intellij.util.Query; +import com.intellij.util.QueryExecutor; +import org.jetbrains.annotations.Nullable; + +/** + * @author max + */ +public class SuperMethodsSearch extends ExtensibleQueryFactory { + public static ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.superMethodsSearch"); + public static final SuperMethodsSearch SUPER_METHODS_SEARCH_INSTANCE = new SuperMethodsSearch(); + + public static class SearchParameters { + private final PsiMethod myMethod; + //null means any class would be matched + @Nullable private final PsiClass myClass; + private final boolean myCheckBases; + private final boolean myAllowStaticMethod; + + public SearchParameters(final PsiMethod method, + @Nullable final PsiClass aClass, + final boolean checkBases, + final boolean allowStaticMethod) { + myCheckBases = checkBases; + myClass = aClass; + myMethod = method; + myAllowStaticMethod = allowStaticMethod; + } + + public final boolean isCheckBases() { + return myCheckBases; + } + + public final PsiMethod getMethod() { + return myMethod; + } + + @Nullable + public final PsiClass getPsiClass() { + return myClass; + } + + public final boolean isAllowStaticMethod() { + return myAllowStaticMethod; + } + } + + private SuperMethodsSearch() { + } + + public static Query search(final PsiMethod derivedMethod, @Nullable final PsiClass psiClass, boolean checkBases, boolean allowStaticMethod) { + final SearchParameters parameters = new SearchParameters(derivedMethod, psiClass, checkBases, allowStaticMethod); + return SUPER_METHODS_SEARCH_INSTANCE.createUniqueResultsQuery(parameters, MethodSignatureUtil.METHOD_BASED_HASHING_STRATEGY); + } + +} diff --git a/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java b/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java index e311029cd77d..0637149120c3 100644 --- a/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java +++ b/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java @@ -1,188 +1,188 @@ -/* - * 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.core; - -import com.intellij.openapi.util.Comparing; -import com.intellij.psi.*; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.codeStyle.SuggestedNameInfo; -import com.intellij.psi.codeStyle.VariableKind; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.util.ArrayUtil; -import com.intellij.util.IncorrectOperationException; -import org.intellij.lang.annotations.MagicConstant; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collection; -import java.util.LinkedHashSet; - -public class CoreJavaCodeStyleManager extends JavaCodeStyleManager { - @Override - public boolean addImport(@NotNull PsiJavaFile file, @NotNull PsiClass refClass) { - return false; - } - - @Override - public PsiElement shortenClassReferences(@NotNull PsiElement element, - @MagicConstant(flags = {DO_NOT_ADD_IMPORTS, UNCOMPLETE_CODE}) int flags) - throws IncorrectOperationException { - return null; - } - - @NotNull - @Override - public String getPrefixByVariableKind(VariableKind variableKind) { - return ""; - } - - @NotNull - @Override - public String getSuffixByVariableKind(VariableKind variableKind) { - return ""; - } - - @Override - public int findEntryIndex(@NotNull PsiImportStatementBase statement) { - return 0; - } - - @Override - public PsiElement shortenClassReferences(@NotNull PsiElement element) throws IncorrectOperationException { - return null; - } - - @Override - public void shortenClassReferences(@NotNull PsiElement element, int startOffset, int endOffset) throws IncorrectOperationException { - } - - @Override - public void optimizeImports(@NotNull PsiFile file) throws IncorrectOperationException { - } - - @Override - public PsiImportList prepareOptimizeImportsResult(@NotNull PsiJavaFile file) { - return null; - } - - @Override - public SuggestedNameInfo suggestVariableName(@NotNull VariableKind kind, - @Nullable String propertyName, - @Nullable PsiExpression expr, - @Nullable PsiType type, - boolean correctKeywords) { - return SuggestedNameInfo.NULL_INFO; - } - - @Override - public String variableNameToPropertyName(@NonNls String name, VariableKind variableKind) { - return null; - } - - @Override - public String propertyNameToVariableName(@NonNls String propertyName, VariableKind variableKind) { - return null; - } - - @Override - public String suggestUniqueVariableName(@NonNls String baseName, PsiElement place, boolean lookForward) { - int index = 0; - PsiElement scope = PsiTreeUtil.getNonStrictParentOfType(place, PsiStatement.class, PsiCodeBlock.class, PsiMethod.class); - NextName: - while (true) { - String name = baseName; - if (index > 0) { - name += index; - } - index++; - if (PsiUtil.isVariableNameUnique(name, place)) { - if (lookForward) { - final String name1 = name; - PsiElement run = scope; - while (run != null) { - class CancelException extends RuntimeException { - } - try { - run.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitAnonymousClass(final PsiAnonymousClass aClass) { - } - - @Override public void visitVariable(PsiVariable variable) { - if (name1.equals(variable.getName())) { - throw new CancelException(); - } - } - }); - } - catch (CancelException e) { - continue NextName; - } - run = run.getNextSibling(); - if (scope instanceof PsiMethod) {//do not check next member for param name conflict - break; - } - } - - } - return name; - } - } - } - - @NotNull - @Override - public SuggestedNameInfo suggestUniqueVariableName(@NotNull final SuggestedNameInfo baseNameInfo, - PsiElement place, - boolean ignorePlaceName, - boolean lookForward) { - final String[] names = baseNameInfo.names; - final LinkedHashSet uniqueNames = new LinkedHashSet(names.length); - for (String name : names) { - if (ignorePlaceName && place instanceof PsiNamedElement) { - final String placeName = ((PsiNamedElement)place).getName(); - if (Comparing.strEqual(placeName, name)) { - uniqueNames.add(name); - continue; - } - } - uniqueNames.add(suggestUniqueVariableName(name, place, lookForward)); - } - - return new SuggestedNameInfo(ArrayUtil.toStringArray(uniqueNames)) { - @Override - public void nameChosen(String name) { - baseNameInfo.nameChosen(name); - } - }; - } - - @Override - public PsiElement qualifyClassReferences(@NotNull PsiElement element) { - return element; - } - - @Override - public void removeRedundantImports(@NotNull PsiJavaFile file) throws IncorrectOperationException { - } - - @Override - public Collection findRedundantImports(PsiJavaFile file) { - return null; - } -} +/* + * 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.core; + +import com.intellij.openapi.util.Comparing; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.SuggestedNameInfo; +import com.intellij.psi.codeStyle.VariableKind; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import com.intellij.util.ArrayUtil; +import com.intellij.util.IncorrectOperationException; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.LinkedHashSet; + +public class CoreJavaCodeStyleManager extends JavaCodeStyleManager { + @Override + public boolean addImport(@NotNull PsiJavaFile file, @NotNull PsiClass refClass) { + return false; + } + + @Override + public PsiElement shortenClassReferences(@NotNull PsiElement element, + @MagicConstant(flags = {DO_NOT_ADD_IMPORTS, UNCOMPLETE_CODE}) int flags) + throws IncorrectOperationException { + return null; + } + + @NotNull + @Override + public String getPrefixByVariableKind(VariableKind variableKind) { + return ""; + } + + @NotNull + @Override + public String getSuffixByVariableKind(VariableKind variableKind) { + return ""; + } + + @Override + public int findEntryIndex(@NotNull PsiImportStatementBase statement) { + return 0; + } + + @Override + public PsiElement shortenClassReferences(@NotNull PsiElement element) throws IncorrectOperationException { + return null; + } + + @Override + public void shortenClassReferences(@NotNull PsiElement element, int startOffset, int endOffset) throws IncorrectOperationException { + } + + @Override + public void optimizeImports(@NotNull PsiFile file) throws IncorrectOperationException { + } + + @Override + public PsiImportList prepareOptimizeImportsResult(@NotNull PsiJavaFile file) { + return null; + } + + @Override + public SuggestedNameInfo suggestVariableName(@NotNull VariableKind kind, + @Nullable String propertyName, + @Nullable PsiExpression expr, + @Nullable PsiType type, + boolean correctKeywords) { + return SuggestedNameInfo.NULL_INFO; + } + + @Override + public String variableNameToPropertyName(@NonNls String name, VariableKind variableKind) { + return null; + } + + @Override + public String propertyNameToVariableName(@NonNls String propertyName, VariableKind variableKind) { + return null; + } + + @Override + public String suggestUniqueVariableName(@NonNls String baseName, PsiElement place, boolean lookForward) { + int index = 0; + PsiElement scope = PsiTreeUtil.getNonStrictParentOfType(place, PsiStatement.class, PsiCodeBlock.class, PsiMethod.class); + NextName: + while (true) { + String name = baseName; + if (index > 0) { + name += index; + } + index++; + if (PsiUtil.isVariableNameUnique(name, place)) { + if (lookForward) { + final String name1 = name; + PsiElement run = scope; + while (run != null) { + class CancelException extends RuntimeException { + } + try { + run.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitAnonymousClass(final PsiAnonymousClass aClass) { + } + + @Override public void visitVariable(PsiVariable variable) { + if (name1.equals(variable.getName())) { + throw new CancelException(); + } + } + }); + } + catch (CancelException e) { + continue NextName; + } + run = run.getNextSibling(); + if (scope instanceof PsiMethod) {//do not check next member for param name conflict + break; + } + } + + } + return name; + } + } + } + + @NotNull + @Override + public SuggestedNameInfo suggestUniqueVariableName(@NotNull final SuggestedNameInfo baseNameInfo, + PsiElement place, + boolean ignorePlaceName, + boolean lookForward) { + final String[] names = baseNameInfo.names; + final LinkedHashSet uniqueNames = new LinkedHashSet(names.length); + for (String name : names) { + if (ignorePlaceName && place instanceof PsiNamedElement) { + final String placeName = ((PsiNamedElement)place).getName(); + if (Comparing.strEqual(placeName, name)) { + uniqueNames.add(name); + continue; + } + } + uniqueNames.add(suggestUniqueVariableName(name, place, lookForward)); + } + + return new SuggestedNameInfo(ArrayUtil.toStringArray(uniqueNames)) { + @Override + public void nameChosen(String name) { + baseNameInfo.nameChosen(name); + } + }; + } + + @Override + public PsiElement qualifyClassReferences(@NotNull PsiElement element) { + return element; + } + + @Override + public void removeRedundantImports(@NotNull PsiJavaFile file) throws IncorrectOperationException { + } + + @Override + public Collection findRedundantImports(PsiJavaFile file) { + return null; + } +} diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java b/java/java-psi-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java index fe0ad6e7dc38..fa0a470e65f7 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java @@ -1,56 +1,56 @@ -/* - * 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.psi.impl; - -import com.intellij.psi.CommonClassNames; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.util.PsiSuperMethodUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - -public class FindSuperElementsHelper { - @Nullable - public static PsiElement[] findSuperElements(@NotNull PsiElement element) { - if (element instanceof PsiClass) { - PsiClass aClass = (PsiClass) element; - List allSupers = new ArrayList(Arrays.asList(aClass.getSupers())); - for (Iterator iterator = allSupers.iterator(); iterator.hasNext();) { - PsiClass superClass = iterator.next(); - if (CommonClassNames.JAVA_LANG_OBJECT.equals(superClass.getQualifiedName())) iterator.remove(); - } - return allSupers.toArray(new PsiClass[allSupers.size()]); - } else if (element instanceof PsiMethod) { - PsiMethod method = (PsiMethod) element; - if (method.isConstructor()) { - PsiMethod constructorInSuper = PsiSuperMethodUtil.findConstructorInSuper(method); - if (constructorInSuper != null) { - return new PsiMethod[]{constructorInSuper}; - } - } else { - return method.findSuperMethods(false); - } - } - return null; - } - -} +/* + * 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.psi.impl; + +import com.intellij.psi.CommonClassNames; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.util.PsiSuperMethodUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +public class FindSuperElementsHelper { + @Nullable + public static PsiElement[] findSuperElements(@NotNull PsiElement element) { + if (element instanceof PsiClass) { + PsiClass aClass = (PsiClass) element; + List allSupers = new ArrayList(Arrays.asList(aClass.getSupers())); + for (Iterator iterator = allSupers.iterator(); iterator.hasNext();) { + PsiClass superClass = iterator.next(); + if (CommonClassNames.JAVA_LANG_OBJECT.equals(superClass.getQualifiedName())) iterator.remove(); + } + return allSupers.toArray(new PsiClass[allSupers.size()]); + } else if (element instanceof PsiMethod) { + PsiMethod method = (PsiMethod) element; + if (method.isConstructor()) { + PsiMethod constructorInSuper = PsiSuperMethodUtil.findConstructorInSuper(method); + if (constructorInSuper != null) { + return new PsiMethod[]{constructorInSuper}; + } + } else { + return method.findSuperMethods(false); + } + } + return null; + } + +} diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLiteralExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLiteralExpressionImpl.java index a1c40acd6522..74d1350b3dc7 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLiteralExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLiteralExpressionImpl.java @@ -1,401 +1,401 @@ -/* - * 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.psi.impl.source.tree.java; - -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.*; -import com.intellij.psi.impl.PsiManagerEx; -import com.intellij.psi.impl.ResolveScopeManager; -import com.intellij.psi.impl.source.tree.JavaElementType; -import com.intellij.psi.impl.source.tree.LeafElement; -import com.intellij.psi.impl.source.tree.TreeElement; -import com.intellij.psi.impl.source.tree.injected.StringLiteralEscaper; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.tree.IElementType; -import com.intellij.psi.tree.TokenSet; -import com.intellij.util.text.LiteralFormatUtil; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class PsiLiteralExpressionImpl - extends ExpressionPsiElement - implements PsiLiteralExpression, PsiLanguageInjectionHost, ContributedReferenceHost { - @NonNls private static final String QUOT = """; - - @NonNls public static final String HEX_PREFIX = "0x"; - @NonNls public static final String BIN_PREFIX = "0b"; - @NonNls public static final String _2_IN_31 = Long.toString(-1L << 31).substring(1); - @NonNls public static final String _2_IN_63 = Long.toString(-1L << 63).substring(1); - public static final TokenSet INTEGER_LITERALS = TokenSet.create(JavaTokenType.INTEGER_LITERAL, JavaTokenType.LONG_LITERAL); - public static final TokenSet REAL_LITERALS = TokenSet.create(JavaTokenType.FLOAT_LITERAL, JavaTokenType.DOUBLE_LITERAL); - public static final TokenSet NUMERIC_LITERALS = TokenSet.orSet(INTEGER_LITERALS, REAL_LITERALS); - - public PsiLiteralExpressionImpl() { - super(JavaElementType.LITERAL_EXPRESSION); - } - - @Override - public PsiType getType() { - final IElementType type = getLiteralElementType(); - if (type == JavaTokenType.INTEGER_LITERAL) { - return PsiType.INT; - } - if (type == JavaTokenType.LONG_LITERAL) { - return PsiType.LONG; - } - if (type == JavaTokenType.FLOAT_LITERAL) { - return PsiType.FLOAT; - } - if (type == JavaTokenType.DOUBLE_LITERAL) { - return PsiType.DOUBLE; - } - if (type == JavaTokenType.CHARACTER_LITERAL) { - return PsiType.CHAR; - } - if (type == JavaTokenType.STRING_LITERAL) { - PsiManagerEx manager = getManager(); - GlobalSearchScope resolveScope = ResolveScopeManager.getElementResolveScope(this); - return PsiType.getJavaLangString(manager, resolveScope); - } - if (type == JavaTokenType.TRUE_KEYWORD || type == JavaTokenType.FALSE_KEYWORD) { - return PsiType.BOOLEAN; - } - if (type == JavaTokenType.NULL_KEYWORD) { - return PsiType.NULL; - } - return null; - } - - public IElementType getLiteralElementType() { - return getFirstChildNode().getElementType(); - } - - public String getCanonicalText() { - final TreeElement literal = getFirstChildNode(); - final IElementType type = literal.getElementType(); - return NUMERIC_LITERALS.contains(type) ? LiteralFormatUtil.removeUnderscores(literal.getText()) : literal.getText(); - } - - @Override - public Object getValue() { - final IElementType type = getLiteralElementType(); - String text = NUMERIC_LITERALS.contains(type) ? getCanonicalText().toLowerCase() : getCanonicalText(); - final int textLength = text.length(); - - if (type == JavaTokenType.INTEGER_LITERAL) { - try { - if (text.startsWith(HEX_PREFIX)) { - // should fit in 32 bits - final long value = parseDigits(text.substring(2), 4, 32); - return Integer.valueOf((int)value); - } - if (text.startsWith(BIN_PREFIX)) { - // should fit in 32 bits - final long value = parseDigits(text.substring(2), 1, 32); - return Integer.valueOf((int)value); - } - if (StringUtil.startsWithChar(text, '0')) { - // should fit in 32 bits - final long value = parseDigits(text, 3, 32); - return Integer.valueOf((int)value); - } - final long l = Long.parseLong(text, 10); - if (text.equals(_2_IN_31)) return Integer.valueOf((int)l); - long converted = (int)l; - return l == converted ? Integer.valueOf((int)l) : null; - } - catch (NumberFormatException e) { - return null; - } - } - if (type == JavaTokenType.LONG_LITERAL) { - if (StringUtil.endsWithChar(text, 'L') || StringUtil.endsWithChar(text, 'l')) { - text = text.substring(0, textLength - 1); - } - try { - if (text.startsWith(HEX_PREFIX)) { - return parseDigits(text.substring(2), 4, 64); - } - if (text.startsWith(BIN_PREFIX)) { - return parseDigits(text.substring(2), 1, 64); - } - if (StringUtil.startsWithChar(text, '0')) { - // should fit in 64 bits - return parseDigits(text, 3, 64); - } - if (_2_IN_63.equals(text)) return Long.valueOf(-1L << 63); - return Long.valueOf(text, 10); - } - catch (NumberFormatException e) { - return null; - } - } - if (type == JavaTokenType.FLOAT_LITERAL) { - try { - return Float.valueOf(text); - } - catch (NumberFormatException e) { - return null; - } - } - if (type == JavaTokenType.DOUBLE_LITERAL) { - try { - return Double.valueOf(text); - } - catch (NumberFormatException e) { - return null; - } - } - if (type == JavaTokenType.CHARACTER_LITERAL) { - if (StringUtil.endsWithChar(text, '\'')) { - if (textLength == 1) return null; - text = text.substring(1, textLength - 1); - } - else { - text = text.substring(1, textLength); - } - StringBuilder chars = new StringBuilder(); - boolean success = parseStringCharacters(text, chars, null); - if (!success) return null; - if (chars.length() != 1) return null; - return Character.valueOf(chars.charAt(0)); - } - if (type == JavaTokenType.STRING_LITERAL) { - String innerText = getInnerText(); - return innerText == null ? null : internedParseStringCharacters(innerText); - } - if (type == JavaTokenType.TRUE_KEYWORD) { - return Boolean.TRUE; - } - if (type == JavaTokenType.FALSE_KEYWORD) { - return Boolean.FALSE; - } - - return null; - } - - @Nullable - public String getInnerText() { - String text = getCanonicalText(); - int textLength = text.length(); - if (StringUtil.endsWithChar(text, '\"')) { - if (textLength == 1) return null; - text = text.substring(1, textLength - 1); - } - else { - if (text.startsWith(QUOT) && text.endsWith(QUOT) && textLength > QUOT.length()) { - text = text.substring(QUOT.length(), textLength - QUOT.length()); - } - else { - return null; - } - } - return text; - } - - // convert text to number according to radix specified - // if number is more than maxBits bits long, throws NumberFormatException - private static long parseDigits(final String text, final int bitsInRadix, final int maxBits) throws NumberFormatException { - final int radix = 1 << bitsInRadix; - final int textLength = text.length(); - if (textLength == 0) { - throw new NumberFormatException(text); - } - long integer = textLength == 1 ? 0 : Long.parseLong(text.substring(0, textLength - 1), radix); - if ((integer & (-1L << (maxBits - bitsInRadix))) != 0) { - throw new NumberFormatException(text); - } - final int lastDigit = Character.digit(text.charAt(textLength - 1), radix); - if (lastDigit == -1) { - throw new NumberFormatException(text); - } - integer <<= bitsInRadix; - integer |= lastDigit; - return integer; - } - - @Nullable - private static String internedParseStringCharacters(final String chars) { - final StringBuilder outChars = new StringBuilder(chars.length()); - final boolean success = parseStringCharacters(chars, outChars, null); - return success ? outChars.toString() : null; - } - - public static boolean parseStringCharacters(@NotNull String chars, @NotNull StringBuilder outChars, @Nullable int[] sourceOffsets) { - assert sourceOffsets == null || sourceOffsets.length == chars.length()+1; - if (chars.indexOf('\\') < 0) { - outChars.append(chars); - if (sourceOffsets != null) { - for (int i = 0; i < sourceOffsets.length; i++) { - sourceOffsets[i] = i; - } - } - return true; - } - int index = 0; - final int outOffset = outChars.length(); - while (index < chars.length()) { - char c = chars.charAt(index++); - if (sourceOffsets != null) { - sourceOffsets[outChars.length()-outOffset] = index - 1; - sourceOffsets[outChars.length() + 1 -outOffset] = index; - } - if (c != '\\') { - outChars.append(c); - continue; - } - if (index == chars.length()) return false; - c = chars.charAt(index++); - switch (c) { - case'b': - outChars.append('\b'); - break; - - case't': - outChars.append('\t'); - break; - - case'n': - outChars.append('\n'); - break; - - case'f': - outChars.append('\f'); - break; - - case'r': - outChars.append('\r'); - break; - - case'"': - outChars.append('"'); - break; - - case'\'': - outChars.append('\''); - break; - - case'\\': - outChars.append('\\'); - break; - - case'0': - case'1': - case'2': - case'3': - case'4': - case'5': - case'6': - case'7': - char startC = c; - int v = (int)c - '0'; - if (index < chars.length()) { - c = chars.charAt(index++); - if ('0' <= c && c <= '7') { - v <<= 3; - v += c - '0'; - if (startC <= '3' && index < chars.length()) { - c = chars.charAt(index++); - if ('0' <= c && c <= '7') { - v <<= 3; - v += c - '0'; - } - else { - index--; - } - } - } - else { - index--; - } - } - outChars.append((char)v); - break; - - case'u': - // uuuuu1234 is valid too - while (index != chars.length() && chars.charAt(index) == 'u') { - index++; - } - if (index + 4 <= chars.length()) { - try { - int code = Integer.parseInt(chars.substring(index, index + 4), 16); - //line separators are invalid here - if (code == 0x000a || code == 0x000d) return false; - c = chars.charAt(index); - if (c == '+' || c == '-') return false; - outChars.append((char)code); - index += 4; - } - catch (Exception e) { - return false; - } - } - else { - return false; - } - break; - - default: - return false; - } - if (sourceOffsets != null) { - sourceOffsets[outChars.length()-outOffset] = index; - } - } - return true; - } - - @Override - public void accept(@NotNull PsiElementVisitor visitor) { - if (visitor instanceof JavaElementVisitor) { - ((JavaElementVisitor)visitor).visitLiteralExpression(this); - } - else { - visitor.visitElement(this); - } - } - - public String toString() { - return "PsiLiteralExpression:" + getText(); - } - - @Override - public boolean isValidHost() { - return getValue() instanceof String; - } - - @Override - @NotNull - public PsiReference[] getReferences() { - return PsiReferenceService.getService().getContributedReferences(this); - } - - @Override - public PsiLanguageInjectionHost updateText(@NotNull final String text) { - TreeElement valueNode = getFirstChildNode(); - assert valueNode instanceof LeafElement; - ((LeafElement)valueNode).replaceWithText(text); - return this; - } - - @Override - @NotNull - public LiteralTextEscaper createLiteralTextEscaper() { - return new StringLiteralEscaper(this); - } -} +/* + * 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.psi.impl.source.tree.java; + +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.psi.impl.PsiManagerEx; +import com.intellij.psi.impl.ResolveScopeManager; +import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.psi.impl.source.tree.LeafElement; +import com.intellij.psi.impl.source.tree.TreeElement; +import com.intellij.psi.impl.source.tree.injected.StringLiteralEscaper; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; +import com.intellij.util.text.LiteralFormatUtil; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class PsiLiteralExpressionImpl + extends ExpressionPsiElement + implements PsiLiteralExpression, PsiLanguageInjectionHost, ContributedReferenceHost { + @NonNls private static final String QUOT = """; + + @NonNls public static final String HEX_PREFIX = "0x"; + @NonNls public static final String BIN_PREFIX = "0b"; + @NonNls public static final String _2_IN_31 = Long.toString(-1L << 31).substring(1); + @NonNls public static final String _2_IN_63 = Long.toString(-1L << 63).substring(1); + public static final TokenSet INTEGER_LITERALS = TokenSet.create(JavaTokenType.INTEGER_LITERAL, JavaTokenType.LONG_LITERAL); + public static final TokenSet REAL_LITERALS = TokenSet.create(JavaTokenType.FLOAT_LITERAL, JavaTokenType.DOUBLE_LITERAL); + public static final TokenSet NUMERIC_LITERALS = TokenSet.orSet(INTEGER_LITERALS, REAL_LITERALS); + + public PsiLiteralExpressionImpl() { + super(JavaElementType.LITERAL_EXPRESSION); + } + + @Override + public PsiType getType() { + final IElementType type = getLiteralElementType(); + if (type == JavaTokenType.INTEGER_LITERAL) { + return PsiType.INT; + } + if (type == JavaTokenType.LONG_LITERAL) { + return PsiType.LONG; + } + if (type == JavaTokenType.FLOAT_LITERAL) { + return PsiType.FLOAT; + } + if (type == JavaTokenType.DOUBLE_LITERAL) { + return PsiType.DOUBLE; + } + if (type == JavaTokenType.CHARACTER_LITERAL) { + return PsiType.CHAR; + } + if (type == JavaTokenType.STRING_LITERAL) { + PsiManagerEx manager = getManager(); + GlobalSearchScope resolveScope = ResolveScopeManager.getElementResolveScope(this); + return PsiType.getJavaLangString(manager, resolveScope); + } + if (type == JavaTokenType.TRUE_KEYWORD || type == JavaTokenType.FALSE_KEYWORD) { + return PsiType.BOOLEAN; + } + if (type == JavaTokenType.NULL_KEYWORD) { + return PsiType.NULL; + } + return null; + } + + public IElementType getLiteralElementType() { + return getFirstChildNode().getElementType(); + } + + public String getCanonicalText() { + final TreeElement literal = getFirstChildNode(); + final IElementType type = literal.getElementType(); + return NUMERIC_LITERALS.contains(type) ? LiteralFormatUtil.removeUnderscores(literal.getText()) : literal.getText(); + } + + @Override + public Object getValue() { + final IElementType type = getLiteralElementType(); + String text = NUMERIC_LITERALS.contains(type) ? getCanonicalText().toLowerCase() : getCanonicalText(); + final int textLength = text.length(); + + if (type == JavaTokenType.INTEGER_LITERAL) { + try { + if (text.startsWith(HEX_PREFIX)) { + // should fit in 32 bits + final long value = parseDigits(text.substring(2), 4, 32); + return Integer.valueOf((int)value); + } + if (text.startsWith(BIN_PREFIX)) { + // should fit in 32 bits + final long value = parseDigits(text.substring(2), 1, 32); + return Integer.valueOf((int)value); + } + if (StringUtil.startsWithChar(text, '0')) { + // should fit in 32 bits + final long value = parseDigits(text, 3, 32); + return Integer.valueOf((int)value); + } + final long l = Long.parseLong(text, 10); + if (text.equals(_2_IN_31)) return Integer.valueOf((int)l); + long converted = (int)l; + return l == converted ? Integer.valueOf((int)l) : null; + } + catch (NumberFormatException e) { + return null; + } + } + if (type == JavaTokenType.LONG_LITERAL) { + if (StringUtil.endsWithChar(text, 'L') || StringUtil.endsWithChar(text, 'l')) { + text = text.substring(0, textLength - 1); + } + try { + if (text.startsWith(HEX_PREFIX)) { + return parseDigits(text.substring(2), 4, 64); + } + if (text.startsWith(BIN_PREFIX)) { + return parseDigits(text.substring(2), 1, 64); + } + if (StringUtil.startsWithChar(text, '0')) { + // should fit in 64 bits + return parseDigits(text, 3, 64); + } + if (_2_IN_63.equals(text)) return Long.valueOf(-1L << 63); + return Long.valueOf(text, 10); + } + catch (NumberFormatException e) { + return null; + } + } + if (type == JavaTokenType.FLOAT_LITERAL) { + try { + return Float.valueOf(text); + } + catch (NumberFormatException e) { + return null; + } + } + if (type == JavaTokenType.DOUBLE_LITERAL) { + try { + return Double.valueOf(text); + } + catch (NumberFormatException e) { + return null; + } + } + if (type == JavaTokenType.CHARACTER_LITERAL) { + if (StringUtil.endsWithChar(text, '\'')) { + if (textLength == 1) return null; + text = text.substring(1, textLength - 1); + } + else { + text = text.substring(1, textLength); + } + StringBuilder chars = new StringBuilder(); + boolean success = parseStringCharacters(text, chars, null); + if (!success) return null; + if (chars.length() != 1) return null; + return Character.valueOf(chars.charAt(0)); + } + if (type == JavaTokenType.STRING_LITERAL) { + String innerText = getInnerText(); + return innerText == null ? null : internedParseStringCharacters(innerText); + } + if (type == JavaTokenType.TRUE_KEYWORD) { + return Boolean.TRUE; + } + if (type == JavaTokenType.FALSE_KEYWORD) { + return Boolean.FALSE; + } + + return null; + } + + @Nullable + public String getInnerText() { + String text = getCanonicalText(); + int textLength = text.length(); + if (StringUtil.endsWithChar(text, '\"')) { + if (textLength == 1) return null; + text = text.substring(1, textLength - 1); + } + else { + if (text.startsWith(QUOT) && text.endsWith(QUOT) && textLength > QUOT.length()) { + text = text.substring(QUOT.length(), textLength - QUOT.length()); + } + else { + return null; + } + } + return text; + } + + // convert text to number according to radix specified + // if number is more than maxBits bits long, throws NumberFormatException + private static long parseDigits(final String text, final int bitsInRadix, final int maxBits) throws NumberFormatException { + final int radix = 1 << bitsInRadix; + final int textLength = text.length(); + if (textLength == 0) { + throw new NumberFormatException(text); + } + long integer = textLength == 1 ? 0 : Long.parseLong(text.substring(0, textLength - 1), radix); + if ((integer & (-1L << (maxBits - bitsInRadix))) != 0) { + throw new NumberFormatException(text); + } + final int lastDigit = Character.digit(text.charAt(textLength - 1), radix); + if (lastDigit == -1) { + throw new NumberFormatException(text); + } + integer <<= bitsInRadix; + integer |= lastDigit; + return integer; + } + + @Nullable + private static String internedParseStringCharacters(final String chars) { + final StringBuilder outChars = new StringBuilder(chars.length()); + final boolean success = parseStringCharacters(chars, outChars, null); + return success ? outChars.toString() : null; + } + + public static boolean parseStringCharacters(@NotNull String chars, @NotNull StringBuilder outChars, @Nullable int[] sourceOffsets) { + assert sourceOffsets == null || sourceOffsets.length == chars.length()+1; + if (chars.indexOf('\\') < 0) { + outChars.append(chars); + if (sourceOffsets != null) { + for (int i = 0; i < sourceOffsets.length; i++) { + sourceOffsets[i] = i; + } + } + return true; + } + int index = 0; + final int outOffset = outChars.length(); + while (index < chars.length()) { + char c = chars.charAt(index++); + if (sourceOffsets != null) { + sourceOffsets[outChars.length()-outOffset] = index - 1; + sourceOffsets[outChars.length() + 1 -outOffset] = index; + } + if (c != '\\') { + outChars.append(c); + continue; + } + if (index == chars.length()) return false; + c = chars.charAt(index++); + switch (c) { + case'b': + outChars.append('\b'); + break; + + case't': + outChars.append('\t'); + break; + + case'n': + outChars.append('\n'); + break; + + case'f': + outChars.append('\f'); + break; + + case'r': + outChars.append('\r'); + break; + + case'"': + outChars.append('"'); + break; + + case'\'': + outChars.append('\''); + break; + + case'\\': + outChars.append('\\'); + break; + + case'0': + case'1': + case'2': + case'3': + case'4': + case'5': + case'6': + case'7': + char startC = c; + int v = (int)c - '0'; + if (index < chars.length()) { + c = chars.charAt(index++); + if ('0' <= c && c <= '7') { + v <<= 3; + v += c - '0'; + if (startC <= '3' && index < chars.length()) { + c = chars.charAt(index++); + if ('0' <= c && c <= '7') { + v <<= 3; + v += c - '0'; + } + else { + index--; + } + } + } + else { + index--; + } + } + outChars.append((char)v); + break; + + case'u': + // uuuuu1234 is valid too + while (index != chars.length() && chars.charAt(index) == 'u') { + index++; + } + if (index + 4 <= chars.length()) { + try { + int code = Integer.parseInt(chars.substring(index, index + 4), 16); + //line separators are invalid here + if (code == 0x000a || code == 0x000d) return false; + c = chars.charAt(index); + if (c == '+' || c == '-') return false; + outChars.append((char)code); + index += 4; + } + catch (Exception e) { + return false; + } + } + else { + return false; + } + break; + + default: + return false; + } + if (sourceOffsets != null) { + sourceOffsets[outChars.length()-outOffset] = index; + } + } + return true; + } + + @Override + public void accept(@NotNull PsiElementVisitor visitor) { + if (visitor instanceof JavaElementVisitor) { + ((JavaElementVisitor)visitor).visitLiteralExpression(this); + } + else { + visitor.visitElement(this); + } + } + + public String toString() { + return "PsiLiteralExpression:" + getText(); + } + + @Override + public boolean isValidHost() { + return getValue() instanceof String; + } + + @Override + @NotNull + public PsiReference[] getReferences() { + return PsiReferenceService.getService().getContributedReferences(this); + } + + @Override + public PsiLanguageInjectionHost updateText(@NotNull final String text) { + TreeElement valueNode = getFirstChildNode(); + assert valueNode instanceof LeafElement; + ((LeafElement)valueNode).replaceWithText(text); + return this; + } + + @Override + @NotNull + public LiteralTextEscaper createLiteralTextEscaper() { + return new StringLiteralEscaper(this); + } +} diff --git a/java/java-tests/testData/codeInsight/completion/keywords/returnInTernary.java b/java/java-tests/testData/codeInsight/completion/keywords/returnInTernary.java index 1ae0cc6bea54..ad957a4ae4c8 100644 --- a/java/java-tests/testData/codeInsight/completion/keywords/returnInTernary.java +++ b/java/java-tests/testData/codeInsight/completion/keywords/returnInTernary.java @@ -1,5 +1,5 @@ -public class Util { - int goo() { - retcond ? 1: 0; - } -} +public class Util { + int goo() { + retcond ? 1: 0; + } +} diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/PreferLocalsToStaticsInSecondCompletion.java b/java/java-tests/testData/codeInsight/completion/normalSorting/PreferLocalsToStaticsInSecondCompletion.java index 3130607b15fa..d12688f6d32e 100644 --- a/java/java-tests/testData/codeInsight/completion/normalSorting/PreferLocalsToStaticsInSecondCompletion.java +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/PreferLocalsToStaticsInSecondCompletion.java @@ -1,7 +1,7 @@ -class Util { - void foox() { - int fooy; - foo - } - +class Util { + void foox() { + int fooy; + foo + } + } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/PreselectMostRelevantInTheMiddleAlpha.java b/java/java-tests/testData/codeInsight/completion/normalSorting/PreselectMostRelevantInTheMiddleAlpha.java index aee4164ed2a4..34da2cfa1e58 100644 --- a/java/java-tests/testData/codeInsight/completion/normalSorting/PreselectMostRelevantInTheMiddleAlpha.java +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/PreselectMostRelevantInTheMiddleAlpha.java @@ -1,17 +1,17 @@ -class Foo { - int ELXEMENT_A = 1; - int ELXEMENT_B = 1; - int ELXEMENT_C = 1; - int ELXEMENT_D = 1; - int ELXEMENT_E = 1; - int ELXEMENT_F = 1; - int ELXEMENT_G = 1; - int ELXEMENT_H = 1; - int ELXEMENT_I = 1; - - - { - Elx - } - +class Foo { + int ELXEMENT_A = 1; + int ELXEMENT_B = 1; + int ELXEMENT_C = 1; + int ELXEMENT_D = 1; + int ELXEMENT_E = 1; + int ELXEMENT_F = 1; + int ELXEMENT_G = 1; + int ELXEMENT_H = 1; + int ELXEMENT_I = 1; + + + { + Elx + } + } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/UnderscoresDontMakeMatchMiddle.java b/java/java-tests/testData/codeInsight/completion/normalSorting/UnderscoresDontMakeMatchMiddle.java index 528d13dafa18..7867e3415883 100644 --- a/java/java-tests/testData/codeInsight/completion/normalSorting/UnderscoresDontMakeMatchMiddle.java +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/UnderscoresDontMakeMatchMiddle.java @@ -1,5 +1,5 @@ -class FooBar { - void foo(FooBar _fooBar) { - fb - } +class FooBar { + void foo(FooBar _fooBar) { + fb + } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/DiamondNotCollapsedInCaseOfAnonymousClasses-out.java b/java/java-tests/testData/codeInsight/completion/smartType/DiamondNotCollapsedInCaseOfAnonymousClasses-out.java index e6db18415733..0b2d9e76e1c3 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/DiamondNotCollapsedInCaseOfAnonymousClasses-out.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/DiamondNotCollapsedInCaseOfAnonymousClasses-out.java @@ -1,33 +1,33 @@ -class MyClass { - public void foo() { - MyDD d = new MyDD() { - @Override - public int hashCode() { - return super.hashCode(); //To change body of overridden methods use File | Settings | File Templates. - } - - @Override - public boolean equals(Object obj) { - return super.equals(obj); //To change body of overridden methods use File | Settings | File Templates. - } - - @Override - protected Object clone() throws CloneNotSupportedException { - return super.clone(); //To change body of overridden methods use File | Settings | File Templates. - } - - @Override - public String toString() { - return super.toString(); //To change body of overridden methods use File | Settings | File Templates. - } - - @Override - protected void finalize() throws Throwable { - super.finalize(); //To change body of overridden methods use File | Settings | File Templates. - } - }; - } -} - -abstract class MyDD { +class MyClass { + public void foo() { + MyDD d = new MyDD() { + @Override + public int hashCode() { + return super.hashCode(); //To change body of overridden methods use File | Settings | File Templates. + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj); //To change body of overridden methods use File | Settings | File Templates. + } + + @Override + protected Object clone() throws CloneNotSupportedException { + return super.clone(); //To change body of overridden methods use File | Settings | File Templates. + } + + @Override + public String toString() { + return super.toString(); //To change body of overridden methods use File | Settings | File Templates. + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); //To change body of overridden methods use File | Settings | File Templates. + } + }; + } +} + +abstract class MyDD { } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/ExpectedReturnTypeWithSubstitution-out.java b/java/java-tests/testData/codeInsight/completion/smartType/ExpectedReturnTypeWithSubstitution-out.java index 3e0cf290521c..0ffbb8b6e246 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/ExpectedReturnTypeWithSubstitution-out.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/ExpectedReturnTypeWithSubstitution-out.java @@ -1,31 +1,31 @@ -/* - * 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. - */ -public class Test { - public interface Some { - T test(T p1, T p2); - } - - class Foo { - public Foo create() {return null;} - public Foo create1() {return null;} - } - - { - Some some = (i1, i2) -> { - return i1.create(); - }; - } +/* + * 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. + */ +public class Test { + public interface Some { + T test(T p1, T p2); + } + + class Foo { + public Foo create() {return null;} + public Foo create1() {return null;} + } + + { + Some some = (i1, i2) -> { + return i1.create(); + }; + } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/NewAnonymousFunction-out.java b/java/java-tests/testData/codeInsight/completion/smartType/NewAnonymousFunction-out.java index 6db0fab1a1d4..3a4d6fb06f81 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/NewAnonymousFunction-out.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/NewAnonymousFunction-out.java @@ -1,29 +1,29 @@ -interface Function { } -class A { - private static final Function a = new Function() { - @Override - public int hashCode() { - return super.hashCode(); //To change body of overridden methods use File | Settings | File Templates. - } - - @Override - public boolean equals(Object obj) { - return super.equals(obj); //To change body of overridden methods use File | Settings | File Templates. - } - - @Override - protected Object clone() throws CloneNotSupportedException { - return super.clone(); //To change body of overridden methods use File | Settings | File Templates. - } - - @Override - public String toString() { - return super.toString(); //To change body of overridden methods use File | Settings | File Templates. - } - - @Override - protected void finalize() throws Throwable { - super.finalize(); //To change body of overridden methods use File | Settings | File Templates. - } - }; +interface Function { } +class A { + private static final Function a = new Function() { + @Override + public int hashCode() { + return super.hashCode(); //To change body of overridden methods use File | Settings | File Templates. + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj); //To change body of overridden methods use File | Settings | File Templates. + } + + @Override + protected Object clone() throws CloneNotSupportedException { + return super.clone(); //To change body of overridden methods use File | Settings | File Templates. + } + + @Override + public String toString() { + return super.toString(); //To change body of overridden methods use File | Settings | File Templates. + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); //To change body of overridden methods use File | Settings | File Templates. + } + }; } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks/afterAll.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks/afterAll.java index 83cbd80eccbf..c921867b407c 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks/afterAll.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks/afterAll.java @@ -1,7 +1,7 @@ -// "Break string on '\n'" "true" - -class A { - String s = "Hello,\n\r" + - "world\n" + - "!\n"; -} +// "Break string on '\n'" "true" + +class A { + String s = "Hello,\n\r" + + "world\n" + + "!\n"; +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks/beforeAll.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks/beforeAll.java index 6ae1121ae3ad..a87961b68b9e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks/beforeAll.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks/beforeAll.java @@ -1,5 +1,5 @@ -// "Break string on '\n'" "true" - -class A { - String s = "Hello,\n\rworld\n!\n"; -} +// "Break string on '\n'" "true" + +class A { + String s = "Hello,\n\rworld\n!\n"; +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks/beforeLastSlashN.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks/beforeLastSlashN.java index 7707aa48bca7..0de2f83afa6a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks/beforeLastSlashN.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks/beforeLastSlashN.java @@ -1,5 +1,5 @@ -// "Break string on '\n'" "false" - -class A { - String s = "Hello!\n"; -} +// "Break string on '\n'" "false" + +class A { + String s = "Hello!\n"; +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks/beforeLastSlashNSlashR.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks/beforeLastSlashNSlashR.java index 5dcb2f789671..c18a560abff9 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks/beforeLastSlashNSlashR.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks/beforeLastSlashNSlashR.java @@ -1,5 +1,5 @@ -// "Break string on '\n'" "false" - -class A { - String s = "Hello!\n\r"; -} +// "Break string on '\n'" "false" + +class A { + String s = "Hello!\n\r"; +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertColorRepresentation/after2Bytes.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertColorRepresentation/after2Bytes.java index e3a2b231851d..a2412d27557a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertColorRepresentation/after2Bytes.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertColorRepresentation/after2Bytes.java @@ -1,21 +1,21 @@ -// "Convert to 'new Color(0x10101)'" "true" - -package java.awt; - -class A { - private Color color = new Color(0x10101); -} - -class Color { - Color(int r, int g, int b) { - } - - Color(int r, int g, int b, int a) { - } - - Color(int rgb) { - } - - Color(int rgba, boolean hasAlpha) { - } -} +// "Convert to 'new Color(0x10101)'" "true" + +package java.awt; + +class A { + private Color color = new Color(0x10101); +} + +class Color { + Color(int r, int g, int b) { + } + + Color(int r, int g, int b, int a) { + } + + Color(int rgb) { + } + + Color(int rgba, boolean hasAlpha) { + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertColorRepresentation/before2Bytes.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertColorRepresentation/before2Bytes.java index 1775753b516b..8396cba9cc2e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertColorRepresentation/before2Bytes.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertColorRepresentation/before2Bytes.java @@ -1,21 +1,21 @@ -// "Convert to 'new Color(0x10101)'" "true" - -package java.awt; - -class A { - private Color color = new Color(257, 257, 257); -} - -class Color { - Color(int r, int g, int b) { - } - - Color(int r, int g, int b, int a) { - } - - Color(int rgb) { - } - - Color(int rgba, boolean hasAlpha) { - } -} +// "Convert to 'new Color(0x10101)'" "true" + +package java.awt; + +class A { + private Color color = new Color(257, 257, 257); +} + +class Color { + Color(int r, int g, int b) { + } + + Color(int r, int g, int b, int a) { + } + + Color(int rgb) { + } + + Color(int rgba, boolean hasAlpha) { + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/ClassNameCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/ClassNameCompletionTest.java index f9c11cd1339a..03f11aac8e33 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/ClassNameCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/ClassNameCompletionTest.java @@ -1,269 +1,269 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.JavaTestUtil; -import com.intellij.codeInsight.lookup.LookupManager; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.roots.LanguageLevelProjectExtension; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.pom.java.LanguageLevel; -import com.intellij.testFramework.TestDataPath; - -import java.io.IOException; - -@TestDataPath("$CONTENT_ROOT/testData") -public class ClassNameCompletionTest extends LightFixtureCompletionTestCase { - - @Override - protected void setUp() throws Exception { - super.setUp(); - LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_7); - } - - @Override - protected String getBasePath() { - return JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/completion/className/"; - } - - public void testImportAfterNew() throws Exception { - createClass("package pack; public class AAClass {}"); - createClass("package pack; public class WithInnerAClass{\n" + - " public static class Inner{}\n" + - "}"); - - String path = "/importAfterNew"; - - configureByFile(path + "/before1.java"); - checkResultByFile(path + "/after1.java"); - - configureByFile(path + "/before2.java"); - selectItem(myItems[0]); - checkResultByFile(path + "/after2.java"); - } - - private void createClass(String text) { - myFixture.addClass(text); - } - - public void testAfterNewThrowable1() throws Exception { - addClassesForAfterNewThrowable(); - String path = "/afterNewThrowable"; - - configureByFile(path + "/before1.java"); - myFixture.type('\n'); - checkResultByFile(path + "/after1.java"); - } - - private void addClassesForAfterNewThrowable() throws IOException { - createClass("public class OurException extends Throwable{}"); - createClass("public class OurNotException {\n" + - " public static class InnerException extends Throwable{}\n" + - " public static class InnerNonException{}\n" + - "}"); - } - - public void testAfterNewThrowable2() throws Exception { - addClassesForAfterNewThrowable(); - String path = "/afterNewThrowable"; - - configureByFile(path + "/before2.java"); - myFixture.type('\n'); - checkResultByFile(path + "/after2.java"); - } - - public void testExcessParensAfterNew() throws Exception { doTest(); } - - public void testReuseParensAfterNew() throws Exception { doTest(); } - - public void testBracesAfterNew() throws Exception { doTest(); } - - public void testInPlainTextFile() throws Exception { - configureByFile(getTestName(false) + ".txt"); - checkResultByFile(getTestName(false) + "_after.txt"); - } - - public void testInPropertiesFile() throws Exception { - myFixture.configureByText("a.properties", "abc = StrinBui"); - complete(); - myFixture.checkResult("abc = java.lang.StringBuilder"); - } - - public void testDoubleStringBuffer() throws Exception { - createClass("package java.lang; public class StringBuffer {}"); - doTest(); - assertNull(myItems); - } - - public void testReplaceReferenceExpressionWithTypeElement() throws Exception { - createClass("package foo.bar; public class ABCDEF {}"); - doTest(); - } - - public void testCamelHumpPrefix() throws Exception { - String path = "/java/"; - configureByFile(path + getTestName(false) + ".java"); - complete(); - assertEquals(2, myItems.length); - } - - private void doTest() throws Exception { - String path = "/java/"; - configureByFile(path + getTestName(false) + ".java"); - checkResultByFile(path + getTestName(false) + "_after.java"); - } - - public void testNameCompletionJava() throws Exception { - String path = "/nameCompletion/java"; - configureByFile(path + "/test1-source.java"); - performAction(); - checkResultByFile(path + "/test1-result.java"); - configureByFile(path + "/test2-source.java"); - performAction(); - checkResultByFile(path + "/test2-result.java"); - } - - public void testImplementsFiltering1() throws Exception { - final String path = "/nameCompletion/java"; - configureByFile(path + "/test4-source.java"); - performAction(); - checkResultByFile(path + "/test4-result.java"); - } - - public void testImplementsFiltering2() throws Exception { - final String path = "/nameCompletion/java"; - configureByFile(path + "/test3-source.java"); - performAction(); - checkResultByFile(path + "/test3-result.java"); - - configureByFile(path + "/implements2-source.java"); - performAction(); - checkResultByFile(path + "/implements2-result.java"); - - configureByFile(path + "/implements3-source.java"); - performAction(); - checkResultByFile(path + "/implements3-result.java"); - } - - public void testAnnotationFiltering() throws Exception { - createClass("@interface MyObjectType {}"); - - final String path = "/nameCompletion/java"; - configureByFile(path + "/test8-source.java"); - performAction(); - checkResultByFile(path + "/test8-result.java"); - cleanupVfs(); - - configureByFile(path + "/test9-source.java"); - performAction(); - checkResultByFile(path + "/test9-result.java"); - cleanupVfs(); - - configureByFile(path + "/test9_2-source.java"); - performAction(); - checkResultByFile(path + "/test9_2-result.java"); - cleanupVfs(); - - configureByFile(path + "/test9_3-source.java"); - performAction(); - checkResultByFile(path + "/test9_3-result.java"); - cleanupVfs(); - - configureByFile(path + "/test11-source.java"); - performAction(); - checkResultByFile(path + "/test11-result.java"); - cleanupVfs(); - - configureByFile(path + "/test10-source.java"); - performAction(); - checkResultByFile(path + "/test10-result.java"); - cleanupVfs(); - - configureByFile(path + "/test12-source.java"); - performAction(); - checkResultByFile(path + "/test12-result.java"); - cleanupVfs(); - - configureByFile(path + "/test13-source.java"); - performAction(); - checkResultByFile(path + "/test13-result.java"); - } - - private void cleanupVfs() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - FileDocumentManager.getInstance().saveAllDocuments(); - for (VirtualFile file : myFixture.getTempDirFixture().getFile("").getChildren()) { - try { - file.delete(this); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - } - }); - } - - public void testInMethodCall() throws Exception { - final String path = "/nameCompletion/java"; - configureByFile(path + "/methodCall-source.java"); - performAction(); - checkResultByFile(path + "/methodCall-result.java"); - } - - public void testInMethodCallQualifier() throws Exception { - final String path = "/nameCompletion/java"; - configureByFile(path + "/methodCall1-source.java"); - performAction(); - checkResultByFile(path + "/methodCall1-result.java"); - } - - public void testInVariableDeclarationType() throws Exception { - final String path = "/nameCompletion/java"; - configureByFile(path + "/varType-source.java"); - performAction(); - checkResultByFile(path + "/varType-result.java"); - } - - public void testExtraSpace() throws Exception { doJavaTest(); } - - public void testAnnotation() throws Exception { doJavaTest(); } - - public void testInStaticImport() throws Exception { doJavaTest(); } - - public void testInCommentWithPackagePrefix() throws Exception { doJavaTest(); } - - private void doJavaTest() throws Exception { - final String path = "/nameCompletion/java"; - myFixture.configureByFile(path + "/" + getTestName(false) + "-source.java"); - performAction(); - checkResultByFile(path + "/" + getTestName(false) + "-result.java"); - } - - @Override - protected void complete() { - myItems = myFixture.complete(CompletionType.BASIC, 2); - } - - private void performAction() { - complete(); - if (LookupManager.getActiveLookup(myFixture.getEditor()) != null) { - myFixture.type('\n'); - } - } -} +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.completion; + +import com.intellij.JavaTestUtil; +import com.intellij.codeInsight.lookup.LookupManager; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.roots.LanguageLevelProjectExtension; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.testFramework.TestDataPath; + +import java.io.IOException; + +@TestDataPath("$CONTENT_ROOT/testData") +public class ClassNameCompletionTest extends LightFixtureCompletionTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_7); + } + + @Override + protected String getBasePath() { + return JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/completion/className/"; + } + + public void testImportAfterNew() throws Exception { + createClass("package pack; public class AAClass {}"); + createClass("package pack; public class WithInnerAClass{\n" + + " public static class Inner{}\n" + + "}"); + + String path = "/importAfterNew"; + + configureByFile(path + "/before1.java"); + checkResultByFile(path + "/after1.java"); + + configureByFile(path + "/before2.java"); + selectItem(myItems[0]); + checkResultByFile(path + "/after2.java"); + } + + private void createClass(String text) { + myFixture.addClass(text); + } + + public void testAfterNewThrowable1() throws Exception { + addClassesForAfterNewThrowable(); + String path = "/afterNewThrowable"; + + configureByFile(path + "/before1.java"); + myFixture.type('\n'); + checkResultByFile(path + "/after1.java"); + } + + private void addClassesForAfterNewThrowable() throws IOException { + createClass("public class OurException extends Throwable{}"); + createClass("public class OurNotException {\n" + + " public static class InnerException extends Throwable{}\n" + + " public static class InnerNonException{}\n" + + "}"); + } + + public void testAfterNewThrowable2() throws Exception { + addClassesForAfterNewThrowable(); + String path = "/afterNewThrowable"; + + configureByFile(path + "/before2.java"); + myFixture.type('\n'); + checkResultByFile(path + "/after2.java"); + } + + public void testExcessParensAfterNew() throws Exception { doTest(); } + + public void testReuseParensAfterNew() throws Exception { doTest(); } + + public void testBracesAfterNew() throws Exception { doTest(); } + + public void testInPlainTextFile() throws Exception { + configureByFile(getTestName(false) + ".txt"); + checkResultByFile(getTestName(false) + "_after.txt"); + } + + public void testInPropertiesFile() throws Exception { + myFixture.configureByText("a.properties", "abc = StrinBui"); + complete(); + myFixture.checkResult("abc = java.lang.StringBuilder"); + } + + public void testDoubleStringBuffer() throws Exception { + createClass("package java.lang; public class StringBuffer {}"); + doTest(); + assertNull(myItems); + } + + public void testReplaceReferenceExpressionWithTypeElement() throws Exception { + createClass("package foo.bar; public class ABCDEF {}"); + doTest(); + } + + public void testCamelHumpPrefix() throws Exception { + String path = "/java/"; + configureByFile(path + getTestName(false) + ".java"); + complete(); + assertEquals(2, myItems.length); + } + + private void doTest() throws Exception { + String path = "/java/"; + configureByFile(path + getTestName(false) + ".java"); + checkResultByFile(path + getTestName(false) + "_after.java"); + } + + public void testNameCompletionJava() throws Exception { + String path = "/nameCompletion/java"; + configureByFile(path + "/test1-source.java"); + performAction(); + checkResultByFile(path + "/test1-result.java"); + configureByFile(path + "/test2-source.java"); + performAction(); + checkResultByFile(path + "/test2-result.java"); + } + + public void testImplementsFiltering1() throws Exception { + final String path = "/nameCompletion/java"; + configureByFile(path + "/test4-source.java"); + performAction(); + checkResultByFile(path + "/test4-result.java"); + } + + public void testImplementsFiltering2() throws Exception { + final String path = "/nameCompletion/java"; + configureByFile(path + "/test3-source.java"); + performAction(); + checkResultByFile(path + "/test3-result.java"); + + configureByFile(path + "/implements2-source.java"); + performAction(); + checkResultByFile(path + "/implements2-result.java"); + + configureByFile(path + "/implements3-source.java"); + performAction(); + checkResultByFile(path + "/implements3-result.java"); + } + + public void testAnnotationFiltering() throws Exception { + createClass("@interface MyObjectType {}"); + + final String path = "/nameCompletion/java"; + configureByFile(path + "/test8-source.java"); + performAction(); + checkResultByFile(path + "/test8-result.java"); + cleanupVfs(); + + configureByFile(path + "/test9-source.java"); + performAction(); + checkResultByFile(path + "/test9-result.java"); + cleanupVfs(); + + configureByFile(path + "/test9_2-source.java"); + performAction(); + checkResultByFile(path + "/test9_2-result.java"); + cleanupVfs(); + + configureByFile(path + "/test9_3-source.java"); + performAction(); + checkResultByFile(path + "/test9_3-result.java"); + cleanupVfs(); + + configureByFile(path + "/test11-source.java"); + performAction(); + checkResultByFile(path + "/test11-result.java"); + cleanupVfs(); + + configureByFile(path + "/test10-source.java"); + performAction(); + checkResultByFile(path + "/test10-result.java"); + cleanupVfs(); + + configureByFile(path + "/test12-source.java"); + performAction(); + checkResultByFile(path + "/test12-result.java"); + cleanupVfs(); + + configureByFile(path + "/test13-source.java"); + performAction(); + checkResultByFile(path + "/test13-result.java"); + } + + private void cleanupVfs() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + FileDocumentManager.getInstance().saveAllDocuments(); + for (VirtualFile file : myFixture.getTempDirFixture().getFile("").getChildren()) { + try { + file.delete(this); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + } + }); + } + + public void testInMethodCall() throws Exception { + final String path = "/nameCompletion/java"; + configureByFile(path + "/methodCall-source.java"); + performAction(); + checkResultByFile(path + "/methodCall-result.java"); + } + + public void testInMethodCallQualifier() throws Exception { + final String path = "/nameCompletion/java"; + configureByFile(path + "/methodCall1-source.java"); + performAction(); + checkResultByFile(path + "/methodCall1-result.java"); + } + + public void testInVariableDeclarationType() throws Exception { + final String path = "/nameCompletion/java"; + configureByFile(path + "/varType-source.java"); + performAction(); + checkResultByFile(path + "/varType-result.java"); + } + + public void testExtraSpace() throws Exception { doJavaTest(); } + + public void testAnnotation() throws Exception { doJavaTest(); } + + public void testInStaticImport() throws Exception { doJavaTest(); } + + public void testInCommentWithPackagePrefix() throws Exception { doJavaTest(); } + + private void doJavaTest() throws Exception { + final String path = "/nameCompletion/java"; + myFixture.configureByFile(path + "/" + getTestName(false) + "-source.java"); + performAction(); + checkResultByFile(path + "/" + getTestName(false) + "-result.java"); + } + + @Override + protected void complete() { + myItems = myFixture.complete(CompletionType.BASIC, 2); + } + + private void performAction() { + complete(); + if (LookupManager.getActiveLookup(myFixture.getEditor()) != null) { + myFixture.type('\n'); + } + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/CompletionSortingTestCase.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/CompletionSortingTestCase.java index fbbf0fae59ed..e07e1dae0fa2 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/CompletionSortingTestCase.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/CompletionSortingTestCase.java @@ -1,82 +1,82 @@ -/* - * Copyright (c) 2000-2005 by JetBrains s.r.o. All Rights Reserved. - * Use is subject to license terms. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.CodeInsightSettings; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.LookupManager; -import com.intellij.codeInsight.lookup.impl.LookupImpl; -import com.intellij.ide.ui.UISettings; -import com.intellij.psi.statistics.StatisticsManager; -import com.intellij.psi.statistics.impl.StatisticsManagerImpl; -import com.intellij.testFramework.TestDataPath; -import org.jetbrains.annotations.NonNls; - -/** - * @author peter - */ -@TestDataPath("$CONTENT_ROOT/testData") -public abstract class CompletionSortingTestCase extends LightFixtureCompletionTestCase { - private final CompletionType myType; - - @SuppressWarnings({"JUnitTestCaseWithNonTrivialConstructors"}) - protected CompletionSortingTestCase(CompletionType type) { - myType = type; - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - ((StatisticsManagerImpl)StatisticsManager.getInstance()).enableStatistics(getTestRootDisposable()); - } - - @Override - protected void tearDown() throws Exception { - LookupManager.getInstance(getProject()).hideActiveLookup(); - UISettings.getInstance().SORT_LOOKUP_ELEMENTS_LEXICOGRAPHICALLY = false; - CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE = CodeInsightSettings.FIRST_LETTER; - super.tearDown(); - } - - @Override - protected abstract String getBasePath(); - - protected void checkPreferredItems(final int selected, @NonNls final String... expected) { - invokeCompletion(getTestName(false) + ".java"); - assertPreferredItems(selected, expected); - } - - protected void assertPreferredItems(final int selected, @NonNls final String... expected) { - myFixture.assertPreferredCompletionItems(selected, expected); - } - - protected LookupImpl invokeCompletion(final String path) { - configureNoCompletion(path); - myFixture.complete(myType); - return getLookup(); - } - - protected void configureNoCompletion(String path) { - myFixture.configureFromExistingVirtualFile( - myFixture.copyFileToProject(path, com.intellij.openapi.util.text.StringUtil.getShortName(path, '/'))); - } - - protected static void incUseCount(final LookupImpl lookup, final int index) { - imitateItemSelection(lookup, index); - refreshSorting(lookup); - } - - protected static void refreshSorting(final LookupImpl lookup) { - lookup.setSelectionTouched(false); - lookup.resort(true); - } - - protected static void imitateItemSelection(final LookupImpl lookup, final int index) { - final LookupElement item = lookup.getItems().get(index); - lookup.setCurrentItem(item); - CompletionLookupArranger.collectStatisticChanges(item, lookup); - CompletionLookupArranger.applyLastCompletionStatisticsUpdate(); - } -} +/* + * Copyright (c) 2000-2005 by JetBrains s.r.o. All Rights Reserved. + * Use is subject to license terms. + */ +package com.intellij.codeInsight.completion; + +import com.intellij.codeInsight.CodeInsightSettings; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupManager; +import com.intellij.codeInsight.lookup.impl.LookupImpl; +import com.intellij.ide.ui.UISettings; +import com.intellij.psi.statistics.StatisticsManager; +import com.intellij.psi.statistics.impl.StatisticsManagerImpl; +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.annotations.NonNls; + +/** + * @author peter + */ +@TestDataPath("$CONTENT_ROOT/testData") +public abstract class CompletionSortingTestCase extends LightFixtureCompletionTestCase { + private final CompletionType myType; + + @SuppressWarnings({"JUnitTestCaseWithNonTrivialConstructors"}) + protected CompletionSortingTestCase(CompletionType type) { + myType = type; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + ((StatisticsManagerImpl)StatisticsManager.getInstance()).enableStatistics(getTestRootDisposable()); + } + + @Override + protected void tearDown() throws Exception { + LookupManager.getInstance(getProject()).hideActiveLookup(); + UISettings.getInstance().SORT_LOOKUP_ELEMENTS_LEXICOGRAPHICALLY = false; + CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE = CodeInsightSettings.FIRST_LETTER; + super.tearDown(); + } + + @Override + protected abstract String getBasePath(); + + protected void checkPreferredItems(final int selected, @NonNls final String... expected) { + invokeCompletion(getTestName(false) + ".java"); + assertPreferredItems(selected, expected); + } + + protected void assertPreferredItems(final int selected, @NonNls final String... expected) { + myFixture.assertPreferredCompletionItems(selected, expected); + } + + protected LookupImpl invokeCompletion(final String path) { + configureNoCompletion(path); + myFixture.complete(myType); + return getLookup(); + } + + protected void configureNoCompletion(String path) { + myFixture.configureFromExistingVirtualFile( + myFixture.copyFileToProject(path, com.intellij.openapi.util.text.StringUtil.getShortName(path, '/'))); + } + + protected static void incUseCount(final LookupImpl lookup, final int index) { + imitateItemSelection(lookup, index); + refreshSorting(lookup); + } + + protected static void refreshSorting(final LookupImpl lookup) { + lookup.setSelectionTouched(false); + lookup.resort(true); + } + + protected static void imitateItemSelection(final LookupImpl lookup, final int index) { + final LookupElement item = lookup.getItems().get(index); + lookup.setCurrentItem(item); + CompletionLookupArranger.collectStatisticChanges(item, lookup); + CompletionLookupArranger.applyLastCompletionStatisticsUpdate(); + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy index 61339b1568ac..1fc4145095c2 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy @@ -1,211 +1,211 @@ -package com.intellij.codeInsight.completion; - -import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase -import com.intellij.codeInsight.CodeInsightSettings -import com.intellij.util.ArrayUtil -import com.intellij.codeInsight.lookup.LookupElementPresentation -import com.intellij.codeInsight.lookup.LookupElement; - -/** - * @author peter - */ -public class GlobalMemberNameCompletionTest extends LightCodeInsightFixtureTestCase { - - public void testMethodName() throws Exception { - myFixture.addClass(""" -package foo; - -public class Foo { - public static int abcmethod() {} - static void methodThatsNotVisible() {} -} -""") - - doTest "class Bar {{ abcm }}", true, """import static foo.Foo.abcmethod; - -class Bar {{ abcmethod() }}""" - } - - public void testFieldName() throws Exception { - myFixture.addClass(""" -package foo; - -public class Foo { - public static int abcfield = 2 - static final int fieldThatsNotVisible = 3 -} -""") - - doTest "class Bar {{ abcf }}", true, """import static foo.Foo.abcfield; - -class Bar {{ abcfield }}""" - } - - public void testFieldNameQualified() throws Exception { - myFixture.addClass(""" -package foo; - -public class Foo { - public static int abcfield = 2 - static final int fieldThatsNotVisible = 3 -} -""") - - doTest "class Bar {{ abcf }}", false, """import foo.Foo; - -class Bar {{ Foo.abcfield }}""" - } - - public void testFieldNamePresentation() { - myFixture.addClass(""" -package foo; - -public class Foo { - public static int abcfield = 2 - static final int fieldThatsNotVisible = 3 -} -""") - myFixture.configureByText "a.java", "class Bar {{ abcf }}" - def element = complete()[0] - def presentation = LookupElementPresentation.renderElement(element) - assert 'Foo.abcfield' == presentation.itemText - assert ' (foo)' == presentation.tailText - assert 'int' == presentation.typeText - } - - private LookupElement[] complete() { - myFixture.complete(CompletionType.BASIC, 2) - } - - public void testQualifiedMethodName() throws Exception { - myFixture.addClass(""" -package foo; - -public class Foo { - public static int abcmethod() {} -} -""") - - doTest "class Bar {{ abcm }}", false, """import foo.Foo; - -class Bar {{ Foo.abcmethod() }}""" - } - - public void testIfThereAreAlreadyStaticImportsWithThatClass() throws Exception { - myFixture.addClass(""" -package foo; - -public class Foo { - public static int anotherMethod(int a) {} - public static int abcmethod() {} - void methodThatsNotVisible() {} -} -""") - - doTest """import static foo.Foo.abcmethod; - -class Bar {{ abcmethod(); anoMe }}""", false, - """import static foo.Foo.abcmethod; -import static foo.Foo.anotherMethod; - -class Bar {{ abcmethod(); anotherMethod() }}""" - } - - - @Override protected void tearDown() { - CodeInsightSettings.instance.EXCLUDED_PACKAGES = ArrayUtil.EMPTY_STRING_ARRAY - super.tearDown() - } - - public void testExcludeClassFromCompletion() throws Exception { - myFixture.addClass("""package foo; - public class Foo { - public static int abcmethod() {} - } - """) - myFixture.addClass("""package foo; - public class Excl { - public static int abcmethod2() {} - } - """) - - CodeInsightSettings.instance.EXCLUDED_PACKAGES = ["foo.Excl"] as String[] - - doTest "class Bar {{ abcm }}", true, """import static foo.Foo.abcmethod; - -class Bar {{ abcmethod() }}""" - } - - public void testExcludeMethodFromCompletion() throws Exception { - myFixture.addClass("""package foo; - public class Foo { - public static int abcmethod1() {} - public static int abcmethodExcluded() {} - } - """) - - CodeInsightSettings.instance.EXCLUDED_PACKAGES = ["foo.Foo.abcmethodExcluded"] as String[] - - doTest "class Bar {{ abcm }}", true, """import static foo.Foo.abcmethod1; - -class Bar {{ abcmethod1() }}""" - } - - public void testMergeOverloads() throws Exception { - myFixture.addClass("""package foo; - public class Foo { - public static int abcmethod(int a) {} - public static int abcmethod(boolean a) {} - public static int abcmethod1(boolean a) {} - } - """) - - myFixture.configureByText("a.java", "class Bar {{ abcm }}") - def element = complete()[0] - - def tail = LookupElementPresentation.renderElement(element).tailFragments - assert tail[0].text == '(...)' - assert !tail[0].grayed - assert tail[1].text == ' (foo)' - assert tail[1].grayed - - assertOrderedEquals myFixture.lookupElementStrings, "abcmethod", "abcmethod1" - } - - public void testMethodFromTheSameClass() { - myFixture.configureByText("a.java", """ -class A { - static void foo() {} - - static void goo() { - f - } -} -""") - def element = complete()[0] - def presentation = LookupElementPresentation.renderElement(element) - assert 'foo' == presentation.itemText - myFixture.type '\n' - myFixture.checkResult ''' -class A { - static void foo() {} - - static void goo() { - foo(); - } -} -''' - } - - private void doTest(String input, boolean importStatic, String output) { - myFixture.configureByText("a.java", input) - - def item = assertOneElement(complete()) - if (importStatic) { - item.'as'(StaticallyImportable).shouldBeImported = true - } - myFixture.type('\n') - myFixture.checkResult output - } - -} +package com.intellij.codeInsight.completion; + +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import com.intellij.codeInsight.CodeInsightSettings +import com.intellij.util.ArrayUtil +import com.intellij.codeInsight.lookup.LookupElementPresentation +import com.intellij.codeInsight.lookup.LookupElement; + +/** + * @author peter + */ +public class GlobalMemberNameCompletionTest extends LightCodeInsightFixtureTestCase { + + public void testMethodName() throws Exception { + myFixture.addClass(""" +package foo; + +public class Foo { + public static int abcmethod() {} + static void methodThatsNotVisible() {} +} +""") + + doTest "class Bar {{ abcm }}", true, """import static foo.Foo.abcmethod; + +class Bar {{ abcmethod() }}""" + } + + public void testFieldName() throws Exception { + myFixture.addClass(""" +package foo; + +public class Foo { + public static int abcfield = 2 + static final int fieldThatsNotVisible = 3 +} +""") + + doTest "class Bar {{ abcf }}", true, """import static foo.Foo.abcfield; + +class Bar {{ abcfield }}""" + } + + public void testFieldNameQualified() throws Exception { + myFixture.addClass(""" +package foo; + +public class Foo { + public static int abcfield = 2 + static final int fieldThatsNotVisible = 3 +} +""") + + doTest "class Bar {{ abcf }}", false, """import foo.Foo; + +class Bar {{ Foo.abcfield }}""" + } + + public void testFieldNamePresentation() { + myFixture.addClass(""" +package foo; + +public class Foo { + public static int abcfield = 2 + static final int fieldThatsNotVisible = 3 +} +""") + myFixture.configureByText "a.java", "class Bar {{ abcf }}" + def element = complete()[0] + def presentation = LookupElementPresentation.renderElement(element) + assert 'Foo.abcfield' == presentation.itemText + assert ' (foo)' == presentation.tailText + assert 'int' == presentation.typeText + } + + private LookupElement[] complete() { + myFixture.complete(CompletionType.BASIC, 2) + } + + public void testQualifiedMethodName() throws Exception { + myFixture.addClass(""" +package foo; + +public class Foo { + public static int abcmethod() {} +} +""") + + doTest "class Bar {{ abcm }}", false, """import foo.Foo; + +class Bar {{ Foo.abcmethod() }}""" + } + + public void testIfThereAreAlreadyStaticImportsWithThatClass() throws Exception { + myFixture.addClass(""" +package foo; + +public class Foo { + public static int anotherMethod(int a) {} + public static int abcmethod() {} + void methodThatsNotVisible() {} +} +""") + + doTest """import static foo.Foo.abcmethod; + +class Bar {{ abcmethod(); anoMe }}""", false, + """import static foo.Foo.abcmethod; +import static foo.Foo.anotherMethod; + +class Bar {{ abcmethod(); anotherMethod() }}""" + } + + + @Override protected void tearDown() { + CodeInsightSettings.instance.EXCLUDED_PACKAGES = ArrayUtil.EMPTY_STRING_ARRAY + super.tearDown() + } + + public void testExcludeClassFromCompletion() throws Exception { + myFixture.addClass("""package foo; + public class Foo { + public static int abcmethod() {} + } + """) + myFixture.addClass("""package foo; + public class Excl { + public static int abcmethod2() {} + } + """) + + CodeInsightSettings.instance.EXCLUDED_PACKAGES = ["foo.Excl"] as String[] + + doTest "class Bar {{ abcm }}", true, """import static foo.Foo.abcmethod; + +class Bar {{ abcmethod() }}""" + } + + public void testExcludeMethodFromCompletion() throws Exception { + myFixture.addClass("""package foo; + public class Foo { + public static int abcmethod1() {} + public static int abcmethodExcluded() {} + } + """) + + CodeInsightSettings.instance.EXCLUDED_PACKAGES = ["foo.Foo.abcmethodExcluded"] as String[] + + doTest "class Bar {{ abcm }}", true, """import static foo.Foo.abcmethod1; + +class Bar {{ abcmethod1() }}""" + } + + public void testMergeOverloads() throws Exception { + myFixture.addClass("""package foo; + public class Foo { + public static int abcmethod(int a) {} + public static int abcmethod(boolean a) {} + public static int abcmethod1(boolean a) {} + } + """) + + myFixture.configureByText("a.java", "class Bar {{ abcm }}") + def element = complete()[0] + + def tail = LookupElementPresentation.renderElement(element).tailFragments + assert tail[0].text == '(...)' + assert !tail[0].grayed + assert tail[1].text == ' (foo)' + assert tail[1].grayed + + assertOrderedEquals myFixture.lookupElementStrings, "abcmethod", "abcmethod1" + } + + public void testMethodFromTheSameClass() { + myFixture.configureByText("a.java", """ +class A { + static void foo() {} + + static void goo() { + f + } +} +""") + def element = complete()[0] + def presentation = LookupElementPresentation.renderElement(element) + assert 'foo' == presentation.itemText + myFixture.type '\n' + myFixture.checkResult ''' +class A { + static void foo() {} + + static void goo() { + foo(); + } +} +''' + } + + private void doTest(String input, boolean importStatic, String output) { + myFixture.configureByText("a.java", input) + + def item = assertOneElement(complete()) + if (importStatic) { + item.'as'(StaticallyImportable).shouldBeImported = true + } + myFixture.type('\n') + myFixture.checkResult output + } + +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/HeavyNormalCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/HeavyNormalCompletionTest.java index c3713d22dbdf..0d2b8a818fd8 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/HeavyNormalCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/HeavyNormalCompletionTest.java @@ -1,113 +1,113 @@ -/* - * Copyright (c) 2000-2005 by JetBrains s.r.o. All Rights Reserved. - * Use is subject to license terms. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.JavaTestUtil; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.LookupManager; -import com.intellij.codeInsight.lookup.impl.LookupImpl; -import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.module.StdModuleTypes; -import com.intellij.openapi.roots.ContentEntry; -import com.intellij.openapi.roots.ModifiableRootModel; -import com.intellij.openapi.roots.ModuleRootManager; -import com.intellij.openapi.roots.SourceFolder; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.JavaPsiFacade; -import com.intellij.testFramework.PsiTestUtil; -import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; - -/** - * @author peter - */ -public class HeavyNormalCompletionTest extends JavaCodeInsightFixtureTestCase { - - @Override - protected String getTestDataPath() { - return JavaTestUtil.getJavaTestDataPath(); - } - - public void testPackagePrefix() throws Throwable { - myFixture.configureByFile("/codeInsight/completion/normal/" + getTestName(false) + ".java"); - new WriteCommandAction.Simple(getProject()) { - @Override - protected void run() throws Throwable { - final ModifiableRootModel model = ModuleRootManager.getInstance(myFixture.getModule()).getModifiableModel(); - model.getContentEntries()[0].getSourceFolders()[0].setPackagePrefix("foo.bar.goo"); - model.commit(); - } - }.execute().throwException(); - - myFixture.completeBasic(); - myFixture.checkResultByFile("/codeInsight/completion/normal/" + getTestName(false) + "_after.java"); - assertTrue(JavaPsiFacade.getInstance(getProject()).findPackage("foo").isValid()); - assertTrue(JavaPsiFacade.getInstance(getProject()).findPackage("foo.bar").isValid()); - assertTrue(JavaPsiFacade.getInstance(getProject()).findPackage("foo.bar.goo").isValid()); - } - - public void testPreferTestCases() throws Throwable { - myFixture.configureByFile("/codeInsight/completion/normal/" + getTestName(false) + ".java"); - new WriteCommandAction.Simple(getProject()) { - @Override - protected void run() throws Throwable { - final ModifiableRootModel model = ModuleRootManager.getInstance(myFixture.getModule()).getModifiableModel(); - ContentEntry contentEntry = model.getContentEntries()[0]; - SourceFolder sourceFolder = contentEntry.getSourceFolders()[0]; - VirtualFile file = sourceFolder.getFile(); - contentEntry.removeSourceFolder(sourceFolder); - contentEntry.addSourceFolder(file, true); - model.commit(); - } - }.execute().throwException(); - - myFixture.addClass("package foo; public class SomeTestCase {}"); - myFixture.addClass("package bar; public class SomeTestec {}"); - myFixture.addClass("package goo; public class SomeAnchor {}"); - - myFixture.completeBasic(); - myFixture.assertPreferredCompletionItems(0, "SomeTestCase", "SomeAnchor", "SomeTestec"); - } - - public void testAllClassesWhenNothingIsFound() throws Throwable { - myFixture.addClass("package foo.bar; public class AxBxCxDxEx {}"); - - myFixture.configureByFile("/codeInsight/completion/normal/" + getTestName(false) + ".java"); - myFixture.completeBasic(); - myFixture.type('\n'); - myFixture.checkResultByFile("/codeInsight/completion/normal/" + getTestName(false) + "_after.java"); - } - - public void testAllClassesOnSecondBasicCompletion() throws Throwable { - myFixture.addClass("package foo.bar; public class AxBxCxDxEx {}"); - - myFixture.configureByFile("/codeInsight/completion/normal/" + getTestName(false) + ".java"); - myFixture.complete(CompletionType.BASIC, 2); - LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(myFixture.getEditor()); - LookupElement[] myItems = lookup.getItems().toArray(LookupElement.EMPTY_ARRAY); - assertEquals(2, myItems.length); - assertEquals("AxBxCxDxEx", myItems[1].getLookupString()); - assertEquals("AyByCyDyEy", myItems[0].getLookupString()); - } - - public void testMapsInvalidation() throws Exception { - myFixture.configureByFile("/codeInsight/completion/normal/" + getTestName(false) + ".java"); - assertInstanceOf(myFixture.getFile().getVirtualFile().getFileSystem(), LocalFileSystem.class); // otherwise the completion copy won't be preserved which is critical here - myFixture.completeBasic(); - assertOrderedEquals(myFixture.getLookupElementStrings(), "getAaa", "getBbb"); - myFixture.getEditor().getCaretModel().moveToOffset(myFixture.getEditor().getCaretModel().getOffset() + 2); - assertNull(myFixture.completeBasic()); - } - - public void testQualifyInaccessibleClassName() throws Exception { - PsiTestUtil.addModule(getProject(), StdModuleTypes.JAVA, "second", myFixture.getTempDirFixture().findOrCreateDir("second")); - myFixture.addFileToProject("second/foo/bar/AxBxCxDxEx.java", "package foo.bar; class AxBxCxDxEx {}"); - - myFixture.configureByText("a.java", "class Main { ABCDE }"); - myFixture.complete(CompletionType.BASIC, 3); - myFixture.checkResult("class Main { foo.bar.AxBxCxDxEx }"); - } - -} +/* + * Copyright (c) 2000-2005 by JetBrains s.r.o. All Rights Reserved. + * Use is subject to license terms. + */ +package com.intellij.codeInsight.completion; + +import com.intellij.JavaTestUtil; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupManager; +import com.intellij.codeInsight.lookup.impl.LookupImpl; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.module.StdModuleTypes; +import com.intellij.openapi.roots.ContentEntry; +import com.intellij.openapi.roots.ModifiableRootModel; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.SourceFolder; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.testFramework.PsiTestUtil; +import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; + +/** + * @author peter + */ +public class HeavyNormalCompletionTest extends JavaCodeInsightFixtureTestCase { + + @Override + protected String getTestDataPath() { + return JavaTestUtil.getJavaTestDataPath(); + } + + public void testPackagePrefix() throws Throwable { + myFixture.configureByFile("/codeInsight/completion/normal/" + getTestName(false) + ".java"); + new WriteCommandAction.Simple(getProject()) { + @Override + protected void run() throws Throwable { + final ModifiableRootModel model = ModuleRootManager.getInstance(myFixture.getModule()).getModifiableModel(); + model.getContentEntries()[0].getSourceFolders()[0].setPackagePrefix("foo.bar.goo"); + model.commit(); + } + }.execute().throwException(); + + myFixture.completeBasic(); + myFixture.checkResultByFile("/codeInsight/completion/normal/" + getTestName(false) + "_after.java"); + assertTrue(JavaPsiFacade.getInstance(getProject()).findPackage("foo").isValid()); + assertTrue(JavaPsiFacade.getInstance(getProject()).findPackage("foo.bar").isValid()); + assertTrue(JavaPsiFacade.getInstance(getProject()).findPackage("foo.bar.goo").isValid()); + } + + public void testPreferTestCases() throws Throwable { + myFixture.configureByFile("/codeInsight/completion/normal/" + getTestName(false) + ".java"); + new WriteCommandAction.Simple(getProject()) { + @Override + protected void run() throws Throwable { + final ModifiableRootModel model = ModuleRootManager.getInstance(myFixture.getModule()).getModifiableModel(); + ContentEntry contentEntry = model.getContentEntries()[0]; + SourceFolder sourceFolder = contentEntry.getSourceFolders()[0]; + VirtualFile file = sourceFolder.getFile(); + contentEntry.removeSourceFolder(sourceFolder); + contentEntry.addSourceFolder(file, true); + model.commit(); + } + }.execute().throwException(); + + myFixture.addClass("package foo; public class SomeTestCase {}"); + myFixture.addClass("package bar; public class SomeTestec {}"); + myFixture.addClass("package goo; public class SomeAnchor {}"); + + myFixture.completeBasic(); + myFixture.assertPreferredCompletionItems(0, "SomeTestCase", "SomeAnchor", "SomeTestec"); + } + + public void testAllClassesWhenNothingIsFound() throws Throwable { + myFixture.addClass("package foo.bar; public class AxBxCxDxEx {}"); + + myFixture.configureByFile("/codeInsight/completion/normal/" + getTestName(false) + ".java"); + myFixture.completeBasic(); + myFixture.type('\n'); + myFixture.checkResultByFile("/codeInsight/completion/normal/" + getTestName(false) + "_after.java"); + } + + public void testAllClassesOnSecondBasicCompletion() throws Throwable { + myFixture.addClass("package foo.bar; public class AxBxCxDxEx {}"); + + myFixture.configureByFile("/codeInsight/completion/normal/" + getTestName(false) + ".java"); + myFixture.complete(CompletionType.BASIC, 2); + LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(myFixture.getEditor()); + LookupElement[] myItems = lookup.getItems().toArray(LookupElement.EMPTY_ARRAY); + assertEquals(2, myItems.length); + assertEquals("AxBxCxDxEx", myItems[1].getLookupString()); + assertEquals("AyByCyDyEy", myItems[0].getLookupString()); + } + + public void testMapsInvalidation() throws Exception { + myFixture.configureByFile("/codeInsight/completion/normal/" + getTestName(false) + ".java"); + assertInstanceOf(myFixture.getFile().getVirtualFile().getFileSystem(), LocalFileSystem.class); // otherwise the completion copy won't be preserved which is critical here + myFixture.completeBasic(); + assertOrderedEquals(myFixture.getLookupElementStrings(), "getAaa", "getBbb"); + myFixture.getEditor().getCaretModel().moveToOffset(myFixture.getEditor().getCaretModel().getOffset() + 2); + assertNull(myFixture.completeBasic()); + } + + public void testQualifyInaccessibleClassName() throws Exception { + PsiTestUtil.addModule(getProject(), StdModuleTypes.JAVA, "second", myFixture.getTempDirFixture().findOrCreateDir("second")); + myFixture.addFileToProject("second/foo/bar/AxBxCxDxEx.java", "package foo.bar; class AxBxCxDxEx {}"); + + myFixture.configureByText("a.java", "class Main { ABCDE }"); + myFixture.complete(CompletionType.BASIC, 3); + myFixture.checkResult("class Main { foo.bar.AxBxCxDxEx }"); + } + +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/BreakStringOnLineBreaksTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/BreakStringOnLineBreaksTest.java index 7b136cb2f787..946817269ae4 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/BreakStringOnLineBreaksTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/BreakStringOnLineBreaksTest.java @@ -1,30 +1,30 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.daemon.quickFix; - -/** - * @author Danila Ponomarenko - */ -public class BreakStringOnLineBreaksTest extends LightQuickFixTestCase { - - public void test() throws Exception { doAllTests(); } - - @Override - protected String getBasePath() { - return "/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks"; - } - +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.daemon.quickFix; + +/** + * @author Danila Ponomarenko + */ +public class BreakStringOnLineBreaksTest extends LightQuickFixTestCase { + + public void test() throws Exception { doAllTests(); } + + @Override + protected String getBasePath() { + return "/codeInsight/daemonCodeAnalyzer/quickFix/breakStringOnLineBreaks"; + } + } \ No newline at end of file diff --git a/java/testFramework/src/com/intellij/codeInsight/completion/CompletionTestCase.java b/java/testFramework/src/com/intellij/codeInsight/completion/CompletionTestCase.java index 849296c2ab12..714408dcf566 100644 --- a/java/testFramework/src/com/intellij/codeInsight/completion/CompletionTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/completion/CompletionTestCase.java @@ -1,123 +1,123 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES 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.completion; - -import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.LookupManager; -import com.intellij.codeInsight.lookup.impl.LookupImpl; -import com.intellij.testFramework.PlatformTestCase; -import com.intellij.util.Function; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; -import java.util.List; - -/** - * @author mike - */ -@PlatformTestCase.WrapInCommand -public abstract class CompletionTestCase extends DaemonAnalyzerTestCase { - protected String myPrefix; - protected LookupElement[] myItems; - private CompletionType myType = CompletionType.BASIC; - - @Override - protected void tearDown() throws Exception { - try { - LookupManager.getInstance(myProject).hideActiveLookup(); - } - finally { - super.tearDown(); - } - myItems = null; - } - - @Override - protected void configureByFile(String filePath) throws Exception { - super.configureByFile(filePath); - - complete(); - } - - protected void configureByFileNoCompletion(String filePath) throws Exception { - super.configureByFile(filePath); - } - - protected void complete() { - complete(1); - } - - protected void complete(final int time) { - new CodeCompletionHandlerBase(myType).invokeCompletion(myProject, myEditor, time); - - LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(myEditor); - myItems = lookup == null ? null : lookup.getItems().toArray(new LookupElement[lookup.getItems().size()]); - myPrefix = lookup == null ? "" : lookup.itemPattern(lookup.getItems().get(0)); - } - - public void setType(CompletionType type) { - myType = type; - } - - protected void selectItem(LookupElement item, char ch) { - final LookupImpl lookup = (LookupImpl)LookupManager.getInstance(myProject).getActiveLookup(); - assert lookup != null; - lookup.setCurrentItem(item); - lookup.finishLookup(ch); - } - - protected void selectItem(LookupElement item) { - selectItem(item, (char)0); - } - - protected void doTestByCount(int finalCount, String... values) { - int index = 0; - if (myItems == null) { - assertEquals(0, finalCount); - return; - } - for (final LookupElement myItem : myItems) { - for (String value : values) { - if (value == null) { - assertFalse("Unacceptable value reached", true); - } - if (value.equals(myItem.getLookupString())) { - index++; - break; - } - } - } - assertEquals(Arrays.toString(myItems), finalCount, index); - } - - @Nullable - protected LookupImpl getActiveLookup() { - return (LookupImpl)LookupManager.getActiveLookup(myEditor); - } - - protected void assertStringItems(String... strings) { - assertNotNull(myItems); - List actual = ContainerUtil.map(myItems, new Function() { - @Override - public String fun(LookupElement element) { - return element.getLookupString(); - } - }); - assertOrderedEquals(actual, strings); - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.completion; + +import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupManager; +import com.intellij.codeInsight.lookup.impl.LookupImpl; +import com.intellij.testFramework.PlatformTestCase; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.List; + +/** + * @author mike + */ +@PlatformTestCase.WrapInCommand +public abstract class CompletionTestCase extends DaemonAnalyzerTestCase { + protected String myPrefix; + protected LookupElement[] myItems; + private CompletionType myType = CompletionType.BASIC; + + @Override + protected void tearDown() throws Exception { + try { + LookupManager.getInstance(myProject).hideActiveLookup(); + } + finally { + super.tearDown(); + } + myItems = null; + } + + @Override + protected void configureByFile(String filePath) throws Exception { + super.configureByFile(filePath); + + complete(); + } + + protected void configureByFileNoCompletion(String filePath) throws Exception { + super.configureByFile(filePath); + } + + protected void complete() { + complete(1); + } + + protected void complete(final int time) { + new CodeCompletionHandlerBase(myType).invokeCompletion(myProject, myEditor, time); + + LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(myEditor); + myItems = lookup == null ? null : lookup.getItems().toArray(new LookupElement[lookup.getItems().size()]); + myPrefix = lookup == null ? "" : lookup.itemPattern(lookup.getItems().get(0)); + } + + public void setType(CompletionType type) { + myType = type; + } + + protected void selectItem(LookupElement item, char ch) { + final LookupImpl lookup = (LookupImpl)LookupManager.getInstance(myProject).getActiveLookup(); + assert lookup != null; + lookup.setCurrentItem(item); + lookup.finishLookup(ch); + } + + protected void selectItem(LookupElement item) { + selectItem(item, (char)0); + } + + protected void doTestByCount(int finalCount, String... values) { + int index = 0; + if (myItems == null) { + assertEquals(0, finalCount); + return; + } + for (final LookupElement myItem : myItems) { + for (String value : values) { + if (value == null) { + assertFalse("Unacceptable value reached", true); + } + if (value.equals(myItem.getLookupString())) { + index++; + break; + } + } + } + assertEquals(Arrays.toString(myItems), finalCount, index); + } + + @Nullable + protected LookupImpl getActiveLookup() { + return (LookupImpl)LookupManager.getActiveLookup(myEditor); + } + + protected void assertStringItems(String... strings) { + assertNotNull(myItems); + List actual = ContainerUtil.map(myItems, new Function() { + @Override + public String fun(LookupElement element) { + return element.getLookupString(); + } + }); + assertOrderedEquals(actual, strings); + } +} diff --git a/java/testFramework/src/com/intellij/codeInsight/completion/LightCompletionTestCase.java b/java/testFramework/src/com/intellij/codeInsight/completion/LightCompletionTestCase.java index 1ed492e461d2..5f435b09dc94 100644 --- a/java/testFramework/src/com/intellij/codeInsight/completion/LightCompletionTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/completion/LightCompletionTestCase.java @@ -1,137 +1,137 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES 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.completion; - -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.LookupManager; -import com.intellij.codeInsight.lookup.impl.LookupImpl; -import com.intellij.testFramework.LightCodeInsightTestCase; -import com.intellij.util.containers.HashSet; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Set; - -/** - * @author mike - */ -public abstract class LightCompletionTestCase extends LightCodeInsightTestCase { - protected String myPrefix; - protected LookupElement[] myItems; - private CompletionType myType = CompletionType.BASIC; - - @Override - protected void tearDown() throws Exception { - LookupManager.getInstance(getProject()).hideActiveLookup(); - super.tearDown(); - } - - @Override - protected void configureByFile(@NotNull String filePath) { - super.configureByFile(filePath); - - complete(); - } - - protected void configureByFileNoComplete(String filePath) throws Exception { - super.configureByFile(filePath); - } - - protected void complete() { - complete(1); - } - - protected void complete(final int time) { - new CodeCompletionHandlerBase(myType).invokeCompletion(getProject(), getEditor(), time); - - LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(myEditor); - myItems = lookup == null ? null : lookup.getItems().toArray(LookupElement.EMPTY_ARRAY); - myPrefix = lookup == null ? null : lookup.itemPattern(lookup.getItems().get(0)); - } - - public void setType(CompletionType type) { - myType = type; - } - - protected void selectItem(LookupElement item) { - selectItem(item, (char)0); - } - - protected void selectItem(LookupElement item, char completionChar) { - final LookupImpl lookup = (LookupImpl)LookupManager.getInstance(getProject()).getActiveLookup(); - lookup.setCurrentItem(item); - if (completionChar == 0 || completionChar == '\n' || completionChar == '\t') { - lookup.finishLookup(completionChar); - } else { - type(completionChar); - } - } - - protected void testByCount(int finalCount, @NonNls String... values) { - if (myItems == null) { - assertEquals(finalCount, 0); - return; - } - int index = 0; - for (final LookupElement myItem : myItems) { - for (String value : values) { - if (value == null) { - assertFalse("Unacceptable value reached: " + myItem.getLookupString(), true); - } - if (value.equals(myItem.getLookupString())) { - index++; - break; - } - } - } - assertEquals(finalCount, index); - } - - protected void assertStringItems(@NonNls String... items) { - assertOrderedEquals(getLookupStrings(new ArrayList()), items); - } - - protected void assertContainsItems(final String... expected) { - final Set actual = getLookupStrings(new HashSet()); - for (String s : expected) { - assertTrue("Expected '" + s + "' not found in " + actual, - actual.contains(s)); - } - } - - protected void assertNotContainItems(final String... unexpected) { - final Set actual = getLookupStrings(new HashSet()); - for (String s : unexpected) { - assertFalse("Unexpected '" + s + "' presented in " + actual, - actual.contains(s)); - } - } - - private > T getLookupStrings(T actual) { - if (myItems != null) { - for (LookupElement lookupElement : myItems) { - actual.add(lookupElement.getLookupString()); - } - } - return actual; - } - - protected static LookupImpl getLookup() { - return (LookupImpl)LookupManager.getActiveLookup(myEditor); - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.completion; + +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupManager; +import com.intellij.codeInsight.lookup.impl.LookupImpl; +import com.intellij.testFramework.LightCodeInsightTestCase; +import com.intellij.util.containers.HashSet; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Set; + +/** + * @author mike + */ +public abstract class LightCompletionTestCase extends LightCodeInsightTestCase { + protected String myPrefix; + protected LookupElement[] myItems; + private CompletionType myType = CompletionType.BASIC; + + @Override + protected void tearDown() throws Exception { + LookupManager.getInstance(getProject()).hideActiveLookup(); + super.tearDown(); + } + + @Override + protected void configureByFile(@NotNull String filePath) { + super.configureByFile(filePath); + + complete(); + } + + protected void configureByFileNoComplete(String filePath) throws Exception { + super.configureByFile(filePath); + } + + protected void complete() { + complete(1); + } + + protected void complete(final int time) { + new CodeCompletionHandlerBase(myType).invokeCompletion(getProject(), getEditor(), time); + + LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(myEditor); + myItems = lookup == null ? null : lookup.getItems().toArray(LookupElement.EMPTY_ARRAY); + myPrefix = lookup == null ? null : lookup.itemPattern(lookup.getItems().get(0)); + } + + public void setType(CompletionType type) { + myType = type; + } + + protected void selectItem(LookupElement item) { + selectItem(item, (char)0); + } + + protected void selectItem(LookupElement item, char completionChar) { + final LookupImpl lookup = (LookupImpl)LookupManager.getInstance(getProject()).getActiveLookup(); + lookup.setCurrentItem(item); + if (completionChar == 0 || completionChar == '\n' || completionChar == '\t') { + lookup.finishLookup(completionChar); + } else { + type(completionChar); + } + } + + protected void testByCount(int finalCount, @NonNls String... values) { + if (myItems == null) { + assertEquals(finalCount, 0); + return; + } + int index = 0; + for (final LookupElement myItem : myItems) { + for (String value : values) { + if (value == null) { + assertFalse("Unacceptable value reached: " + myItem.getLookupString(), true); + } + if (value.equals(myItem.getLookupString())) { + index++; + break; + } + } + } + assertEquals(finalCount, index); + } + + protected void assertStringItems(@NonNls String... items) { + assertOrderedEquals(getLookupStrings(new ArrayList()), items); + } + + protected void assertContainsItems(final String... expected) { + final Set actual = getLookupStrings(new HashSet()); + for (String s : expected) { + assertTrue("Expected '" + s + "' not found in " + actual, + actual.contains(s)); + } + } + + protected void assertNotContainItems(final String... unexpected) { + final Set actual = getLookupStrings(new HashSet()); + for (String s : unexpected) { + assertFalse("Unexpected '" + s + "' presented in " + actual, + actual.contains(s)); + } + } + + private > T getLookupStrings(T actual) { + if (myItems != null) { + for (LookupElement lookupElement : myItems) { + actual.add(lookupElement.getLookupString()); + } + } + return actual; + } + + protected static LookupImpl getLookup() { + return (LookupImpl)LookupManager.getActiveLookup(myEditor); + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java index 3154add423e5..1f6566944f31 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java @@ -1,241 +1,241 @@ -package org.jetbrains.jps.javac; - -import com.intellij.openapi.util.io.FileUtilRt; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jps.incremental.Utils; - -import javax.tools.*; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Collections; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -/** - * @author Eugene Zhuravlev - * Date: 9/24/11 - */ -class JavacFileManager extends ForwardingJavaFileManager implements StandardJavaFileManager{ - - private final Context myContext; - private Map> myOutputsMap = Collections.emptyMap(); - - interface Context { - boolean isCanceled(); - - StandardJavaFileManager getStandardFileManager(); - - void consumeOutputFile(@NotNull OutputFileObject obj); - - void reportMessage(final Diagnostic.Kind kind, String message); - } - - public JavacFileManager(Context context) { - super(context.getStandardFileManager()); - myContext = context; - } - - public void setOutputDirectories(final Map> outputDirToSrcRoots) throws IOException{ - for (File outputDir : outputDirToSrcRoots.keySet()) { - // this will validate output dirs - setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(outputDir)); - } - myOutputsMap = outputDirToSrcRoots; - } - - public void setLocation(Location location, Iterable path) throws IOException{ - getStdManager().setLocation(location, path); - } - - public Iterable getJavaFileObjectsFromFiles(Iterable files) { - return getStdManager().getJavaFileObjectsFromFiles(files); - } - - public Iterable getJavaFileObjects(File... files) { - return getStdManager().getJavaFileObjects(files); - } - - public Iterable getJavaFileObjectsFromStrings(Iterable names) { - return getStdManager().getJavaFileObjectsFromStrings(names); - } - - public Iterable getJavaFileObjects(String... names) { - return getStdManager().getJavaFileObjects(names); - } - - public Iterable getLocation(Location location) { - return getStdManager().getLocation(location); - } - - public boolean isSameFile(FileObject a, FileObject b) { - if (a instanceof OutputFileObject || b instanceof OutputFileObject) { - return a.equals(b); - } - return super.isSameFile(a, b); - } - - @Override - public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException { - checkCanceled(); - final FileObject fo = super.getFileForInput(location, packageName, relativeName); - if (fo == null) { - // workaround javac bug (missing null-check): throwing exception here instead of returning null - throw new FileNotFoundException("Resource does not exist : " + location + '/' + packageName + '/' + relativeName); - } - return fo; - } - - @Override - public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind) throws IOException { - checkCanceled(); - final JavaFileObject fo = super.getJavaFileForInput(location, className, kind); - if (fo == null) { - // workaround javac bug (missing null-check): throwing exception here instead of returning null - throw new FileNotFoundException("Java resource does not exist : " + location + '/' + kind + '/' + className); - } - return fo; - } - - public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { - if (kind != JavaFileObject.Kind.SOURCE && kind != JavaFileObject.Kind.CLASS) { - throw new IllegalArgumentException("Invalid kind " + kind); - } - return getFileForOutput(location, kind, externalizeFileName(className, kind), className, sibling); - } - - public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException { - final StringBuilder name = new StringBuilder(); - if (packageName.isEmpty()) { - name.append(relativeName); - } - else { - name.append(externalizeFileName(packageName)).append(File.separatorChar).append(relativeName); - } - final String fileName = name.toString(); - return getFileForOutput(location, getKind(fileName), fileName, null, sibling); - } - - private OutputFileObject getFileForOutput(Location location, JavaFileObject.Kind kind, String fileName, @Nullable String className, FileObject sibling) throws IOException { - checkCanceled(); - - JavaFileObject src = null; - if (sibling instanceof JavaFileObject) { - final JavaFileObject javaFileObject = (JavaFileObject)sibling; - if (javaFileObject.getKind() == JavaFileObject.Kind.SOURCE) { - src = javaFileObject; - } - } - - File dir = getSingleOutputDirectory(location, src); - - if (location == StandardLocation.CLASS_OUTPUT) { - if (dir == null) { - throw new IOException("Output directory is not specified"); - } - } - else if (location == StandardLocation.SOURCE_OUTPUT) { - if (dir == null) { - dir = getSingleOutputDirectory(StandardLocation.CLASS_OUTPUT, src); - if (dir == null) { - throw new IOException("Neither class output directory nor source output are specified"); - } - } - } - final File file = (dir == null? new File(fileName).getAbsoluteFile() : new File(dir, fileName)); - return new OutputFileObject(myContext, dir, fileName, file, kind, className, src != null? src.toUri() : null); - } - - private File getSingleOutputDirectory(final Location loc, final JavaFileObject sourceFile) { - if (loc == StandardLocation.CLASS_OUTPUT) { - if (myOutputsMap.size() > 1 && sourceFile != null) { - // multiple outputs case - final File outputDir = findOutputDir(Utils.convertToFile(sourceFile.toUri())); - if (outputDir != null) { - return outputDir; - } - } - } - - final Iterable location = getStdManager().getLocation(loc); - if (location != null) { - final Iterator it = location.iterator(); - if (it.hasNext()) { - return it.next(); - } - } - return null; - } - - private File findOutputDir(File src) { - File file = FileUtilRt.getParentFile(src); - while (file != null) { - for (Map.Entry> entry : myOutputsMap.entrySet()) { - if (entry.getValue().contains(file)) { - return entry.getKey(); - } - } - file = FileUtilRt.getParentFile(file); - } - return null; - } - - @NotNull - private StandardJavaFileManager getStdManager() { - return fileManager; - } - - public Iterable toJavaFileObjects(Iterable files) { - return getStdManager().getJavaFileObjectsFromFiles(files); - } - - @Override - public void close() { - try { - super.close(); - } - catch (IOException e) { - throw new RuntimeException(e); - } - finally { - myOutputsMap = Collections.emptyMap(); - } - } - - private static JavaFileObject.Kind getKind(String name) { - if (name.endsWith(JavaFileObject.Kind.CLASS.extension)){ - return JavaFileObject.Kind.CLASS; - } - if (name.endsWith(JavaFileObject.Kind.SOURCE.extension)) { - return JavaFileObject.Kind.SOURCE; - } - if (name.endsWith(JavaFileObject.Kind.HTML.extension)) { - return JavaFileObject.Kind.HTML; - } - return JavaFileObject.Kind.OTHER; - } - - private static String externalizeFileName(CharSequence cs, JavaFileObject.Kind kind) { - return externalizeFileName(cs) + kind.extension; - } - - private static String externalizeFileName(CharSequence name) { - return name.toString().replace('.', File.separatorChar); - } - - private int myChecksCounter = 0; - - private void checkCanceled() { - final int counter = (myChecksCounter + 1) % 10; - myChecksCounter = counter; - if (counter == 0 && myContext.isCanceled()) { - throw new CompilationCanceledException(); - } - } - - public Context getContext() { - return myContext; - } -} +package org.jetbrains.jps.javac; + +import com.intellij.openapi.util.io.FileUtilRt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.incremental.Utils; + +import javax.tools.*; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * @author Eugene Zhuravlev + * Date: 9/24/11 + */ +class JavacFileManager extends ForwardingJavaFileManager implements StandardJavaFileManager{ + + private final Context myContext; + private Map> myOutputsMap = Collections.emptyMap(); + + interface Context { + boolean isCanceled(); + + StandardJavaFileManager getStandardFileManager(); + + void consumeOutputFile(@NotNull OutputFileObject obj); + + void reportMessage(final Diagnostic.Kind kind, String message); + } + + public JavacFileManager(Context context) { + super(context.getStandardFileManager()); + myContext = context; + } + + public void setOutputDirectories(final Map> outputDirToSrcRoots) throws IOException{ + for (File outputDir : outputDirToSrcRoots.keySet()) { + // this will validate output dirs + setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(outputDir)); + } + myOutputsMap = outputDirToSrcRoots; + } + + public void setLocation(Location location, Iterable path) throws IOException{ + getStdManager().setLocation(location, path); + } + + public Iterable getJavaFileObjectsFromFiles(Iterable files) { + return getStdManager().getJavaFileObjectsFromFiles(files); + } + + public Iterable getJavaFileObjects(File... files) { + return getStdManager().getJavaFileObjects(files); + } + + public Iterable getJavaFileObjectsFromStrings(Iterable names) { + return getStdManager().getJavaFileObjectsFromStrings(names); + } + + public Iterable getJavaFileObjects(String... names) { + return getStdManager().getJavaFileObjects(names); + } + + public Iterable getLocation(Location location) { + return getStdManager().getLocation(location); + } + + public boolean isSameFile(FileObject a, FileObject b) { + if (a instanceof OutputFileObject || b instanceof OutputFileObject) { + return a.equals(b); + } + return super.isSameFile(a, b); + } + + @Override + public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException { + checkCanceled(); + final FileObject fo = super.getFileForInput(location, packageName, relativeName); + if (fo == null) { + // workaround javac bug (missing null-check): throwing exception here instead of returning null + throw new FileNotFoundException("Resource does not exist : " + location + '/' + packageName + '/' + relativeName); + } + return fo; + } + + @Override + public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind) throws IOException { + checkCanceled(); + final JavaFileObject fo = super.getJavaFileForInput(location, className, kind); + if (fo == null) { + // workaround javac bug (missing null-check): throwing exception here instead of returning null + throw new FileNotFoundException("Java resource does not exist : " + location + '/' + kind + '/' + className); + } + return fo; + } + + public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { + if (kind != JavaFileObject.Kind.SOURCE && kind != JavaFileObject.Kind.CLASS) { + throw new IllegalArgumentException("Invalid kind " + kind); + } + return getFileForOutput(location, kind, externalizeFileName(className, kind), className, sibling); + } + + public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException { + final StringBuilder name = new StringBuilder(); + if (packageName.isEmpty()) { + name.append(relativeName); + } + else { + name.append(externalizeFileName(packageName)).append(File.separatorChar).append(relativeName); + } + final String fileName = name.toString(); + return getFileForOutput(location, getKind(fileName), fileName, null, sibling); + } + + private OutputFileObject getFileForOutput(Location location, JavaFileObject.Kind kind, String fileName, @Nullable String className, FileObject sibling) throws IOException { + checkCanceled(); + + JavaFileObject src = null; + if (sibling instanceof JavaFileObject) { + final JavaFileObject javaFileObject = (JavaFileObject)sibling; + if (javaFileObject.getKind() == JavaFileObject.Kind.SOURCE) { + src = javaFileObject; + } + } + + File dir = getSingleOutputDirectory(location, src); + + if (location == StandardLocation.CLASS_OUTPUT) { + if (dir == null) { + throw new IOException("Output directory is not specified"); + } + } + else if (location == StandardLocation.SOURCE_OUTPUT) { + if (dir == null) { + dir = getSingleOutputDirectory(StandardLocation.CLASS_OUTPUT, src); + if (dir == null) { + throw new IOException("Neither class output directory nor source output are specified"); + } + } + } + final File file = (dir == null? new File(fileName).getAbsoluteFile() : new File(dir, fileName)); + return new OutputFileObject(myContext, dir, fileName, file, kind, className, src != null? src.toUri() : null); + } + + private File getSingleOutputDirectory(final Location loc, final JavaFileObject sourceFile) { + if (loc == StandardLocation.CLASS_OUTPUT) { + if (myOutputsMap.size() > 1 && sourceFile != null) { + // multiple outputs case + final File outputDir = findOutputDir(Utils.convertToFile(sourceFile.toUri())); + if (outputDir != null) { + return outputDir; + } + } + } + + final Iterable location = getStdManager().getLocation(loc); + if (location != null) { + final Iterator it = location.iterator(); + if (it.hasNext()) { + return it.next(); + } + } + return null; + } + + private File findOutputDir(File src) { + File file = FileUtilRt.getParentFile(src); + while (file != null) { + for (Map.Entry> entry : myOutputsMap.entrySet()) { + if (entry.getValue().contains(file)) { + return entry.getKey(); + } + } + file = FileUtilRt.getParentFile(file); + } + return null; + } + + @NotNull + private StandardJavaFileManager getStdManager() { + return fileManager; + } + + public Iterable toJavaFileObjects(Iterable files) { + return getStdManager().getJavaFileObjectsFromFiles(files); + } + + @Override + public void close() { + try { + super.close(); + } + catch (IOException e) { + throw new RuntimeException(e); + } + finally { + myOutputsMap = Collections.emptyMap(); + } + } + + private static JavaFileObject.Kind getKind(String name) { + if (name.endsWith(JavaFileObject.Kind.CLASS.extension)){ + return JavaFileObject.Kind.CLASS; + } + if (name.endsWith(JavaFileObject.Kind.SOURCE.extension)) { + return JavaFileObject.Kind.SOURCE; + } + if (name.endsWith(JavaFileObject.Kind.HTML.extension)) { + return JavaFileObject.Kind.HTML; + } + return JavaFileObject.Kind.OTHER; + } + + private static String externalizeFileName(CharSequence cs, JavaFileObject.Kind kind) { + return externalizeFileName(cs) + kind.extension; + } + + private static String externalizeFileName(CharSequence name) { + return name.toString().replace('.', File.separatorChar); + } + + private int myChecksCounter = 0; + + private void checkCanceled() { + final int counter = (myChecksCounter + 1) % 10; + myChecksCounter = counter; + if (counter == 0 && myContext.isCanceled()) { + throw new CompilationCanceledException(); + } + } + + public Context getContext() { + return myContext; + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/OutputFileObject.java b/jps/jps-builders/src/org/jetbrains/jps/javac/OutputFileObject.java index 000a1e14e817..7aadb345a514 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/OutputFileObject.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/OutputFileObject.java @@ -1,128 +1,128 @@ -package org.jetbrains.jps.javac; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jps.incremental.BinaryContent; -import org.jetbrains.jps.incremental.Utils; - -import javax.tools.*; -import java.io.*; -import java.net.URI; - -/** - * @author Eugene Zhuravlev - * Date: 9/24/11 - */ -public final class OutputFileObject extends SimpleJavaFileObject { - @Nullable - private final JavacFileManager.Context myContext; - @Nullable - private final File myOutputRoot; - private final String myRelativePath; - private final File myFile; - @Nullable - private final String myClassName; - @Nullable private final URI mySourceUri; - private volatile BinaryContent myContent; - private final File mySourceFile; - - public OutputFileObject(@NotNull JavacFileManager.Context context, @Nullable File outputRoot, String relativePath, @NotNull File file, @NotNull Kind kind, @Nullable String className, @Nullable final URI sourceUri) { - this(context, outputRoot, relativePath, file, kind, className, sourceUri, null); - } - - public OutputFileObject(@Nullable JavacFileManager.Context context, @Nullable File outputRoot, String relativePath, @NotNull File file, @NotNull Kind kind, @Nullable String className, @Nullable final URI srcUri, @Nullable BinaryContent content) { - super(Utils.toURI(file.getPath()), kind); - myContext = context; - mySourceUri = srcUri; - myContent = content; - myOutputRoot = outputRoot; - myRelativePath = relativePath; - myFile = file; - myClassName = className != null? className.replace('/', '.') : null; - mySourceFile = srcUri != null? Utils.convertToFile(srcUri) : null; - } - - @Nullable - public File getOutputRoot() { - return myOutputRoot; - } - - public String getRelativePath() { - return myRelativePath; - } - - @NotNull - public File getFile() { - return myFile; - } - - @Nullable - public String getClassName() { - return myClassName; - } - - @Nullable - public File getSourceFile() { - return mySourceFile; - } - - @Nullable - public URI getSourceUri() { - return mySourceUri; - } - - @Override - public ByteArrayOutputStream openOutputStream() { - return new ByteArrayOutputStream() { - @Override - public void close() throws IOException { - try { - super.close(); - } - finally { - myContent = new BinaryContent(buf, 0, size()); - if (myContext != null) { - myContext.consumeOutputFile(OutputFileObject.this); - } - } - } - }; - } - - @Override - public InputStream openInputStream() throws IOException { - final BinaryContent bytes = myContent; - if (bytes != null) { - return new ByteArrayInputStream(bytes.getBuffer(), bytes.getOffset(), bytes.getLength()); - } - return new BufferedInputStream(new FileInputStream(myFile)); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { - final BinaryContent content = myContent; - if (content == null) { - throw new FileNotFoundException(toUri().getPath()); - } - return new String(content.getBuffer(), content.getOffset(), content.getLength()); - } - - @Nullable - public BinaryContent getContent() { - return myContent; - } - - public void updateContent(@NotNull byte[] updatedContent) { - myContent = new BinaryContent(updatedContent, 0, updatedContent.length); - } - - @Override - public int hashCode() { - return toUri().hashCode(); - } - - @Override - public boolean equals(Object obj) { - return obj instanceof JavaFileObject && toUri().equals(((JavaFileObject)obj).toUri()); - } -} +package org.jetbrains.jps.javac; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.incremental.BinaryContent; +import org.jetbrains.jps.incremental.Utils; + +import javax.tools.*; +import java.io.*; +import java.net.URI; + +/** + * @author Eugene Zhuravlev + * Date: 9/24/11 + */ +public final class OutputFileObject extends SimpleJavaFileObject { + @Nullable + private final JavacFileManager.Context myContext; + @Nullable + private final File myOutputRoot; + private final String myRelativePath; + private final File myFile; + @Nullable + private final String myClassName; + @Nullable private final URI mySourceUri; + private volatile BinaryContent myContent; + private final File mySourceFile; + + public OutputFileObject(@NotNull JavacFileManager.Context context, @Nullable File outputRoot, String relativePath, @NotNull File file, @NotNull Kind kind, @Nullable String className, @Nullable final URI sourceUri) { + this(context, outputRoot, relativePath, file, kind, className, sourceUri, null); + } + + public OutputFileObject(@Nullable JavacFileManager.Context context, @Nullable File outputRoot, String relativePath, @NotNull File file, @NotNull Kind kind, @Nullable String className, @Nullable final URI srcUri, @Nullable BinaryContent content) { + super(Utils.toURI(file.getPath()), kind); + myContext = context; + mySourceUri = srcUri; + myContent = content; + myOutputRoot = outputRoot; + myRelativePath = relativePath; + myFile = file; + myClassName = className != null? className.replace('/', '.') : null; + mySourceFile = srcUri != null? Utils.convertToFile(srcUri) : null; + } + + @Nullable + public File getOutputRoot() { + return myOutputRoot; + } + + public String getRelativePath() { + return myRelativePath; + } + + @NotNull + public File getFile() { + return myFile; + } + + @Nullable + public String getClassName() { + return myClassName; + } + + @Nullable + public File getSourceFile() { + return mySourceFile; + } + + @Nullable + public URI getSourceUri() { + return mySourceUri; + } + + @Override + public ByteArrayOutputStream openOutputStream() { + return new ByteArrayOutputStream() { + @Override + public void close() throws IOException { + try { + super.close(); + } + finally { + myContent = new BinaryContent(buf, 0, size()); + if (myContext != null) { + myContext.consumeOutputFile(OutputFileObject.this); + } + } + } + }; + } + + @Override + public InputStream openInputStream() throws IOException { + final BinaryContent bytes = myContent; + if (bytes != null) { + return new ByteArrayInputStream(bytes.getBuffer(), bytes.getOffset(), bytes.getLength()); + } + return new BufferedInputStream(new FileInputStream(myFile)); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + final BinaryContent content = myContent; + if (content == null) { + throw new FileNotFoundException(toUri().getPath()); + } + return new String(content.getBuffer(), content.getOffset(), content.getLength()); + } + + @Nullable + public BinaryContent getContent() { + return myContent; + } + + public void updateContent(@NotNull byte[] updatedContent) { + myContent = new BinaryContent(updatedContent, 0, updatedContent.length); + } + + @Override + public int hashCode() { + return toUri().hashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof JavaFileObject && toUri().equals(((JavaFileObject)obj).toUri()); + } +} diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/LogParser.java b/jps/jps-builders/testSrc/org/jetbrains/ether/LogParser.java index cb9571f7c966..2df575dcc39f 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/LogParser.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/LogParser.java @@ -1,81 +1,81 @@ -package org.jetbrains.ether; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; - -/** - * @author Eugene Zhuravlev - * Date: 6/29/12 - */ -public class LogParser { - - private static final String COMPILING_START_STR = "incremental.java.JavaBuilder - Compiling"; - - public static void main(String[] args) throws IOException { - final String logPath = args[0]; - - long totalTime = 0L; - int totalFileCount = 0; - final BufferedReader reader = new BufferedReader(new FileReader(new File(logPath))); - try { - String line = reader.readLine(); - while (line != null) { - if (line.contains(COMPILING_START_STR)) { - final long startTime = getTime(line); - final String nextLine = reader.readLine(); - if (nextLine != null && nextLine.contains("- Dependency analysis found")) { - final long endTime = getTime(nextLine); - totalTime += (endTime - startTime); - final int index = line.indexOf(COMPILING_START_STR); - if (index > 0) { - final StringBuilder buf = new StringBuilder(); - for (int idx = index + COMPILING_START_STR.length(); idx < line.length(); idx++) { - final char ch = line.charAt(idx); - if (ch == ' ' || ch == '\t') { - continue; - } - if (!Character.isDigit(ch)) { - break; - } - buf.append(ch); - } - if (buf.length() > 0) { - final int fileCount = Integer.parseInt(buf.toString()); - totalFileCount += fileCount; - } - } - } - } - line = reader.readLine(); - } - } - finally { - reader.close(); - } - - long millis = totalTime % 1000; - long seconds = totalTime / 1000; - long minutes = seconds / 60; - seconds = seconds % 60; - - System.out.println("Files compiled: " + totalFileCount); - System.out.println("Total time spent compiling java " + minutes + " min " + seconds + " sec " + millis + " ms"); - } - - - private static final int HOURS_START = 11; - private static final int MINUTES_START = HOURS_START + 3; - private static final int SECONDS_START = MINUTES_START + 3; - private static final int MILLIS_START = SECONDS_START + 3; - - private static long getTime(String line) { - final int hours = Integer.parseInt(line.substring(HOURS_START, HOURS_START + 2)); - final int minutes = Integer.parseInt(line.substring(MINUTES_START, MINUTES_START + 2)); - final int seconds = Integer.parseInt(line.substring(SECONDS_START, SECONDS_START + 2)); - final int millis = Integer.parseInt(line.substring(MILLIS_START, MILLIS_START + 3)); - return millis + seconds * 1000 + minutes * 60000 + hours * 3600000; - } - -} +package org.jetbrains.ether; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +/** + * @author Eugene Zhuravlev + * Date: 6/29/12 + */ +public class LogParser { + + private static final String COMPILING_START_STR = "incremental.java.JavaBuilder - Compiling"; + + public static void main(String[] args) throws IOException { + final String logPath = args[0]; + + long totalTime = 0L; + int totalFileCount = 0; + final BufferedReader reader = new BufferedReader(new FileReader(new File(logPath))); + try { + String line = reader.readLine(); + while (line != null) { + if (line.contains(COMPILING_START_STR)) { + final long startTime = getTime(line); + final String nextLine = reader.readLine(); + if (nextLine != null && nextLine.contains("- Dependency analysis found")) { + final long endTime = getTime(nextLine); + totalTime += (endTime - startTime); + final int index = line.indexOf(COMPILING_START_STR); + if (index > 0) { + final StringBuilder buf = new StringBuilder(); + for (int idx = index + COMPILING_START_STR.length(); idx < line.length(); idx++) { + final char ch = line.charAt(idx); + if (ch == ' ' || ch == '\t') { + continue; + } + if (!Character.isDigit(ch)) { + break; + } + buf.append(ch); + } + if (buf.length() > 0) { + final int fileCount = Integer.parseInt(buf.toString()); + totalFileCount += fileCount; + } + } + } + } + line = reader.readLine(); + } + } + finally { + reader.close(); + } + + long millis = totalTime % 1000; + long seconds = totalTime / 1000; + long minutes = seconds / 60; + seconds = seconds % 60; + + System.out.println("Files compiled: " + totalFileCount); + System.out.println("Total time spent compiling java " + minutes + " min " + seconds + " sec " + millis + " ms"); + } + + + private static final int HOURS_START = 11; + private static final int MINUTES_START = HOURS_START + 3; + private static final int SECONDS_START = MINUTES_START + 3; + private static final int MILLIS_START = SECONDS_START + 3; + + private static long getTime(String line) { + final int hours = Integer.parseInt(line.substring(HOURS_START, HOURS_START + 2)); + final int minutes = Integer.parseInt(line.substring(MINUTES_START, MINUTES_START + 2)); + final int seconds = Integer.parseInt(line.substring(SECONDS_START, SECONDS_START + 2)); + final int millis = Integer.parseInt(line.substring(MILLIS_START, MILLIS_START + 3)); + return millis + seconds * 1000 + minutes * 60000 + hours * 3600000; + } + +} diff --git a/license/kryo-license.txt b/license/kryo-license.txt index 5a57ac7a1f7a..e1cd88478edf 100755 --- a/license/kryo-license.txt +++ b/license/kryo-license.txt @@ -1,10 +1,10 @@ -Copyright (c) 2008, Nathan Sweet -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Copyright (c) 2008, Nathan Sweet +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/platform/core-api/src/com/intellij/openapi/application/AccessToken.java b/platform/core-api/src/com/intellij/openapi/application/AccessToken.java index 9e1e028c83ae..f567c15c51c3 100644 --- a/platform/core-api/src/com/intellij/openapi/application/AccessToken.java +++ b/platform/core-api/src/com/intellij/openapi/application/AccessToken.java @@ -1,16 +1,16 @@ -package com.intellij.openapi.application; - -public abstract class AccessToken { - protected void acquired() { - } - - protected void released() { - } - - public abstract void finish(); - - public static final AccessToken EMPTY_ACCESS_TOKEN = new AccessToken() { - @Override - public void finish() {} - }; -} +package com.intellij.openapi.application; + +public abstract class AccessToken { + protected void acquired() { + } + + protected void released() { + } + + public abstract void finish(); + + public static final AccessToken EMPTY_ACCESS_TOKEN = new AccessToken() { + @Override + public void finish() {} + }; +} diff --git a/platform/core-api/src/com/intellij/psi/stubs/StubSerializationHelper.java b/platform/core-api/src/com/intellij/psi/stubs/StubSerializationHelper.java index 2e1d882b5c6f..eb66f8daa384 100644 --- a/platform/core-api/src/com/intellij/psi/stubs/StubSerializationHelper.java +++ b/platform/core-api/src/com/intellij/psi/stubs/StubSerializationHelper.java @@ -1,232 +1,232 @@ -/* - * 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.psi.stubs; - -import com.intellij.openapi.diagnostic.LogUtil; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.LowMemoryWatcher; -import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; -import com.intellij.util.containers.SLRUCache; -import com.intellij.util.io.AbstractStringEnumerator; -import com.intellij.util.io.DataInputOutputUtil; -import com.intellij.util.io.IOUtil; -import gnu.trove.TIntObjectHashMap; -import gnu.trove.TObjectIntHashMap; -import jsr166e.SequenceLock; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.locks.Lock; - -/** - * Author: dmitrylomov - */ -public class StubSerializationHelper { - - private final static Logger LOG = Logger.getInstance(StubSerializationHelper.class); - private AbstractStringEnumerator myNameStorage; - - protected final TIntObjectHashMap myIdToSerializer = new TIntObjectHashMap(); - protected final TObjectIntHashMap mySerializerToId = new TObjectIntHashMap(); - - public StubSerializationHelper(AbstractStringEnumerator nameStorage) { - myNameStorage = nameStorage; - } - - public void assignId(@NotNull final ObjectStubSerializer serializer) throws IOException { - final int id = persistentId(serializer); - final ObjectStubSerializer old = myIdToSerializer.put(id, serializer); - assert old == null : "ID: " + serializer.getExternalId() + " is not unique; Already registered serializer with this ID: " + old.getClass().getName(); - - final int oldId = mySerializerToId.put(serializer, id); - assert oldId == 0 : "Serializer " + serializer + " is already registered; Old ID:" + oldId; - } - - private int persistentId(@NotNull final ObjectStubSerializer serializer) throws IOException { - if (myNameStorage == null) { - throw new IOException("SerializationManager's name storage failed to initialize"); - } - return myNameStorage.enumerate(serializer.getExternalId()); - } - - private void doSerialize(final Stub rootStub, final StubOutputStream stream) throws IOException { - final ObjectStubSerializer serializer = StubSerializationUtil.getSerializer(rootStub); - - DataInputOutputUtil.writeINT(stream, getClassId(serializer)); - serializer.serialize(rootStub, stream); - - final List children = rootStub.getChildrenStubs(); - final int childrenSize = children.size(); - DataInputOutputUtil.writeINT(stream, childrenSize); - for (int i = 0; i < childrenSize; ++i) { - doSerialize(children.get(i), stream); - } - } - - public void serialize(Stub rootStub, OutputStream stream) throws IOException { - BufferExposingByteArrayOutputStream out = new BufferExposingByteArrayOutputStream(); - FileLocalStringEnumerator storage = new FileLocalStringEnumerator(); - StubOutputStream stubOutputStream = new StubOutputStream(out, storage); - - doSerialize(rootStub, stubOutputStream); - DataOutputStream resultStream = new DataOutputStream(stream); - DataInputOutputUtil.writeINT(resultStream, storage.myStrings.size()); - byte[] buffer = IOUtil.allocReadWriteUTFBuffer(); - for(String s:storage.myStrings) { - IOUtil.writeUTFFast(buffer, resultStream, s); - } - resultStream.write(out.getInternalBuffer(), 0, out.size()); - } - - private int getClassId(final ObjectStubSerializer serializer) { - final int idValue = mySerializerToId.get(serializer); - assert idValue != 0: "No ID found for serializer " + LogUtil.objectAndClass(serializer); - return idValue; - } - - private static class RecentStringInterner { - private final int myStripeMask; - private final SLRUCache[] myInterns; - private final Lock[] myStripeLocks; - private final LowMemoryWatcher myClearingCallback; - - private RecentStringInterner(int capacity) { - final int stripes = 16; - myInterns = new SLRUCache[stripes]; - myStripeLocks = new Lock[myInterns.length]; - for(int i = 0; i < myInterns.length; ++i) { - myInterns[i] = new SLRUCache(capacity / stripes, capacity / stripes) { - @NotNull - @Override - public String createValue(String key) { - return key; - } - }; - myStripeLocks[i] = new SequenceLock(); - } - - assert Integer.highestOneBit(stripes) == stripes; - myStripeMask = stripes - 1; - myClearingCallback = LowMemoryWatcher.register(new Runnable() { - @Override - public void run() { - clear(); - }; - }); - } - - String get(String s) { - final int stripe = Math.abs(s.hashCode()) & myStripeMask; - try { - myStripeLocks[stripe].lock(); - return myInterns[stripe].get(s); - } finally { - myStripeLocks[stripe].unlock(); - } - } - - void clear() { - for(int i = 0; i < myInterns.length; ++i) { - myStripeLocks[i].lock(); - myInterns[i].clear(); - myStripeLocks[i].unlock(); - } - } - } - - private final RecentStringInterner myStringInterner = new RecentStringInterner(8192); - - public Stub deserialize(InputStream stream) throws IOException, SerializerNotFoundException { - FileLocalStringEnumerator storage = new FileLocalStringEnumerator(); - StubInputStream inputStream = new StubInputStream(stream, storage); - final int size = DataInputOutputUtil.readINT(inputStream); - byte[] buffer = IOUtil.allocReadWriteUTFBuffer(); - - int i = 1; - while(i <= size) { - String s = myStringInterner.get(IOUtil.readUTFFast(buffer, inputStream)); - storage.myStrings.add(s); - storage.myEnumerates.put(s, i); - ++i; - } - return deserialize(inputStream, null); - } - - private Stub deserialize(StubInputStream stream, @Nullable Stub parentStub) throws IOException, SerializerNotFoundException { - final int id = DataInputOutputUtil.readINT(stream); - final ObjectStubSerializer serializer = getClassById(id); - if (serializer == null) { - throw new SerializerNotFoundException("No serializer registered for stub: ID=" + id + "; parent stub class=" + (parentStub != null? parentStub.getClass().getName() : "null")); - } - - Stub stub = serializer.deserialize(stream, parentStub); - int childCount = DataInputOutputUtil.readINT(stream); - for (int i = 0; i < childCount; i++) { - deserialize(stream, stub); - } - return stub; - } - - - private ObjectStubSerializer getClassById(int id) { - return myIdToSerializer.get(id); - } - - private static class FileLocalStringEnumerator implements AbstractStringEnumerator { - private final TObjectIntHashMap myEnumerates = new TObjectIntHashMap(); - private final ArrayList myStrings = new ArrayList(); - - @Override - public int enumerate(@Nullable String value) throws IOException { - if (value == null) return 0; - int i = myEnumerates.get(value); - if (i == 0) { - myEnumerates.put(value, i = myStrings.size() + 1); - myStrings.add(value); - } - return i; - } - - @Override - public String valueOf(int idx) throws IOException { - if (idx == 0) return null; - return myStrings.get(idx - 1); - } - - @Override - public void markCorrupted() { - } - - @Override - public void close() throws IOException { - } - - @Override - public boolean isDirty() { - return false; - } - - @Override - public void force() { - } - } -} +/* + * 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.psi.stubs; + +import com.intellij.openapi.diagnostic.LogUtil; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.LowMemoryWatcher; +import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; +import com.intellij.util.containers.SLRUCache; +import com.intellij.util.io.AbstractStringEnumerator; +import com.intellij.util.io.DataInputOutputUtil; +import com.intellij.util.io.IOUtil; +import gnu.trove.TIntObjectHashMap; +import gnu.trove.TObjectIntHashMap; +import jsr166e.SequenceLock; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.locks.Lock; + +/** + * Author: dmitrylomov + */ +public class StubSerializationHelper { + + private final static Logger LOG = Logger.getInstance(StubSerializationHelper.class); + private AbstractStringEnumerator myNameStorage; + + protected final TIntObjectHashMap myIdToSerializer = new TIntObjectHashMap(); + protected final TObjectIntHashMap mySerializerToId = new TObjectIntHashMap(); + + public StubSerializationHelper(AbstractStringEnumerator nameStorage) { + myNameStorage = nameStorage; + } + + public void assignId(@NotNull final ObjectStubSerializer serializer) throws IOException { + final int id = persistentId(serializer); + final ObjectStubSerializer old = myIdToSerializer.put(id, serializer); + assert old == null : "ID: " + serializer.getExternalId() + " is not unique; Already registered serializer with this ID: " + old.getClass().getName(); + + final int oldId = mySerializerToId.put(serializer, id); + assert oldId == 0 : "Serializer " + serializer + " is already registered; Old ID:" + oldId; + } + + private int persistentId(@NotNull final ObjectStubSerializer serializer) throws IOException { + if (myNameStorage == null) { + throw new IOException("SerializationManager's name storage failed to initialize"); + } + return myNameStorage.enumerate(serializer.getExternalId()); + } + + private void doSerialize(final Stub rootStub, final StubOutputStream stream) throws IOException { + final ObjectStubSerializer serializer = StubSerializationUtil.getSerializer(rootStub); + + DataInputOutputUtil.writeINT(stream, getClassId(serializer)); + serializer.serialize(rootStub, stream); + + final List children = rootStub.getChildrenStubs(); + final int childrenSize = children.size(); + DataInputOutputUtil.writeINT(stream, childrenSize); + for (int i = 0; i < childrenSize; ++i) { + doSerialize(children.get(i), stream); + } + } + + public void serialize(Stub rootStub, OutputStream stream) throws IOException { + BufferExposingByteArrayOutputStream out = new BufferExposingByteArrayOutputStream(); + FileLocalStringEnumerator storage = new FileLocalStringEnumerator(); + StubOutputStream stubOutputStream = new StubOutputStream(out, storage); + + doSerialize(rootStub, stubOutputStream); + DataOutputStream resultStream = new DataOutputStream(stream); + DataInputOutputUtil.writeINT(resultStream, storage.myStrings.size()); + byte[] buffer = IOUtil.allocReadWriteUTFBuffer(); + for(String s:storage.myStrings) { + IOUtil.writeUTFFast(buffer, resultStream, s); + } + resultStream.write(out.getInternalBuffer(), 0, out.size()); + } + + private int getClassId(final ObjectStubSerializer serializer) { + final int idValue = mySerializerToId.get(serializer); + assert idValue != 0: "No ID found for serializer " + LogUtil.objectAndClass(serializer); + return idValue; + } + + private static class RecentStringInterner { + private final int myStripeMask; + private final SLRUCache[] myInterns; + private final Lock[] myStripeLocks; + private final LowMemoryWatcher myClearingCallback; + + private RecentStringInterner(int capacity) { + final int stripes = 16; + myInterns = new SLRUCache[stripes]; + myStripeLocks = new Lock[myInterns.length]; + for(int i = 0; i < myInterns.length; ++i) { + myInterns[i] = new SLRUCache(capacity / stripes, capacity / stripes) { + @NotNull + @Override + public String createValue(String key) { + return key; + } + }; + myStripeLocks[i] = new SequenceLock(); + } + + assert Integer.highestOneBit(stripes) == stripes; + myStripeMask = stripes - 1; + myClearingCallback = LowMemoryWatcher.register(new Runnable() { + @Override + public void run() { + clear(); + }; + }); + } + + String get(String s) { + final int stripe = Math.abs(s.hashCode()) & myStripeMask; + try { + myStripeLocks[stripe].lock(); + return myInterns[stripe].get(s); + } finally { + myStripeLocks[stripe].unlock(); + } + } + + void clear() { + for(int i = 0; i < myInterns.length; ++i) { + myStripeLocks[i].lock(); + myInterns[i].clear(); + myStripeLocks[i].unlock(); + } + } + } + + private final RecentStringInterner myStringInterner = new RecentStringInterner(8192); + + public Stub deserialize(InputStream stream) throws IOException, SerializerNotFoundException { + FileLocalStringEnumerator storage = new FileLocalStringEnumerator(); + StubInputStream inputStream = new StubInputStream(stream, storage); + final int size = DataInputOutputUtil.readINT(inputStream); + byte[] buffer = IOUtil.allocReadWriteUTFBuffer(); + + int i = 1; + while(i <= size) { + String s = myStringInterner.get(IOUtil.readUTFFast(buffer, inputStream)); + storage.myStrings.add(s); + storage.myEnumerates.put(s, i); + ++i; + } + return deserialize(inputStream, null); + } + + private Stub deserialize(StubInputStream stream, @Nullable Stub parentStub) throws IOException, SerializerNotFoundException { + final int id = DataInputOutputUtil.readINT(stream); + final ObjectStubSerializer serializer = getClassById(id); + if (serializer == null) { + throw new SerializerNotFoundException("No serializer registered for stub: ID=" + id + "; parent stub class=" + (parentStub != null? parentStub.getClass().getName() : "null")); + } + + Stub stub = serializer.deserialize(stream, parentStub); + int childCount = DataInputOutputUtil.readINT(stream); + for (int i = 0; i < childCount; i++) { + deserialize(stream, stub); + } + return stub; + } + + + private ObjectStubSerializer getClassById(int id) { + return myIdToSerializer.get(id); + } + + private static class FileLocalStringEnumerator implements AbstractStringEnumerator { + private final TObjectIntHashMap myEnumerates = new TObjectIntHashMap(); + private final ArrayList myStrings = new ArrayList(); + + @Override + public int enumerate(@Nullable String value) throws IOException { + if (value == null) return 0; + int i = myEnumerates.get(value); + if (i == 0) { + myEnumerates.put(value, i = myStrings.size() + 1); + myStrings.add(value); + } + return i; + } + + @Override + public String valueOf(int idx) throws IOException { + if (idx == 0) return null; + return myStrings.get(idx - 1); + } + + @Override + public void markCorrupted() { + } + + @Override + public void close() throws IOException { + } + + @Override + public boolean isDirty() { + return false; + } + + @Override + public void force() { + } + } +} diff --git a/platform/core-impl/src/com/intellij/mock/MockProject.java b/platform/core-impl/src/com/intellij/mock/MockProject.java index de5f8a85e3a0..c5d8c8f44265 100644 --- a/platform/core-impl/src/com/intellij/mock/MockProject.java +++ b/platform/core-impl/src/com/intellij/mock/MockProject.java @@ -1,155 +1,155 @@ -/* - * 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.mock; - -import com.intellij.openapi.Disposable; -import com.intellij.openapi.components.ExtensionAreas; -import com.intellij.openapi.components.ProjectComponent; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.vfs.VirtualFile; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.picocontainer.PicoContainer; - -/** - * @author yole - */ -public class MockProject extends MockComponentManager implements Project { - private static final Logger LOG = Logger.getInstance("#com.intellij.mock.MockProject"); - private VirtualFile myBaseDir; - - public MockProject(PicoContainer parent, @NotNull Disposable parentDisposable) { - super(parent, parentDisposable); - Extensions.instantiateArea(ExtensionAreas.IDEA_PROJECT, this, null); - Disposer.register(parentDisposable, new Disposable() { - @Override - public void dispose() { - Extensions.disposeArea(MockProject.this); - } - }); - } - - @Override - public boolean isDefault() { - return false; - } - - @NotNull - @Override - public Condition getDisposed() { - return new Condition() { - @Override - public boolean value(final Object o) { - return isDisposed(); - } - }; - } - - @Override - public boolean isOpen() { - return false; - } - - @Override - public boolean isInitialized() { - return true; - } - - @Override - public VirtualFile getProjectFile() { - return null; - } - - @Override - @NotNull - public String getName() { - return ""; - } - - @Override - @Nullable - @NonNls - public String getPresentableUrl() { - return null; - } - - @Override - @NotNull - @NonNls - public String getLocationHash() { - return "mock"; - } - - @Override - @Nullable - @NonNls - public String getLocation() { - throw new UnsupportedOperationException("Method getLocation not implemented in " + getClass()); - } - - @Override - @NotNull - public String getProjectFilePath() { - return ""; - } - - @Override - public VirtualFile getWorkspaceFile() { - return null; - } - - public void setBaseDir(VirtualFile baseDir) { - myBaseDir = baseDir; - } - - @Override - @Nullable - public VirtualFile getBaseDir() { - return myBaseDir; - } - - @Override - public String getBasePath() { - return null; - } - - @Override - public void save() { - } - - @Override - public T[] getExtensions(final ExtensionPointName extensionPointName) { - return Extensions.getArea(this).getExtensionPoint(extensionPointName).getExtensions(); - } - - public void projectOpened() { - final ProjectComponent[] components = getComponents(ProjectComponent.class); - for (ProjectComponent component : components) { - try { - component.projectOpened(); - } - catch (Throwable e) { - LOG.error(component.toString(), e); - } - } - } -} +/* + * 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.mock; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.components.ExtensionAreas; +import com.intellij.openapi.components.ProjectComponent; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.picocontainer.PicoContainer; + +/** + * @author yole + */ +public class MockProject extends MockComponentManager implements Project { + private static final Logger LOG = Logger.getInstance("#com.intellij.mock.MockProject"); + private VirtualFile myBaseDir; + + public MockProject(PicoContainer parent, @NotNull Disposable parentDisposable) { + super(parent, parentDisposable); + Extensions.instantiateArea(ExtensionAreas.IDEA_PROJECT, this, null); + Disposer.register(parentDisposable, new Disposable() { + @Override + public void dispose() { + Extensions.disposeArea(MockProject.this); + } + }); + } + + @Override + public boolean isDefault() { + return false; + } + + @NotNull + @Override + public Condition getDisposed() { + return new Condition() { + @Override + public boolean value(final Object o) { + return isDisposed(); + } + }; + } + + @Override + public boolean isOpen() { + return false; + } + + @Override + public boolean isInitialized() { + return true; + } + + @Override + public VirtualFile getProjectFile() { + return null; + } + + @Override + @NotNull + public String getName() { + return ""; + } + + @Override + @Nullable + @NonNls + public String getPresentableUrl() { + return null; + } + + @Override + @NotNull + @NonNls + public String getLocationHash() { + return "mock"; + } + + @Override + @Nullable + @NonNls + public String getLocation() { + throw new UnsupportedOperationException("Method getLocation not implemented in " + getClass()); + } + + @Override + @NotNull + public String getProjectFilePath() { + return ""; + } + + @Override + public VirtualFile getWorkspaceFile() { + return null; + } + + public void setBaseDir(VirtualFile baseDir) { + myBaseDir = baseDir; + } + + @Override + @Nullable + public VirtualFile getBaseDir() { + return myBaseDir; + } + + @Override + public String getBasePath() { + return null; + } + + @Override + public void save() { + } + + @Override + public T[] getExtensions(final ExtensionPointName extensionPointName) { + return Extensions.getArea(this).getExtensionPoint(extensionPointName).getExtensions(); + } + + public void projectOpened() { + final ProjectComponent[] components = getComponents(ProjectComponent.class); + for (ProjectComponent component : components) { + try { + component.projectOpened(); + } + catch (Throwable e) { + LOG.error(component.toString(), e); + } + } + } +} diff --git a/platform/core-impl/src/com/intellij/openapi/application/impl/ModalityStateEx.java b/platform/core-impl/src/com/intellij/openapi/application/impl/ModalityStateEx.java index e45934aa5196..682475183590 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/impl/ModalityStateEx.java +++ b/platform/core-impl/src/com/intellij/openapi/application/impl/ModalityStateEx.java @@ -1,102 +1,102 @@ -/* - * 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.openapi.application.impl; - -import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.progress.ProgressIndicator; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; - -public class ModalityStateEx extends ModalityState { - private static final WeakReference[] EMPTY_REFS_ARRAY = new WeakReference[0]; - - private final WeakReference[] myModalEntities; - - public ModalityStateEx() { - this(EMPTY_REFS_ARRAY); - } - - public ModalityStateEx(@NotNull Object[] modalEntities) { - if (modalEntities.length > 0) { - myModalEntities = new WeakReference[modalEntities.length]; - for (int i = 0; i < modalEntities.length; i++) { - Object entity = modalEntities[i]; - myModalEntities[i] = new WeakReference(entity); - } - } - else{ - myModalEntities = EMPTY_REFS_ARRAY; - } - } - - @NotNull - public ModalityState appendProgress(@NotNull ProgressIndicator progress){ - return appendEntity(progress); - } - - @NotNull - ModalityStateEx appendEntity(@NotNull Object anEntity){ - ArrayList list = new ArrayList(); - for (WeakReference modalEntity : myModalEntities) { - Object entity = modalEntity.get(); - if (entity == null) continue; - list.add(entity); - } - list.add(anEntity); - return new ModalityStateEx(list.toArray()); - } - - private static boolean contains(WeakReference[] array, Object o){ - for (WeakReference reference : array) { - Object o1 = reference.get(); - if (o1 == null) continue; - if (o1.equals(o)) return true; - } - return false; - } - - @Override - public boolean dominates(@NotNull ModalityState anotherState){ - if (anotherState == ModalityState.any()) return false; - - for (WeakReference modalEntity : myModalEntities) { - Object entity = modalEntity.get(); - if (entity == null) continue; - if (!contains(((ModalityStateEx)anotherState).myModalEntities, entity)) return true; // I have entity which is absent in anotherState - } - return false; - } - - boolean contains(Object modalEntity) { - return contains(myModalEntities, modalEntity); - } - - @NonNls - public String toString() { - if (myModalEntities.length == 0) return "ModalityState.NON_MODAL"; - @NonNls StringBuilder buffer = new StringBuilder(); - buffer.append("ModalityState:"); - for (int i = 0; i < myModalEntities.length; i++) { - Object entity = myModalEntities[i].get(); - if (i > 0) buffer.append(", "); - buffer.append(entity); - } - return buffer.toString(); - } -} +/* + * 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.openapi.application.impl; + +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.progress.ProgressIndicator; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; + +public class ModalityStateEx extends ModalityState { + private static final WeakReference[] EMPTY_REFS_ARRAY = new WeakReference[0]; + + private final WeakReference[] myModalEntities; + + public ModalityStateEx() { + this(EMPTY_REFS_ARRAY); + } + + public ModalityStateEx(@NotNull Object[] modalEntities) { + if (modalEntities.length > 0) { + myModalEntities = new WeakReference[modalEntities.length]; + for (int i = 0; i < modalEntities.length; i++) { + Object entity = modalEntities[i]; + myModalEntities[i] = new WeakReference(entity); + } + } + else{ + myModalEntities = EMPTY_REFS_ARRAY; + } + } + + @NotNull + public ModalityState appendProgress(@NotNull ProgressIndicator progress){ + return appendEntity(progress); + } + + @NotNull + ModalityStateEx appendEntity(@NotNull Object anEntity){ + ArrayList list = new ArrayList(); + for (WeakReference modalEntity : myModalEntities) { + Object entity = modalEntity.get(); + if (entity == null) continue; + list.add(entity); + } + list.add(anEntity); + return new ModalityStateEx(list.toArray()); + } + + private static boolean contains(WeakReference[] array, Object o){ + for (WeakReference reference : array) { + Object o1 = reference.get(); + if (o1 == null) continue; + if (o1.equals(o)) return true; + } + return false; + } + + @Override + public boolean dominates(@NotNull ModalityState anotherState){ + if (anotherState == ModalityState.any()) return false; + + for (WeakReference modalEntity : myModalEntities) { + Object entity = modalEntity.get(); + if (entity == null) continue; + if (!contains(((ModalityStateEx)anotherState).myModalEntities, entity)) return true; // I have entity which is absent in anotherState + } + return false; + } + + boolean contains(Object modalEntity) { + return contains(myModalEntities, modalEntity); + } + + @NonNls + public String toString() { + if (myModalEntities.length == 0) return "ModalityState.NON_MODAL"; + @NonNls StringBuilder buffer = new StringBuilder(); + buffer.append("ModalityState:"); + for (int i = 0; i < myModalEntities.length; i++) { + Object entity = myModalEntities[i].get(); + if (i > 0) buffer.append(", "); + buffer.append(entity); + } + return buffer.toString(); + } +} diff --git a/platform/core-impl/src/com/intellij/openapi/editor/ex/util/SegmentArrayWithData.java b/platform/core-impl/src/com/intellij/openapi/editor/ex/util/SegmentArrayWithData.java index 530c01260642..5cd71ee9d10d 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/ex/util/SegmentArrayWithData.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/ex/util/SegmentArrayWithData.java @@ -1,118 +1,118 @@ -/* - * 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.openapi.editor.ex.util; - -import org.jetbrains.annotations.NotNull; - -/** - * Expands {@link SegmentArray} contract in providing ability to attach additional 'short' variable to target segment, - * i.e. holds mappings like {@code 'index <-> (data, (start; end))'}. - *

- * Not thread-safe. - */ -public class SegmentArrayWithData extends SegmentArray { - private short[] myData; - - public SegmentArrayWithData() { - myData = new short[INITIAL_SIZE]; - } - - public void setElementAt(int i, int startOffset, int endOffset, int data) { - if (data < 0 && data > Short.MAX_VALUE) throw new IndexOutOfBoundsException("data out of short range" + data); - super.setElementAt(i, startOffset, endOffset); - myData = reallocateArray(myData, i+1); - myData[i] = (short)data; - } - - @Override - public void remove(int startIndex, int endIndex) { - myData = remove(myData, startIndex, endIndex); - super.remove(startIndex, endIndex); - } - - public void replace(int startIndex, int endIndex, @NotNull SegmentArrayWithData newData) { - int oldLen = endIndex - startIndex; - int newLen = newData.getSegmentCount(); - - int delta = newLen - oldLen; - if (delta < 0) { - remove(endIndex + delta, endIndex); - } - else if (delta > 0) { - SegmentArrayWithData deltaData = new SegmentArrayWithData(); - for (int i = oldLen; i < newLen; i++) { - deltaData.setElementAt(i - oldLen, newData.getSegmentStart(i), newData.getSegmentEnd(i), newData.getSegmentData(i)); - } - insert(deltaData, startIndex + oldLen); - } - - int common = Math.min(newLen, oldLen); - replace(startIndex, newData, common); - } - - - protected void replace(int startOffset, @NotNull SegmentArrayWithData data, int len) { - System.arraycopy(data.myData, 0, myData, startOffset, len); - super.replace(startOffset, data, len); - } - - public void insert(@NotNull SegmentArrayWithData segmentArray, int startIndex) { - myData = insert(myData, segmentArray.myData, startIndex, segmentArray.getSegmentCount()); - super.insert(segmentArray, startIndex); - } - - @NotNull - private short[] insert(@NotNull short[] array, @NotNull short[] insertArray, int startIndex, int insertLength) { - short[] newArray = reallocateArray(array, mySegmentCount + insertLength); - if (startIndex < mySegmentCount) { - System.arraycopy(newArray, startIndex, newArray, startIndex + insertLength, mySegmentCount - startIndex); - } - System.arraycopy(insertArray, 0, newArray, startIndex, insertLength); - return newArray; - } - - @NotNull - private short[] remove(@NotNull short[] array, int startIndex, int endIndex) { - if (endIndex < mySegmentCount) { - System.arraycopy(array, endIndex, array, startIndex, mySegmentCount - endIndex); - } - return array; - } - - public short getSegmentData(int index) { - if(index < 0 || index >= mySegmentCount) { - throw new IndexOutOfBoundsException("Wrong index: " + index); - } - return myData[index]; - } - - public void setSegmentData(int index, int data) { - if(index < 0 || index >= mySegmentCount) throw new IndexOutOfBoundsException("Wrong index: " + index); - if (data < 0 && data > Short.MAX_VALUE) throw new IndexOutOfBoundsException("data out of short range" + data); - myData[index] = (short)data; - } - - @NotNull - private static short[] reallocateArray(@NotNull short[] array, int index) { - if (index < array.length) return array; - - short[] newArray = new short[calcCapacity(array.length, index)]; - System.arraycopy(array, 0, newArray, 0, array.length); - return newArray; - } - -} - +/* + * 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.openapi.editor.ex.util; + +import org.jetbrains.annotations.NotNull; + +/** + * Expands {@link SegmentArray} contract in providing ability to attach additional 'short' variable to target segment, + * i.e. holds mappings like {@code 'index <-> (data, (start; end))'}. + *

+ * Not thread-safe. + */ +public class SegmentArrayWithData extends SegmentArray { + private short[] myData; + + public SegmentArrayWithData() { + myData = new short[INITIAL_SIZE]; + } + + public void setElementAt(int i, int startOffset, int endOffset, int data) { + if (data < 0 && data > Short.MAX_VALUE) throw new IndexOutOfBoundsException("data out of short range" + data); + super.setElementAt(i, startOffset, endOffset); + myData = reallocateArray(myData, i+1); + myData[i] = (short)data; + } + + @Override + public void remove(int startIndex, int endIndex) { + myData = remove(myData, startIndex, endIndex); + super.remove(startIndex, endIndex); + } + + public void replace(int startIndex, int endIndex, @NotNull SegmentArrayWithData newData) { + int oldLen = endIndex - startIndex; + int newLen = newData.getSegmentCount(); + + int delta = newLen - oldLen; + if (delta < 0) { + remove(endIndex + delta, endIndex); + } + else if (delta > 0) { + SegmentArrayWithData deltaData = new SegmentArrayWithData(); + for (int i = oldLen; i < newLen; i++) { + deltaData.setElementAt(i - oldLen, newData.getSegmentStart(i), newData.getSegmentEnd(i), newData.getSegmentData(i)); + } + insert(deltaData, startIndex + oldLen); + } + + int common = Math.min(newLen, oldLen); + replace(startIndex, newData, common); + } + + + protected void replace(int startOffset, @NotNull SegmentArrayWithData data, int len) { + System.arraycopy(data.myData, 0, myData, startOffset, len); + super.replace(startOffset, data, len); + } + + public void insert(@NotNull SegmentArrayWithData segmentArray, int startIndex) { + myData = insert(myData, segmentArray.myData, startIndex, segmentArray.getSegmentCount()); + super.insert(segmentArray, startIndex); + } + + @NotNull + private short[] insert(@NotNull short[] array, @NotNull short[] insertArray, int startIndex, int insertLength) { + short[] newArray = reallocateArray(array, mySegmentCount + insertLength); + if (startIndex < mySegmentCount) { + System.arraycopy(newArray, startIndex, newArray, startIndex + insertLength, mySegmentCount - startIndex); + } + System.arraycopy(insertArray, 0, newArray, startIndex, insertLength); + return newArray; + } + + @NotNull + private short[] remove(@NotNull short[] array, int startIndex, int endIndex) { + if (endIndex < mySegmentCount) { + System.arraycopy(array, endIndex, array, startIndex, mySegmentCount - endIndex); + } + return array; + } + + public short getSegmentData(int index) { + if(index < 0 || index >= mySegmentCount) { + throw new IndexOutOfBoundsException("Wrong index: " + index); + } + return myData[index]; + } + + public void setSegmentData(int index, int data) { + if(index < 0 || index >= mySegmentCount) throw new IndexOutOfBoundsException("Wrong index: " + index); + if (data < 0 && data > Short.MAX_VALUE) throw new IndexOutOfBoundsException("data out of short range" + data); + myData[index] = (short)data; + } + + @NotNull + private static short[] reallocateArray(@NotNull short[] array, int index) { + if (index < array.length) return array; + + short[] newArray = new short[calcCapacity(array.length, index)]; + System.arraycopy(array, 0, newArray, 0, array.length); + return newArray; + } + +} + 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 3e358f948f73..4b1b4c0c00cc 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 @@ -1,952 +1,952 @@ -/* - * 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.psi.impl.source.tree; - -import com.intellij.diagnostic.ThreadDumper; -import com.intellij.extapi.psi.ASTDelegatePsiElement; -import com.intellij.lang.*; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProgressIndicatorProvider; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.pom.tree.events.ChangeInfo; -import com.intellij.pom.tree.events.TreeChangeEvent; -import com.intellij.pom.tree.events.impl.ChangeInfoImpl; -import com.intellij.pom.tree.events.impl.ReplaceChangeInfoImpl; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiLock; -import com.intellij.psi.impl.DebugUtil; -import com.intellij.psi.impl.FreeThreadedFileViewProvider; -import com.intellij.psi.impl.source.DummyHolder; -import com.intellij.psi.impl.source.DummyHolderElement; -import com.intellij.psi.impl.source.DummyHolderFactory; -import com.intellij.psi.impl.source.SourceTreeToPsiMap; -import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; -import com.intellij.psi.tree.IElementType; -import com.intellij.psi.tree.TokenSet; -import com.intellij.util.ArrayFactory; -import com.intellij.util.text.CharArrayCharSequence; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class CompositeElement extends TreeElement { - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.CompositeElement"); - - private TreeElement firstChild = null; - private TreeElement lastChild = null; - - private volatile int myModificationsCount = 0; - private static final int NOT_CACHED = -239; - private volatile int myCachedLength = NOT_CACHED; - private volatile int myHC = -1; - private volatile PsiElement myWrapper = null; - private static final boolean ASSERT_THREADING = true;//DebugUtil.CHECK || ApplicationManagerEx.getApplicationEx().isInternal() || ApplicationManagerEx.getApplicationEx().isUnitTestMode(); - - public CompositeElement(@NotNull IElementType type) { - super(type); - } - - public int getModificationCount() { - return myModificationsCount; - } - - @Override - public CompositeElement clone() { - CompositeElement clone = (CompositeElement)super.clone(); - - synchronized (PsiLock.LOCK) { - clone.firstChild = null; - clone.lastChild = null; - clone.myModificationsCount = 0; - clone.myWrapper = null; - for (ASTNode child = rawFirstChild(); child != null; child = child.getTreeNext()) { - clone.rawAddChildrenWithoutNotifications((TreeElement)child.clone()); - } - clone.clearCaches(); - } - return clone; - } - - public void subtreeChanged() { - synchronized (PsiLock.LOCK) { - CompositeElement compositeElement = this; - while(compositeElement != null) { - compositeElement.clearCaches(); - if (!(compositeElement instanceof PsiElement)) { - final PsiElement psi = compositeElement.myWrapper; - if (psi instanceof ASTDelegatePsiElement) { - ((ASTDelegatePsiElement)psi).subtreeChanged(); - } - else if (psi instanceof PsiFile) { - ((PsiFile)psi).subtreeChanged(); - } - } - - compositeElement = compositeElement.getTreeParent(); - } - } - } - - @Override - public void clearCaches() { - assertThreading(); - myCachedLength = NOT_CACHED; - - myModificationsCount++; - myHC = -1; - - clearRelativeOffsets(rawFirstChild()); - } - - public void assertThreading() { - if (ASSERT_THREADING) { - boolean ok = ApplicationManager.getApplication().isWriteAccessAllowed() || - //Thread.holdsLock(START_OFFSET_LOCK) || - isNonPhysicalOrInjected(); - if (!ok) { - FileElement fileElement; - PsiFile psiFile; - LOG.error("Threading assertion. " + - " Under write: " + ApplicationManager.getApplication().isWriteAccessAllowed() + - "; Thread.holdsLock(START_OFFSET_LOCK): " + Thread.holdsLock(START_OFFSET_LOCK) + - "; Thread.holdsLock(PsiLock.LOCK): " + Thread.holdsLock(PsiLock.LOCK) + - "; wrapper: " + myWrapper + - "; wrapper.isPhysical(): " + (myWrapper != null && myWrapper.isPhysical()) + - "; fileElement: " +(fileElement = TreeUtil.getFileElement(this))+ - "; psiFile: " + (psiFile = fileElement == null ? null : (PsiFile)fileElement.getPsi()) + - "; psiFile.getViewProvider(): " + (psiFile == null ? null : psiFile.getViewProvider()) + - "; psiFile.isPhysical(): " + (psiFile != null && psiFile.isPhysical()) - ); - } - } - } - - private boolean isNonPhysicalOrInjected() { - FileElement fileElement = TreeUtil.getFileElement(this); - if (fileElement == null || fileElement instanceof DummyHolderElement) return true; - if (fileElement.getTreeParent() != null) return true; // dummy holder - PsiElement wrapper = this instanceof PsiElement ? (PsiElement)this : myWrapper; - if (wrapper == null) return true; - PsiFile psiFile = wrapper.getContainingFile(); - return - psiFile == null || - psiFile instanceof DummyHolder || - psiFile.getViewProvider() instanceof FreeThreadedFileViewProvider || - !psiFile.isPhysical(); - } - - @Override - public void acceptTree(TreeElementVisitor visitor) { - visitor.visitComposite(this); - } - - @Override - public LeafElement findLeafElementAt(int offset) { - TreeElement element = this; - startFind: - while (true) { - TreeElement child = element.getFirstChildNode(); - while (child != null) { - final int textLength = child.getTextLength(); - if (textLength > offset) { - if (child instanceof LeafElement) { - if (child instanceof ForeignLeafPsiElement) { - child = child.getTreeNext(); - continue; - } - return (LeafElement)child; - } - element = child; - continue startFind; - } - offset -= textLength; - child = child.getTreeNext(); - } - return null; - } - } - - @Nullable - public PsiElement findPsiChildByType(IElementType type) { - final ASTNode node = findChildByType(type); - return node == null ? null : node.getPsi(); - } - - @Nullable - public PsiElement findPsiChildByType(TokenSet types) { - final ASTNode node = findChildByType(types); - return node == null ? null : node.getPsi(); - } - - @Override - public ASTNode findChildByType(IElementType type) { - if (DebugUtil.CHECK_INSIDE_ATOMIC_ACTION_ENABLED){ - ApplicationManager.getApplication().assertReadAccessAllowed(); - } - - for(ASTNode element = getFirstChildNode(); element != null; element = element.getTreeNext()){ - if (element.getElementType() == type) return element; - } - return null; - } - - @Override - public ASTNode findChildByType(IElementType type, ASTNode anchor) { - if (DebugUtil.CHECK_INSIDE_ATOMIC_ACTION_ENABLED){ - ApplicationManager.getApplication().assertReadAccessAllowed(); - } - - ASTNode child = anchor; - while (true) { - if (child == null) return null; - if (type == child.getElementType()) return child; - child = child.getTreeNext(); - } - } - - @Override - @Nullable - public ASTNode findChildByType(@NotNull TokenSet types) { - if (DebugUtil.CHECK_INSIDE_ATOMIC_ACTION_ENABLED){ - ApplicationManager.getApplication().assertReadAccessAllowed(); - } - for(ASTNode element = getFirstChildNode(); element != null; element = element.getTreeNext()){ - if (types.contains(element.getElementType())) return element; - } - return null; - } - - @Override - @Nullable - public ASTNode findChildByType(@NotNull TokenSet typesSet, ASTNode anchor) { - if (DebugUtil.CHECK_INSIDE_ATOMIC_ACTION_ENABLED){ - ApplicationManager.getApplication().assertReadAccessAllowed(); - } - ASTNode child = anchor; - while (true) { - if (child == null) return null; - if (typesSet.contains(child.getElementType())) return child; - child = child.getTreeNext(); - } - } - - @Override - @NotNull - public String getText() { - return new String(textToCharArray()); - } - - @Override - public CharSequence getChars() { - return new CharArrayCharSequence(textToCharArray()); - } - - @Override - public int getNotCachedLength() { - final int[] result = {0}; - - acceptTree(new RecursiveTreeElementWalkingVisitor(false) { - @Override - protected void visitNode(final TreeElement element) { - if (element instanceof LeafElement || TreeUtil.isCollapsedChameleon(element)) { - result[0] += element.getNotCachedLength(); - } - super.visitNode(element); - } - }); - - return result[0]; - } - - @Override - @NotNull - public char[] textToCharArray() { - ApplicationManager.getApplication().assertReadAccessAllowed(); - int startStamp = myModificationsCount; - - final int len = getTextLength(); - - if (startStamp != myModificationsCount) { - throw new AssertionError("Tree changed while calculating text. startStamp:"+startStamp+"; current:"+myModificationsCount+"; myHC:"+myHC+"; assertThreading:"+ASSERT_THREADING+"; Thread.holdsLock(START_OFFSET_LOCK):"+Thread.holdsLock(START_OFFSET_LOCK)+"; Thread.holdsLock(PSI_LOCK):"+Thread.holdsLock(PsiLock.LOCK)+"; this: " + this); - } - - char[] buffer = new char[len]; - final int endOffset; - try { - endOffset = AstBufferUtil.toBuffer(this, buffer, 0); - } - catch (ArrayIndexOutOfBoundsException e) { - @NonNls String msg = "Underestimated text length: " + len; - msg += diagnoseTextInconsistency(new String(buffer), startStamp); - try { - int length = AstBufferUtil.toBuffer(this, new char[len], 0); - msg += ";\n repetition gives success (" + length + ")"; - } - catch (ArrayIndexOutOfBoundsException e1) { - msg += ";\n repetition fails as well"; - } - throw new RuntimeException(msg, e); - } - if (endOffset != len) { - @NonNls String msg = "len=" + len + ";\n endOffset=" + endOffset; - msg += diagnoseTextInconsistency(new String(buffer, 0, Math.min(len, endOffset)), startStamp); - throw new AssertionError(msg); - } - return buffer; - } - - private String diagnoseTextInconsistency(String text, int startStamp) { - @NonNls String msg = ""; - msg += ";\n changed=" + (startStamp != myModificationsCount); - msg += ";\n buffer=" + text; - msg += ";\n this=" + this; - int shitStart = textMatches(text, 0); - msg += ";\n matches until " + shitStart; - LeafElement leaf = findLeafElementAt(Math.abs(shitStart)); - msg += ";\n element there=" + leaf; - if (leaf != null) { - PsiElement psi = leaf.getPsi(); - msg += ";\n leaf.text=" + leaf.getText(); - msg += ";\n leaf.psi=" + psi; - msg += ";\n leaf.lang=" + (psi == null ? null : psi.getLanguage()); - msg += ";\n leaf.type=" + leaf.getElementType(); - } - PsiElement psi = getPsi(); - if (psi != null) { - boolean valid = psi.isValid(); - msg += ";\n psi.valid=" + valid; - if (valid) { - PsiFile file = psi.getContainingFile(); - if (file != null) { - msg += ";\n psi.file=" + file; - msg += ";\n psi.file.tl=" + file.getTextLength(); - msg += ";\n psi.file.lang=" + file.getLanguage(); - msg += ";\n psi.file.vp=" + file.getViewProvider(); - msg += ";\n psi.file.vp.lang=" + file.getViewProvider().getLanguages(); - msg += ";\n psi.file.vp.lang=" + file.getViewProvider().getLanguages(); - - PsiElement fileLeaf = file.findElementAt(getTextRange().getStartOffset()); - LeafElement myLeaf = findLeafElementAt(0); - msg += ";\n leaves at start=" + fileLeaf + " and " + myLeaf; - } - } - } - return msg; - } - - @Override - public boolean textContains(char c) { - for (ASTNode child = getFirstChildNode(); child != null; child = child.getTreeNext()) { - if (child.textContains(c)) return true; - } - return false; - } - - @Override - protected int textMatches(@NotNull CharSequence buffer, int start) { - int curOffset = start; - for (TreeElement child = getFirstChildNode(); child != null; child = child.getTreeNext()) { - curOffset = child.textMatches(buffer, curOffset); - if (curOffset < 0) return curOffset; - } - return curOffset; - } - - /* - protected int textMatches(final CharSequence buffer, final int start) { - final int[] curOffset = {start}; - acceptTree(new RecursiveTreeElementWalkingVisitor() { - @Override - public void visitLeaf(LeafElement leaf) { - matchText(leaf); - } - - private void matchText(TreeElement leaf) { - curOffset[0] = leaf.textMatches(buffer, curOffset[0]); - if (curOffset[0] == -1) { - stopWalking(); - } - } - - @Override - public void visitComposite(CompositeElement composite) { - if (composite instanceof LazyParseableElement && !((LazyParseableElement)composite).isParsed()) { - matchText(composite); - } - else { - super.visitComposite(composite); - } - } - }); - return curOffset[0]; - } - */ - - @Nullable - public final PsiElement findChildByRoleAsPsiElement(int role) { - ASTNode element = findChildByRole(role); - if (element == null) return null; - return SourceTreeToPsiMap.treeElementToPsi(element); - } - - @Nullable - public ASTNode findChildByRole(int role) { - // assert ChildRole.isUnique(role); - for (ASTNode child = getFirstChildNode(); child != null; child = child.getTreeNext()) { - if (getChildRole(child) == role) return child; - } - return null; - } - - public int getChildRole(ASTNode child) { - LOG.assertTrue(child.getTreeParent() == this, child); - return 0; //ChildRole.NONE; - } - - protected final int getChildRole(ASTNode child, int roleCandidate) { - if (findChildByRole(roleCandidate) == child) { - return roleCandidate; - } - return 0; //ChildRole.NONE; - } - - @Override - public ASTNode[] getChildren(@Nullable TokenSet filter) { - int count = countChildren(filter); - if (count == 0) { - return EMPTY_ARRAY; - } - final ASTNode[] result = new ASTNode[count]; - count = 0; - for (ASTNode child = getFirstChildNode(); child != null; child = child.getTreeNext()) { - if (filter == null || filter.contains(child.getElementType())) { - result[count++] = child; - } - } - return result; - } - - @NotNull - public T[] getChildrenAsPsiElements(@Nullable TokenSet filter, ArrayFactory constructor) { - ApplicationManager.getApplication().assertReadAccessAllowed(); - int count = countChildren(filter); - T[] result = constructor.create(count); - if (count == 0) { - return result; - } - int idx = 0; - for (ASTNode child = getFirstChildNode(); child != null && idx < count; child = child.getTreeNext()) { - if (filter == null || filter.contains(child.getElementType())) { - @SuppressWarnings("unchecked") T element = (T)child.getPsi(); - LOG.assertTrue(element != null, child); - result[idx++] = element; - } - } - return result; - } - - @NotNull - public T[] getChildrenAsPsiElements(@NotNull IElementType type, ArrayFactory constructor) { - ApplicationManager.getApplication().assertReadAccessAllowed(); - int count = countChildren(type); - T[] result = constructor.create(count); - if (count == 0) { - return result; - } - int idx = 0; - for (ASTNode child = getFirstChildNode(); child != null && idx < count; child = child.getTreeNext()) { - if (type == child.getElementType()) { - @SuppressWarnings("unchecked") T element = (T)child.getPsi(); - LOG.assertTrue(element != null, child); - result[idx++] = element; - } - } - return result; - } - - public int countChildren(@Nullable TokenSet filter) { - // no lock is needed because all chameleons are expanded already - int count = 0; - for (ASTNode child = getFirstChildNode(); child != null; child = child.getTreeNext()) { - if (filter == null || filter.contains(child.getElementType())) { - count++; - } - } - - return count; - } - - public int countChildren(IElementType type) { - // no lock is needed because all chameleons are expanded already - int count = 0; - for (ASTNode child = getFirstChildNode(); child != null; child = child.getTreeNext()) { - if (type == child.getElementType()) { - count++; - } - } - - return count; - } - - /** - * @return First element that was appended (for example whitespaces could be skipped) - */ - public TreeElement addInternal(TreeElement first, ASTNode last, ASTNode anchor, Boolean before) { - ASTNode anchorBefore; - if (anchor != null) { - anchorBefore = before.booleanValue() ? anchor : anchor.getTreeNext(); - } - else { - anchorBefore = before == null || before.booleanValue() ? null : getFirstChildNode(); - } - return (TreeElement)CodeEditUtil.addChildren(this, first, last, anchorBefore); - } - - public void deleteChildInternal(@NotNull ASTNode child) { - CodeEditUtil.removeChild(this, child); - } - - public void replaceChildInternal(@NotNull ASTNode child, @NotNull TreeElement newElement) { - CodeEditUtil.replaceChild(this, child, newElement); - } - - @Override - public int getTextLength() { - int cachedLength = myCachedLength; - if (cachedLength >= 0) return cachedLength; - - synchronized (START_OFFSET_LOCK) { - cachedLength = myCachedLength; - if (cachedLength >= 0) return cachedLength; - - ApplicationManager.getApplication().assertReadAccessAllowed(); //otherwise a write action can modify the tree while we're walking it - try { - walkCachingLength(); - } - catch (AssertionError e) { - myCachedLength = NOT_CACHED; - String assertion = StringUtil.getThrowableText(e); - throw new AssertionError("Walking failure: ===\n"+assertion+"\n=== Thread dump:\n"+ ThreadDumper.dumpThreadsToString()+"\n===\n"); - } - return myCachedLength; - } - } - - @Override - public int hc() { - int hc = myHC; - if (hc == -1) { - hc = 0; - TreeElement child = firstChild; - while (child != null) { - hc += child.hc(); - child = child.getTreeNext(); - } - myHC = hc; - } - return hc; - } - - @Override - public int getCachedLength() { - return myCachedLength; - } - - private void walkCachingLength() { - if (myCachedLength != NOT_CACHED) { - throw new AssertionError("Before walking: cached="+myCachedLength); - } - - TreeElement cur = this; - while (cur != null) { - cur = next(cur); - } - - if (myCachedLength < 0) { - throw new AssertionError("After walking: cached="+myCachedLength); - } - } - - void setCachedLength(int cachedLength) { - myCachedLength = cachedLength; - } - - @Nullable - private TreeElement next(TreeElement cur) { - //for a collapsed chameleon, we're not going down, even if it's expanded by some other thread after this line - final int len = cur.getCachedLength(); - final boolean down = len == NOT_CACHED; - if (down) { - CompositeElement composite = (CompositeElement)cur; // It's a composite or we won't be going down - TreeElement child = composite.getFirstChildNode(); // if we're LazyParseable, sync is a must for accessing the non-volatile field - if (child != null) { - LOG.assertTrue(child.getTreeParent() == composite, cur); - return child; - } - - composite.myCachedLength = 0; - } else { - assert len >= 0 : this + "; len=" + len; - } - - // up - while (cur != this) { - CompositeElement parent = cur.getTreeParent(); - int curLength = cur.getCachedLength(); - if (curLength < 0) { - throw new AssertionError(cur + "; " + curLength); - } - parent.myCachedLength -= curLength; - - TreeElement next = cur.getTreeNext(); - if (next != null) { - LOG.assertTrue(next.getTreePrev() == cur, cur); - return next; - } - - LOG.assertTrue(parent.getLastChildNode() == cur, parent); - parent.myCachedLength = -parent.myCachedLength + NOT_CACHED; - - cur = parent; - } - - return null; - } - - @Override - public TreeElement getFirstChildNode() { - return firstChild; - } - - @Override - public TreeElement getLastChildNode() { - return lastChild; - } - - void setFirstChildNode(TreeElement firstChild) { - this.firstChild = firstChild; - clearRelativeOffsets(firstChild); - } - - void setLastChildNode(TreeElement lastChild) { - this.lastChild = lastChild; - } - - @Override - public void addChild(@NotNull ASTNode child, @Nullable final ASTNode anchorBefore) { - LOG.assertTrue(anchorBefore == null || ((TreeElement)anchorBefore).getTreeParent() == this, "anchorBefore == null || anchorBefore.getTreeParent() == parent"); - TreeUtil.ensureParsed(getFirstChildNode()); - TreeUtil.ensureParsed(child); - final TreeElement last = ((TreeElement)child).getTreeNext(); - final TreeElement first = (TreeElement)child; - - removeChildrenInner(first, last); - - ChangeUtil.prepareAndRunChangeAction(new ChangeUtil.ChangeAction(){ - @Override - public void makeChange(TreeChangeEvent destinationTreeChange) { - if (anchorBefore != null) { - insertBefore(destinationTreeChange, (TreeElement)anchorBefore, first); - } - else { - add(destinationTreeChange, CompositeElement.this, first); - } - } - }, this); - } - - @Override - public void addLeaf(@NotNull final IElementType leafType, final CharSequence leafText, final ASTNode anchorBefore) { - FileElement holder = new DummyHolder(getManager(), null).getTreeElement(); - final LeafElement leaf = ASTFactory.leaf(leafType, holder.getCharTable().intern(leafText)); - CodeEditUtil.setNodeGenerated(leaf, true); - holder.rawAddChildren(leaf); - - addChild(leaf, anchorBefore); - } - - @Override - public void addChild(@NotNull ASTNode child) { - addChild(child, null); - } - - @Override - public void removeChild(@NotNull ASTNode child) { - removeChildInner((TreeElement)child); - } - - @Override - public void removeRange(@NotNull ASTNode first, ASTNode firstWhichStayInTree) { - removeChildrenInner((TreeElement)first, (TreeElement)firstWhichStayInTree); - } - - @Override - public void replaceChild(@NotNull ASTNode oldChild, @NotNull ASTNode newChild) { - LOG.assertTrue(((TreeElement)oldChild).getTreeParent() == this); - final TreeElement oldChild1 = (TreeElement)oldChild; - final TreeElement newChildNext = ((TreeElement)newChild).getTreeNext(); - final TreeElement newChild1 = (TreeElement)newChild; - - if(oldChild1 == newChild1) return; - - removeChildrenInner(newChild1, newChildNext); - - ChangeUtil.prepareAndRunChangeAction(new ChangeUtil.ChangeAction(){ - @Override - public void makeChange(TreeChangeEvent destinationTreeChange) { - replace(destinationTreeChange, oldChild1, newChild1); - repairRemovedElement(CompositeElement.this, oldChild1); - } - }, this); - } - - @Override - public void replaceAllChildrenToChildrenOf(final ASTNode anotherParent) { - TreeUtil.ensureParsed(getFirstChildNode()); - TreeUtil.ensureParsed(anotherParent.getFirstChildNode()); - final ASTNode firstChild = anotherParent.getFirstChildNode(); - ChangeUtil.prepareAndRunChangeAction(new ChangeUtil.ChangeAction(){ - @Override - public void makeChange(TreeChangeEvent destinationTreeChange) { - destinationTreeChange.addElementaryChange(anotherParent, ChangeInfoImpl.create(ChangeInfo.CONTENTS_CHANGED, anotherParent)); - ((CompositeElement)anotherParent).rawRemoveAllChildren(); - } - }, (TreeElement)anotherParent); - - if (firstChild != null) { - ChangeUtil.prepareAndRunChangeAction(new ChangeUtil.ChangeAction(){ - @Override - public void makeChange(TreeChangeEvent destinationTreeChange) { - if(getTreeParent() != null){ - final ChangeInfoImpl changeInfo = ChangeInfoImpl.create(ChangeInfo.CONTENTS_CHANGED, CompositeElement.this); - changeInfo.setOldLength(getTextLength()); - destinationTreeChange.addElementaryChange(CompositeElement.this, changeInfo); - rawRemoveAllChildren(); - rawAddChildren((TreeElement)firstChild); - } - else{ - final TreeElement first = getFirstChildNode(); - remove(destinationTreeChange, first, null); - add(destinationTreeChange, CompositeElement.this, (TreeElement)firstChild); - repairRemovedElement(CompositeElement.this, first); - } - } - }, this); - } - else { - removeAllChildren(); - } - } - - public void removeAllChildren() { - final TreeElement child = getFirstChildNode(); - if (child != null) { - removeRange(child, null); - } - } - - @Override - public void addChildren(ASTNode firstChild, ASTNode lastChild, ASTNode anchorBefore) { - while (firstChild != lastChild) { - final ASTNode next1 = firstChild.getTreeNext(); - addChild(firstChild, anchorBefore); - firstChild = next1; - } - } - - @Override - public final PsiElement getPsi() { - ProgressIndicatorProvider.checkCanceled(); // We hope this method is being called often enough to cancel daemon processes smoothly - - PsiElement wrapper = myWrapper; - if (wrapper != null) return wrapper; - - synchronized (PsiLock.LOCK) { - wrapper = myWrapper; - if (wrapper != null) return wrapper; - - return createAndStorePsi(); - } - } - - @Override - @Nullable - public T getPsi(Class clazz) { - return LeafElement.getPsi(clazz, getPsi(), LOG); - } - - private PsiElement createAndStorePsi() { - PsiElement psi = createPsiNoLock(); - myWrapper = psi; - return psi; - } - - protected PsiElement createPsiNoLock() { - final Language lang = getElementType().getLanguage(); - final ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(lang); - if (parserDefinition != null) { - return parserDefinition.createElement(this); - } - - //noinspection ConstantConditions - return null; - } - - public void setPsi(@NotNull PsiElement psi) { - myWrapper = psi; - } - - public final void rawAddChildren(@NotNull TreeElement first) { - rawAddChildrenWithoutNotifications(first); - - subtreeChanged(); - } - - public void rawAddChildrenWithoutNotifications(TreeElement first) { - final TreeElement last = getLastChildNode(); - if (last == null){ - first.rawRemoveUpToWithoutNotifications(null); - setFirstChildNode(first); - while(true){ - final TreeElement treeNext = first.getTreeNext(); - first.setTreeParent(this); - if(treeNext == null) break; - first = treeNext; - } - setLastChildNode(first); - first.setTreeParent(this); - } - else { - last.rawInsertAfterMeWithoutNotifications(first); - } - - DebugUtil.checkTreeStructure(this); - } - - public void rawRemoveAllChildren() { - TreeElement first = getFirstChildNode(); - if (first != null) { - first.rawRemoveUpToLast(); - } - } - - // creates PSI and stores to the 'myWrapper', if not created already - void createAllChildrenPsiIfNecessary() { - synchronized (PsiLock.LOCK) { // guard for race condition with getPsi() - acceptTree(CREATE_CHILDREN_PSI); - } - } - private static final RecursiveTreeElementWalkingVisitor CREATE_CHILDREN_PSI = new RecursiveTreeElementWalkingVisitor(false) { - @Override - public void visitLeaf(LeafElement leaf) { - } - - @Override - public void visitComposite(CompositeElement composite) { - ProgressIndicatorProvider.checkCanceled(); // we can safely interrupt creating children PSI any moment - if (composite.myWrapper != null) { - // someone else 've managed to create the PSI in the meantime. Abandon our attempts to cache everything. - stopWalking(); - return; - } - composite.createAndStorePsi(); - super.visitComposite(composite); - } - }; - - private static void repairRemovedElement(final CompositeElement oldParent, final TreeElement oldChild) { - if(oldChild == null) return; - final FileElement treeElement = DummyHolderFactory.createHolder(oldParent.getManager(), null, false).getTreeElement(); - treeElement.rawAddChildren(oldChild); - } - - private static void add(final TreeChangeEvent destinationTreeChange, - final CompositeElement parent, - final TreeElement first) { - parent.rawAddChildren(first); - TreeElement child = first; - while(child != null){ - destinationTreeChange.addElementaryChange(child, ChangeInfoImpl.create(ChangeInfo.ADD, child)); - child = child.getTreeNext(); - } - } - - private static void remove(final TreeChangeEvent destinationTreeChange, - final TreeElement first, - final TreeElement last) { - if (first != null) { - TreeElement child = first; - while(child != last && child != null){ - destinationTreeChange.addElementaryChange(child, ChangeInfoImpl.create(ChangeInfo.REMOVED, child)); - child = child.getTreeNext(); - } - - first.rawRemoveUpTo(last); - } - } - - private static void insertBefore(final TreeChangeEvent destinationTreeChange, - final TreeElement anchorBefore, - final TreeElement first) { - anchorBefore.rawInsertBeforeMe(first); - TreeElement child = first; - while(child != anchorBefore){ - destinationTreeChange.addElementaryChange(child, ChangeInfoImpl.create(ChangeInfo.ADD, child)); - child = child.getTreeNext(); - } - } - - private static void replace(final TreeChangeEvent sourceTreeChange, - final TreeElement oldChild, - final TreeElement newChild) { - oldChild.rawReplaceWithList(newChild); - final ReplaceChangeInfoImpl change = new ReplaceChangeInfoImpl(newChild); - sourceTreeChange.addElementaryChange(newChild, change); - change.setReplaced(oldChild); - } - - private static void removeChildInner(final TreeElement child) { - removeChildrenInner(child, child.getTreeNext()); - } - - private static void removeChildrenInner(final TreeElement first, final TreeElement last) { - final FileElement fileElement = TreeUtil.getFileElement(first); - if (fileElement != null) { - ChangeUtil.prepareAndRunChangeAction(new ChangeUtil.ChangeAction() { - @Override - public void makeChange(TreeChangeEvent destinationTreeChange) { - remove(destinationTreeChange, first, last); - repairRemovedElement(fileElement, first); - } - }, first.getTreeParent()); - } - else { - first.rawRemoveUpTo(last); - } - } - - - public TreeElement rawFirstChild() { - return firstChild; - } - - public TreeElement rawLastChild() { - return lastChild; - } -} +/* + * 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.psi.impl.source.tree; + +import com.intellij.diagnostic.ThreadDumper; +import com.intellij.extapi.psi.ASTDelegatePsiElement; +import com.intellij.lang.*; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressIndicatorProvider; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.pom.tree.events.ChangeInfo; +import com.intellij.pom.tree.events.TreeChangeEvent; +import com.intellij.pom.tree.events.impl.ChangeInfoImpl; +import com.intellij.pom.tree.events.impl.ReplaceChangeInfoImpl; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiLock; +import com.intellij.psi.impl.DebugUtil; +import com.intellij.psi.impl.FreeThreadedFileViewProvider; +import com.intellij.psi.impl.source.DummyHolder; +import com.intellij.psi.impl.source.DummyHolderElement; +import com.intellij.psi.impl.source.DummyHolderFactory; +import com.intellij.psi.impl.source.SourceTreeToPsiMap; +import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; +import com.intellij.util.ArrayFactory; +import com.intellij.util.text.CharArrayCharSequence; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class CompositeElement extends TreeElement { + private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.CompositeElement"); + + private TreeElement firstChild = null; + private TreeElement lastChild = null; + + private volatile int myModificationsCount = 0; + private static final int NOT_CACHED = -239; + private volatile int myCachedLength = NOT_CACHED; + private volatile int myHC = -1; + private volatile PsiElement myWrapper = null; + private static final boolean ASSERT_THREADING = true;//DebugUtil.CHECK || ApplicationManagerEx.getApplicationEx().isInternal() || ApplicationManagerEx.getApplicationEx().isUnitTestMode(); + + public CompositeElement(@NotNull IElementType type) { + super(type); + } + + public int getModificationCount() { + return myModificationsCount; + } + + @Override + public CompositeElement clone() { + CompositeElement clone = (CompositeElement)super.clone(); + + synchronized (PsiLock.LOCK) { + clone.firstChild = null; + clone.lastChild = null; + clone.myModificationsCount = 0; + clone.myWrapper = null; + for (ASTNode child = rawFirstChild(); child != null; child = child.getTreeNext()) { + clone.rawAddChildrenWithoutNotifications((TreeElement)child.clone()); + } + clone.clearCaches(); + } + return clone; + } + + public void subtreeChanged() { + synchronized (PsiLock.LOCK) { + CompositeElement compositeElement = this; + while(compositeElement != null) { + compositeElement.clearCaches(); + if (!(compositeElement instanceof PsiElement)) { + final PsiElement psi = compositeElement.myWrapper; + if (psi instanceof ASTDelegatePsiElement) { + ((ASTDelegatePsiElement)psi).subtreeChanged(); + } + else if (psi instanceof PsiFile) { + ((PsiFile)psi).subtreeChanged(); + } + } + + compositeElement = compositeElement.getTreeParent(); + } + } + } + + @Override + public void clearCaches() { + assertThreading(); + myCachedLength = NOT_CACHED; + + myModificationsCount++; + myHC = -1; + + clearRelativeOffsets(rawFirstChild()); + } + + public void assertThreading() { + if (ASSERT_THREADING) { + boolean ok = ApplicationManager.getApplication().isWriteAccessAllowed() || + //Thread.holdsLock(START_OFFSET_LOCK) || + isNonPhysicalOrInjected(); + if (!ok) { + FileElement fileElement; + PsiFile psiFile; + LOG.error("Threading assertion. " + + " Under write: " + ApplicationManager.getApplication().isWriteAccessAllowed() + + "; Thread.holdsLock(START_OFFSET_LOCK): " + Thread.holdsLock(START_OFFSET_LOCK) + + "; Thread.holdsLock(PsiLock.LOCK): " + Thread.holdsLock(PsiLock.LOCK) + + "; wrapper: " + myWrapper + + "; wrapper.isPhysical(): " + (myWrapper != null && myWrapper.isPhysical()) + + "; fileElement: " +(fileElement = TreeUtil.getFileElement(this))+ + "; psiFile: " + (psiFile = fileElement == null ? null : (PsiFile)fileElement.getPsi()) + + "; psiFile.getViewProvider(): " + (psiFile == null ? null : psiFile.getViewProvider()) + + "; psiFile.isPhysical(): " + (psiFile != null && psiFile.isPhysical()) + ); + } + } + } + + private boolean isNonPhysicalOrInjected() { + FileElement fileElement = TreeUtil.getFileElement(this); + if (fileElement == null || fileElement instanceof DummyHolderElement) return true; + if (fileElement.getTreeParent() != null) return true; // dummy holder + PsiElement wrapper = this instanceof PsiElement ? (PsiElement)this : myWrapper; + if (wrapper == null) return true; + PsiFile psiFile = wrapper.getContainingFile(); + return + psiFile == null || + psiFile instanceof DummyHolder || + psiFile.getViewProvider() instanceof FreeThreadedFileViewProvider || + !psiFile.isPhysical(); + } + + @Override + public void acceptTree(TreeElementVisitor visitor) { + visitor.visitComposite(this); + } + + @Override + public LeafElement findLeafElementAt(int offset) { + TreeElement element = this; + startFind: + while (true) { + TreeElement child = element.getFirstChildNode(); + while (child != null) { + final int textLength = child.getTextLength(); + if (textLength > offset) { + if (child instanceof LeafElement) { + if (child instanceof ForeignLeafPsiElement) { + child = child.getTreeNext(); + continue; + } + return (LeafElement)child; + } + element = child; + continue startFind; + } + offset -= textLength; + child = child.getTreeNext(); + } + return null; + } + } + + @Nullable + public PsiElement findPsiChildByType(IElementType type) { + final ASTNode node = findChildByType(type); + return node == null ? null : node.getPsi(); + } + + @Nullable + public PsiElement findPsiChildByType(TokenSet types) { + final ASTNode node = findChildByType(types); + return node == null ? null : node.getPsi(); + } + + @Override + public ASTNode findChildByType(IElementType type) { + if (DebugUtil.CHECK_INSIDE_ATOMIC_ACTION_ENABLED){ + ApplicationManager.getApplication().assertReadAccessAllowed(); + } + + for(ASTNode element = getFirstChildNode(); element != null; element = element.getTreeNext()){ + if (element.getElementType() == type) return element; + } + return null; + } + + @Override + public ASTNode findChildByType(IElementType type, ASTNode anchor) { + if (DebugUtil.CHECK_INSIDE_ATOMIC_ACTION_ENABLED){ + ApplicationManager.getApplication().assertReadAccessAllowed(); + } + + ASTNode child = anchor; + while (true) { + if (child == null) return null; + if (type == child.getElementType()) return child; + child = child.getTreeNext(); + } + } + + @Override + @Nullable + public ASTNode findChildByType(@NotNull TokenSet types) { + if (DebugUtil.CHECK_INSIDE_ATOMIC_ACTION_ENABLED){ + ApplicationManager.getApplication().assertReadAccessAllowed(); + } + for(ASTNode element = getFirstChildNode(); element != null; element = element.getTreeNext()){ + if (types.contains(element.getElementType())) return element; + } + return null; + } + + @Override + @Nullable + public ASTNode findChildByType(@NotNull TokenSet typesSet, ASTNode anchor) { + if (DebugUtil.CHECK_INSIDE_ATOMIC_ACTION_ENABLED){ + ApplicationManager.getApplication().assertReadAccessAllowed(); + } + ASTNode child = anchor; + while (true) { + if (child == null) return null; + if (typesSet.contains(child.getElementType())) return child; + child = child.getTreeNext(); + } + } + + @Override + @NotNull + public String getText() { + return new String(textToCharArray()); + } + + @Override + public CharSequence getChars() { + return new CharArrayCharSequence(textToCharArray()); + } + + @Override + public int getNotCachedLength() { + final int[] result = {0}; + + acceptTree(new RecursiveTreeElementWalkingVisitor(false) { + @Override + protected void visitNode(final TreeElement element) { + if (element instanceof LeafElement || TreeUtil.isCollapsedChameleon(element)) { + result[0] += element.getNotCachedLength(); + } + super.visitNode(element); + } + }); + + return result[0]; + } + + @Override + @NotNull + public char[] textToCharArray() { + ApplicationManager.getApplication().assertReadAccessAllowed(); + int startStamp = myModificationsCount; + + final int len = getTextLength(); + + if (startStamp != myModificationsCount) { + throw new AssertionError("Tree changed while calculating text. startStamp:"+startStamp+"; current:"+myModificationsCount+"; myHC:"+myHC+"; assertThreading:"+ASSERT_THREADING+"; Thread.holdsLock(START_OFFSET_LOCK):"+Thread.holdsLock(START_OFFSET_LOCK)+"; Thread.holdsLock(PSI_LOCK):"+Thread.holdsLock(PsiLock.LOCK)+"; this: " + this); + } + + char[] buffer = new char[len]; + final int endOffset; + try { + endOffset = AstBufferUtil.toBuffer(this, buffer, 0); + } + catch (ArrayIndexOutOfBoundsException e) { + @NonNls String msg = "Underestimated text length: " + len; + msg += diagnoseTextInconsistency(new String(buffer), startStamp); + try { + int length = AstBufferUtil.toBuffer(this, new char[len], 0); + msg += ";\n repetition gives success (" + length + ")"; + } + catch (ArrayIndexOutOfBoundsException e1) { + msg += ";\n repetition fails as well"; + } + throw new RuntimeException(msg, e); + } + if (endOffset != len) { + @NonNls String msg = "len=" + len + ";\n endOffset=" + endOffset; + msg += diagnoseTextInconsistency(new String(buffer, 0, Math.min(len, endOffset)), startStamp); + throw new AssertionError(msg); + } + return buffer; + } + + private String diagnoseTextInconsistency(String text, int startStamp) { + @NonNls String msg = ""; + msg += ";\n changed=" + (startStamp != myModificationsCount); + msg += ";\n buffer=" + text; + msg += ";\n this=" + this; + int shitStart = textMatches(text, 0); + msg += ";\n matches until " + shitStart; + LeafElement leaf = findLeafElementAt(Math.abs(shitStart)); + msg += ";\n element there=" + leaf; + if (leaf != null) { + PsiElement psi = leaf.getPsi(); + msg += ";\n leaf.text=" + leaf.getText(); + msg += ";\n leaf.psi=" + psi; + msg += ";\n leaf.lang=" + (psi == null ? null : psi.getLanguage()); + msg += ";\n leaf.type=" + leaf.getElementType(); + } + PsiElement psi = getPsi(); + if (psi != null) { + boolean valid = psi.isValid(); + msg += ";\n psi.valid=" + valid; + if (valid) { + PsiFile file = psi.getContainingFile(); + if (file != null) { + msg += ";\n psi.file=" + file; + msg += ";\n psi.file.tl=" + file.getTextLength(); + msg += ";\n psi.file.lang=" + file.getLanguage(); + msg += ";\n psi.file.vp=" + file.getViewProvider(); + msg += ";\n psi.file.vp.lang=" + file.getViewProvider().getLanguages(); + msg += ";\n psi.file.vp.lang=" + file.getViewProvider().getLanguages(); + + PsiElement fileLeaf = file.findElementAt(getTextRange().getStartOffset()); + LeafElement myLeaf = findLeafElementAt(0); + msg += ";\n leaves at start=" + fileLeaf + " and " + myLeaf; + } + } + } + return msg; + } + + @Override + public boolean textContains(char c) { + for (ASTNode child = getFirstChildNode(); child != null; child = child.getTreeNext()) { + if (child.textContains(c)) return true; + } + return false; + } + + @Override + protected int textMatches(@NotNull CharSequence buffer, int start) { + int curOffset = start; + for (TreeElement child = getFirstChildNode(); child != null; child = child.getTreeNext()) { + curOffset = child.textMatches(buffer, curOffset); + if (curOffset < 0) return curOffset; + } + return curOffset; + } + + /* + protected int textMatches(final CharSequence buffer, final int start) { + final int[] curOffset = {start}; + acceptTree(new RecursiveTreeElementWalkingVisitor() { + @Override + public void visitLeaf(LeafElement leaf) { + matchText(leaf); + } + + private void matchText(TreeElement leaf) { + curOffset[0] = leaf.textMatches(buffer, curOffset[0]); + if (curOffset[0] == -1) { + stopWalking(); + } + } + + @Override + public void visitComposite(CompositeElement composite) { + if (composite instanceof LazyParseableElement && !((LazyParseableElement)composite).isParsed()) { + matchText(composite); + } + else { + super.visitComposite(composite); + } + } + }); + return curOffset[0]; + } + */ + + @Nullable + public final PsiElement findChildByRoleAsPsiElement(int role) { + ASTNode element = findChildByRole(role); + if (element == null) return null; + return SourceTreeToPsiMap.treeElementToPsi(element); + } + + @Nullable + public ASTNode findChildByRole(int role) { + // assert ChildRole.isUnique(role); + for (ASTNode child = getFirstChildNode(); child != null; child = child.getTreeNext()) { + if (getChildRole(child) == role) return child; + } + return null; + } + + public int getChildRole(ASTNode child) { + LOG.assertTrue(child.getTreeParent() == this, child); + return 0; //ChildRole.NONE; + } + + protected final int getChildRole(ASTNode child, int roleCandidate) { + if (findChildByRole(roleCandidate) == child) { + return roleCandidate; + } + return 0; //ChildRole.NONE; + } + + @Override + public ASTNode[] getChildren(@Nullable TokenSet filter) { + int count = countChildren(filter); + if (count == 0) { + return EMPTY_ARRAY; + } + final ASTNode[] result = new ASTNode[count]; + count = 0; + for (ASTNode child = getFirstChildNode(); child != null; child = child.getTreeNext()) { + if (filter == null || filter.contains(child.getElementType())) { + result[count++] = child; + } + } + return result; + } + + @NotNull + public T[] getChildrenAsPsiElements(@Nullable TokenSet filter, ArrayFactory constructor) { + ApplicationManager.getApplication().assertReadAccessAllowed(); + int count = countChildren(filter); + T[] result = constructor.create(count); + if (count == 0) { + return result; + } + int idx = 0; + for (ASTNode child = getFirstChildNode(); child != null && idx < count; child = child.getTreeNext()) { + if (filter == null || filter.contains(child.getElementType())) { + @SuppressWarnings("unchecked") T element = (T)child.getPsi(); + LOG.assertTrue(element != null, child); + result[idx++] = element; + } + } + return result; + } + + @NotNull + public T[] getChildrenAsPsiElements(@NotNull IElementType type, ArrayFactory constructor) { + ApplicationManager.getApplication().assertReadAccessAllowed(); + int count = countChildren(type); + T[] result = constructor.create(count); + if (count == 0) { + return result; + } + int idx = 0; + for (ASTNode child = getFirstChildNode(); child != null && idx < count; child = child.getTreeNext()) { + if (type == child.getElementType()) { + @SuppressWarnings("unchecked") T element = (T)child.getPsi(); + LOG.assertTrue(element != null, child); + result[idx++] = element; + } + } + return result; + } + + public int countChildren(@Nullable TokenSet filter) { + // no lock is needed because all chameleons are expanded already + int count = 0; + for (ASTNode child = getFirstChildNode(); child != null; child = child.getTreeNext()) { + if (filter == null || filter.contains(child.getElementType())) { + count++; + } + } + + return count; + } + + public int countChildren(IElementType type) { + // no lock is needed because all chameleons are expanded already + int count = 0; + for (ASTNode child = getFirstChildNode(); child != null; child = child.getTreeNext()) { + if (type == child.getElementType()) { + count++; + } + } + + return count; + } + + /** + * @return First element that was appended (for example whitespaces could be skipped) + */ + public TreeElement addInternal(TreeElement first, ASTNode last, ASTNode anchor, Boolean before) { + ASTNode anchorBefore; + if (anchor != null) { + anchorBefore = before.booleanValue() ? anchor : anchor.getTreeNext(); + } + else { + anchorBefore = before == null || before.booleanValue() ? null : getFirstChildNode(); + } + return (TreeElement)CodeEditUtil.addChildren(this, first, last, anchorBefore); + } + + public void deleteChildInternal(@NotNull ASTNode child) { + CodeEditUtil.removeChild(this, child); + } + + public void replaceChildInternal(@NotNull ASTNode child, @NotNull TreeElement newElement) { + CodeEditUtil.replaceChild(this, child, newElement); + } + + @Override + public int getTextLength() { + int cachedLength = myCachedLength; + if (cachedLength >= 0) return cachedLength; + + synchronized (START_OFFSET_LOCK) { + cachedLength = myCachedLength; + if (cachedLength >= 0) return cachedLength; + + ApplicationManager.getApplication().assertReadAccessAllowed(); //otherwise a write action can modify the tree while we're walking it + try { + walkCachingLength(); + } + catch (AssertionError e) { + myCachedLength = NOT_CACHED; + String assertion = StringUtil.getThrowableText(e); + throw new AssertionError("Walking failure: ===\n"+assertion+"\n=== Thread dump:\n"+ ThreadDumper.dumpThreadsToString()+"\n===\n"); + } + return myCachedLength; + } + } + + @Override + public int hc() { + int hc = myHC; + if (hc == -1) { + hc = 0; + TreeElement child = firstChild; + while (child != null) { + hc += child.hc(); + child = child.getTreeNext(); + } + myHC = hc; + } + return hc; + } + + @Override + public int getCachedLength() { + return myCachedLength; + } + + private void walkCachingLength() { + if (myCachedLength != NOT_CACHED) { + throw new AssertionError("Before walking: cached="+myCachedLength); + } + + TreeElement cur = this; + while (cur != null) { + cur = next(cur); + } + + if (myCachedLength < 0) { + throw new AssertionError("After walking: cached="+myCachedLength); + } + } + + void setCachedLength(int cachedLength) { + myCachedLength = cachedLength; + } + + @Nullable + private TreeElement next(TreeElement cur) { + //for a collapsed chameleon, we're not going down, even if it's expanded by some other thread after this line + final int len = cur.getCachedLength(); + final boolean down = len == NOT_CACHED; + if (down) { + CompositeElement composite = (CompositeElement)cur; // It's a composite or we won't be going down + TreeElement child = composite.getFirstChildNode(); // if we're LazyParseable, sync is a must for accessing the non-volatile field + if (child != null) { + LOG.assertTrue(child.getTreeParent() == composite, cur); + return child; + } + + composite.myCachedLength = 0; + } else { + assert len >= 0 : this + "; len=" + len; + } + + // up + while (cur != this) { + CompositeElement parent = cur.getTreeParent(); + int curLength = cur.getCachedLength(); + if (curLength < 0) { + throw new AssertionError(cur + "; " + curLength); + } + parent.myCachedLength -= curLength; + + TreeElement next = cur.getTreeNext(); + if (next != null) { + LOG.assertTrue(next.getTreePrev() == cur, cur); + return next; + } + + LOG.assertTrue(parent.getLastChildNode() == cur, parent); + parent.myCachedLength = -parent.myCachedLength + NOT_CACHED; + + cur = parent; + } + + return null; + } + + @Override + public TreeElement getFirstChildNode() { + return firstChild; + } + + @Override + public TreeElement getLastChildNode() { + return lastChild; + } + + void setFirstChildNode(TreeElement firstChild) { + this.firstChild = firstChild; + clearRelativeOffsets(firstChild); + } + + void setLastChildNode(TreeElement lastChild) { + this.lastChild = lastChild; + } + + @Override + public void addChild(@NotNull ASTNode child, @Nullable final ASTNode anchorBefore) { + LOG.assertTrue(anchorBefore == null || ((TreeElement)anchorBefore).getTreeParent() == this, "anchorBefore == null || anchorBefore.getTreeParent() == parent"); + TreeUtil.ensureParsed(getFirstChildNode()); + TreeUtil.ensureParsed(child); + final TreeElement last = ((TreeElement)child).getTreeNext(); + final TreeElement first = (TreeElement)child; + + removeChildrenInner(first, last); + + ChangeUtil.prepareAndRunChangeAction(new ChangeUtil.ChangeAction(){ + @Override + public void makeChange(TreeChangeEvent destinationTreeChange) { + if (anchorBefore != null) { + insertBefore(destinationTreeChange, (TreeElement)anchorBefore, first); + } + else { + add(destinationTreeChange, CompositeElement.this, first); + } + } + }, this); + } + + @Override + public void addLeaf(@NotNull final IElementType leafType, final CharSequence leafText, final ASTNode anchorBefore) { + FileElement holder = new DummyHolder(getManager(), null).getTreeElement(); + final LeafElement leaf = ASTFactory.leaf(leafType, holder.getCharTable().intern(leafText)); + CodeEditUtil.setNodeGenerated(leaf, true); + holder.rawAddChildren(leaf); + + addChild(leaf, anchorBefore); + } + + @Override + public void addChild(@NotNull ASTNode child) { + addChild(child, null); + } + + @Override + public void removeChild(@NotNull ASTNode child) { + removeChildInner((TreeElement)child); + } + + @Override + public void removeRange(@NotNull ASTNode first, ASTNode firstWhichStayInTree) { + removeChildrenInner((TreeElement)first, (TreeElement)firstWhichStayInTree); + } + + @Override + public void replaceChild(@NotNull ASTNode oldChild, @NotNull ASTNode newChild) { + LOG.assertTrue(((TreeElement)oldChild).getTreeParent() == this); + final TreeElement oldChild1 = (TreeElement)oldChild; + final TreeElement newChildNext = ((TreeElement)newChild).getTreeNext(); + final TreeElement newChild1 = (TreeElement)newChild; + + if(oldChild1 == newChild1) return; + + removeChildrenInner(newChild1, newChildNext); + + ChangeUtil.prepareAndRunChangeAction(new ChangeUtil.ChangeAction(){ + @Override + public void makeChange(TreeChangeEvent destinationTreeChange) { + replace(destinationTreeChange, oldChild1, newChild1); + repairRemovedElement(CompositeElement.this, oldChild1); + } + }, this); + } + + @Override + public void replaceAllChildrenToChildrenOf(final ASTNode anotherParent) { + TreeUtil.ensureParsed(getFirstChildNode()); + TreeUtil.ensureParsed(anotherParent.getFirstChildNode()); + final ASTNode firstChild = anotherParent.getFirstChildNode(); + ChangeUtil.prepareAndRunChangeAction(new ChangeUtil.ChangeAction(){ + @Override + public void makeChange(TreeChangeEvent destinationTreeChange) { + destinationTreeChange.addElementaryChange(anotherParent, ChangeInfoImpl.create(ChangeInfo.CONTENTS_CHANGED, anotherParent)); + ((CompositeElement)anotherParent).rawRemoveAllChildren(); + } + }, (TreeElement)anotherParent); + + if (firstChild != null) { + ChangeUtil.prepareAndRunChangeAction(new ChangeUtil.ChangeAction(){ + @Override + public void makeChange(TreeChangeEvent destinationTreeChange) { + if(getTreeParent() != null){ + final ChangeInfoImpl changeInfo = ChangeInfoImpl.create(ChangeInfo.CONTENTS_CHANGED, CompositeElement.this); + changeInfo.setOldLength(getTextLength()); + destinationTreeChange.addElementaryChange(CompositeElement.this, changeInfo); + rawRemoveAllChildren(); + rawAddChildren((TreeElement)firstChild); + } + else{ + final TreeElement first = getFirstChildNode(); + remove(destinationTreeChange, first, null); + add(destinationTreeChange, CompositeElement.this, (TreeElement)firstChild); + repairRemovedElement(CompositeElement.this, first); + } + } + }, this); + } + else { + removeAllChildren(); + } + } + + public void removeAllChildren() { + final TreeElement child = getFirstChildNode(); + if (child != null) { + removeRange(child, null); + } + } + + @Override + public void addChildren(ASTNode firstChild, ASTNode lastChild, ASTNode anchorBefore) { + while (firstChild != lastChild) { + final ASTNode next1 = firstChild.getTreeNext(); + addChild(firstChild, anchorBefore); + firstChild = next1; + } + } + + @Override + public final PsiElement getPsi() { + ProgressIndicatorProvider.checkCanceled(); // We hope this method is being called often enough to cancel daemon processes smoothly + + PsiElement wrapper = myWrapper; + if (wrapper != null) return wrapper; + + synchronized (PsiLock.LOCK) { + wrapper = myWrapper; + if (wrapper != null) return wrapper; + + return createAndStorePsi(); + } + } + + @Override + @Nullable + public T getPsi(Class clazz) { + return LeafElement.getPsi(clazz, getPsi(), LOG); + } + + private PsiElement createAndStorePsi() { + PsiElement psi = createPsiNoLock(); + myWrapper = psi; + return psi; + } + + protected PsiElement createPsiNoLock() { + final Language lang = getElementType().getLanguage(); + final ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(lang); + if (parserDefinition != null) { + return parserDefinition.createElement(this); + } + + //noinspection ConstantConditions + return null; + } + + public void setPsi(@NotNull PsiElement psi) { + myWrapper = psi; + } + + public final void rawAddChildren(@NotNull TreeElement first) { + rawAddChildrenWithoutNotifications(first); + + subtreeChanged(); + } + + public void rawAddChildrenWithoutNotifications(TreeElement first) { + final TreeElement last = getLastChildNode(); + if (last == null){ + first.rawRemoveUpToWithoutNotifications(null); + setFirstChildNode(first); + while(true){ + final TreeElement treeNext = first.getTreeNext(); + first.setTreeParent(this); + if(treeNext == null) break; + first = treeNext; + } + setLastChildNode(first); + first.setTreeParent(this); + } + else { + last.rawInsertAfterMeWithoutNotifications(first); + } + + DebugUtil.checkTreeStructure(this); + } + + public void rawRemoveAllChildren() { + TreeElement first = getFirstChildNode(); + if (first != null) { + first.rawRemoveUpToLast(); + } + } + + // creates PSI and stores to the 'myWrapper', if not created already + void createAllChildrenPsiIfNecessary() { + synchronized (PsiLock.LOCK) { // guard for race condition with getPsi() + acceptTree(CREATE_CHILDREN_PSI); + } + } + private static final RecursiveTreeElementWalkingVisitor CREATE_CHILDREN_PSI = new RecursiveTreeElementWalkingVisitor(false) { + @Override + public void visitLeaf(LeafElement leaf) { + } + + @Override + public void visitComposite(CompositeElement composite) { + ProgressIndicatorProvider.checkCanceled(); // we can safely interrupt creating children PSI any moment + if (composite.myWrapper != null) { + // someone else 've managed to create the PSI in the meantime. Abandon our attempts to cache everything. + stopWalking(); + return; + } + composite.createAndStorePsi(); + super.visitComposite(composite); + } + }; + + private static void repairRemovedElement(final CompositeElement oldParent, final TreeElement oldChild) { + if(oldChild == null) return; + final FileElement treeElement = DummyHolderFactory.createHolder(oldParent.getManager(), null, false).getTreeElement(); + treeElement.rawAddChildren(oldChild); + } + + private static void add(final TreeChangeEvent destinationTreeChange, + final CompositeElement parent, + final TreeElement first) { + parent.rawAddChildren(first); + TreeElement child = first; + while(child != null){ + destinationTreeChange.addElementaryChange(child, ChangeInfoImpl.create(ChangeInfo.ADD, child)); + child = child.getTreeNext(); + } + } + + private static void remove(final TreeChangeEvent destinationTreeChange, + final TreeElement first, + final TreeElement last) { + if (first != null) { + TreeElement child = first; + while(child != last && child != null){ + destinationTreeChange.addElementaryChange(child, ChangeInfoImpl.create(ChangeInfo.REMOVED, child)); + child = child.getTreeNext(); + } + + first.rawRemoveUpTo(last); + } + } + + private static void insertBefore(final TreeChangeEvent destinationTreeChange, + final TreeElement anchorBefore, + final TreeElement first) { + anchorBefore.rawInsertBeforeMe(first); + TreeElement child = first; + while(child != anchorBefore){ + destinationTreeChange.addElementaryChange(child, ChangeInfoImpl.create(ChangeInfo.ADD, child)); + child = child.getTreeNext(); + } + } + + private static void replace(final TreeChangeEvent sourceTreeChange, + final TreeElement oldChild, + final TreeElement newChild) { + oldChild.rawReplaceWithList(newChild); + final ReplaceChangeInfoImpl change = new ReplaceChangeInfoImpl(newChild); + sourceTreeChange.addElementaryChange(newChild, change); + change.setReplaced(oldChild); + } + + private static void removeChildInner(final TreeElement child) { + removeChildrenInner(child, child.getTreeNext()); + } + + private static void removeChildrenInner(final TreeElement first, final TreeElement last) { + final FileElement fileElement = TreeUtil.getFileElement(first); + if (fileElement != null) { + ChangeUtil.prepareAndRunChangeAction(new ChangeUtil.ChangeAction() { + @Override + public void makeChange(TreeChangeEvent destinationTreeChange) { + remove(destinationTreeChange, first, last); + repairRemovedElement(fileElement, first); + } + }, first.getTreeParent()); + } + else { + first.rawRemoveUpTo(last); + } + } + + + public TreeElement rawFirstChild() { + return firstChild; + } + + public TreeElement rawLastChild() { + return lastChild; + } +} diff --git a/platform/funcTests/config/options/feature.usage.statistics.xml b/platform/funcTests/config/options/feature.usage.statistics.xml index caae350bb7c5..e047526ca94f 100644 --- a/platform/funcTests/config/options/feature.usage.statistics.xml +++ b/platform/funcTests/config/options/feature.usage.statistics.xml @@ -1,74 +1,74 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionParameters.java b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionParameters.java index 899405724b80..1058bdb15efe 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionParameters.java +++ b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionParameters.java @@ -1,109 +1,109 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.lookup.Lookup; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; - -/** - * @author peter - */ -public final class CompletionParameters { - private final PsiElement myPosition; - private final PsiFile myOriginalFile; - private final CompletionType myCompletionType; - private final Lookup myLookup; - private final int myOffset; - private final int myInvocationCount; - - CompletionParameters(@NotNull final PsiElement position, @NotNull final PsiFile originalFile, - final CompletionType completionType, int offset, final int invocationCount, Lookup lookup) { - assert offset >= position.getTextRange().getStartOffset(); - myPosition = position; - assert position.isValid(); - myOriginalFile = originalFile; - myCompletionType = completionType; - myOffset = offset; - myInvocationCount = invocationCount; - myLookup = lookup; - } - - public CompletionParameters delegateToClassName() { - return withType(CompletionType.CLASS_NAME).withInvocationCount(myInvocationCount - 1); - } - - public CompletionParameters withType(CompletionType type) { - return new CompletionParameters(myPosition, myOriginalFile, type, myOffset, myInvocationCount, myLookup); - } - - public CompletionParameters withInvocationCount(int newCount) { - return new CompletionParameters(myPosition, myOriginalFile, myCompletionType, myOffset, newCount, myLookup); - } - - @NotNull - public PsiElement getPosition() { - return myPosition; - } - - @NotNull - public Lookup getLookup() { - return myLookup; - } - - @Nullable - public PsiElement getOriginalPosition() { - return myOriginalFile.findElementAt(myPosition.getTextRange().getStartOffset()); - } - - @NotNull - public PsiFile getOriginalFile() { - return myOriginalFile; - } - - @NotNull - public CompletionType getCompletionType() { - return myCompletionType; - } - - public int getOffset() { - return myOffset; - } - - /** - * @return - * 0 for autopopup - * 1 for explicitly invoked completion - * >1 for next completion invocations when one lookup is already active - */ - public int getInvocationCount() { - return myInvocationCount; - } - - public boolean isAutoPopup() { - return myInvocationCount == 0; - } - - public CompletionParameters withPosition(PsiElement element, int offset) { - return new CompletionParameters(element, myOriginalFile, myCompletionType, offset, myInvocationCount, myLookup); - } - - public boolean isExtendedCompletion() { - return myCompletionType == CompletionType.BASIC && myInvocationCount >= 2; - } -} +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.completion; + +import com.intellij.codeInsight.lookup.Lookup; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; + +/** + * @author peter + */ +public final class CompletionParameters { + private final PsiElement myPosition; + private final PsiFile myOriginalFile; + private final CompletionType myCompletionType; + private final Lookup myLookup; + private final int myOffset; + private final int myInvocationCount; + + CompletionParameters(@NotNull final PsiElement position, @NotNull final PsiFile originalFile, + final CompletionType completionType, int offset, final int invocationCount, Lookup lookup) { + assert offset >= position.getTextRange().getStartOffset(); + myPosition = position; + assert position.isValid(); + myOriginalFile = originalFile; + myCompletionType = completionType; + myOffset = offset; + myInvocationCount = invocationCount; + myLookup = lookup; + } + + public CompletionParameters delegateToClassName() { + return withType(CompletionType.CLASS_NAME).withInvocationCount(myInvocationCount - 1); + } + + public CompletionParameters withType(CompletionType type) { + return new CompletionParameters(myPosition, myOriginalFile, type, myOffset, myInvocationCount, myLookup); + } + + public CompletionParameters withInvocationCount(int newCount) { + return new CompletionParameters(myPosition, myOriginalFile, myCompletionType, myOffset, newCount, myLookup); + } + + @NotNull + public PsiElement getPosition() { + return myPosition; + } + + @NotNull + public Lookup getLookup() { + return myLookup; + } + + @Nullable + public PsiElement getOriginalPosition() { + return myOriginalFile.findElementAt(myPosition.getTextRange().getStartOffset()); + } + + @NotNull + public PsiFile getOriginalFile() { + return myOriginalFile; + } + + @NotNull + public CompletionType getCompletionType() { + return myCompletionType; + } + + public int getOffset() { + return myOffset; + } + + /** + * @return + * 0 for autopopup + * 1 for explicitly invoked completion + * >1 for next completion invocations when one lookup is already active + */ + public int getInvocationCount() { + return myInvocationCount; + } + + public boolean isAutoPopup() { + return myInvocationCount == 0; + } + + public CompletionParameters withPosition(PsiElement element, int offset) { + return new CompletionParameters(element, myOriginalFile, myCompletionType, offset, myInvocationCount, myLookup); + } + + public boolean isExtendedCompletion() { + return myCompletionType == CompletionType.BASIC && myInvocationCount >= 2; + } +} diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionType.java b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionType.java index 25a9021018c8..23818c37f580 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionType.java +++ b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionType.java @@ -1,15 +1,15 @@ -package com.intellij.codeInsight.completion; - -/** - * @author peter - */ -public enum CompletionType { - BASIC, - SMART, - - /** - * Only to be passed to {@link CompletionService#getVariantsFromContributors(CompletionParameters, CompletionContributor, com.intellij.util.Consumer)} - * to invoke special class-name providers for various file types where those class names are applicable (e.g. xml, txt, properties, custom) - */ - CLASS_NAME -} +package com.intellij.codeInsight.completion; + +/** + * @author peter + */ +public enum CompletionType { + BASIC, + SMART, + + /** + * Only to be passed to {@link CompletionService#getVariantsFromContributors(CompletionParameters, CompletionContributor, com.intellij.util.Consumer)} + * to invoke special class-name providers for various file types where those class names are applicable (e.g. xml, txt, properties, custom) + */ + CLASS_NAME +} diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/SkipAutopopupInStrings.java b/platform/lang-api/src/com/intellij/codeInsight/completion/SkipAutopopupInStrings.java index 7d8c5d7ea630..8f3714dbda93 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/completion/SkipAutopopupInStrings.java +++ b/platform/lang-api/src/com/intellij/codeInsight/completion/SkipAutopopupInStrings.java @@ -1,66 +1,66 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES 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.completion; - -import com.intellij.lang.LanguageParserDefinitions; -import com.intellij.lang.ParserDefinition; -import com.intellij.patterns.PlatformPatterns; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiErrorElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtilBase; -import com.intellij.util.ThreeState; -import org.jetbrains.annotations.NotNull; - -/** - * @author peter - */ -public class SkipAutopopupInStrings extends CompletionConfidence { - @NotNull - @Override - public ThreeState shouldFocusLookup(@NotNull CompletionParameters parameters) { - return ThreeState.UNSURE; - } - - @NotNull - @Override - public ThreeState shouldSkipAutopopup(@NotNull PsiElement contextElement, @NotNull PsiFile psiFile, int offset) { - if (isInStringLiteral(contextElement)) { - return ThreeState.YES; - } - - return ThreeState.UNSURE; - } - - public static boolean isInStringLiteral(PsiElement element) { - ParserDefinition definition = LanguageParserDefinitions.INSTANCE.forLanguage(PsiUtilBase.findLanguageFromElement(element)); - if (definition == null) { - return false; - } - - return isStringLiteral(element, definition) || isStringLiteral(element.getParent(), definition) || - isStringLiteralWithError(element, definition) || isStringLiteralWithError(element.getParent(), definition); - } - - private static boolean isStringLiteral(PsiElement element, ParserDefinition definition) { - return PlatformPatterns.psiElement().withElementType(definition.getStringLiteralElements()).accepts(element); - } - - private static boolean isStringLiteralWithError(PsiElement element, ParserDefinition definition) { - return isStringLiteral(element, definition) && PsiTreeUtil.nextLeaf(element) instanceof PsiErrorElement; - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.completion; + +import com.intellij.lang.LanguageParserDefinitions; +import com.intellij.lang.ParserDefinition; +import com.intellij.patterns.PlatformPatterns; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiErrorElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtilBase; +import com.intellij.util.ThreeState; +import org.jetbrains.annotations.NotNull; + +/** + * @author peter + */ +public class SkipAutopopupInStrings extends CompletionConfidence { + @NotNull + @Override + public ThreeState shouldFocusLookup(@NotNull CompletionParameters parameters) { + return ThreeState.UNSURE; + } + + @NotNull + @Override + public ThreeState shouldSkipAutopopup(@NotNull PsiElement contextElement, @NotNull PsiFile psiFile, int offset) { + if (isInStringLiteral(contextElement)) { + return ThreeState.YES; + } + + return ThreeState.UNSURE; + } + + public static boolean isInStringLiteral(PsiElement element) { + ParserDefinition definition = LanguageParserDefinitions.INSTANCE.forLanguage(PsiUtilBase.findLanguageFromElement(element)); + if (definition == null) { + return false; + } + + return isStringLiteral(element, definition) || isStringLiteral(element.getParent(), definition) || + isStringLiteralWithError(element, definition) || isStringLiteralWithError(element.getParent(), definition); + } + + private static boolean isStringLiteral(PsiElement element, ParserDefinition definition) { + return PlatformPatterns.psiElement().withElementType(definition.getStringLiteralElements()).accepts(element); + } + + private static boolean isStringLiteralWithError(PsiElement element, ParserDefinition definition) { + return isStringLiteral(element, definition) && PsiTreeUtil.nextLeaf(element) instanceof PsiErrorElement; + } +} diff --git a/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityIntentionActionWrapper.java b/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityIntentionActionWrapper.java index 3b4bce020894..4c6aa7cbb62d 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityIntentionActionWrapper.java +++ b/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityIntentionActionWrapper.java @@ -1,96 +1,96 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.intention.impl; - -import com.intellij.codeInsight.intention.HighPriorityAction; -import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.codeInsight.intention.LowPriorityAction; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiFile; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.NotNull; - -/** - * @author Danila Ponomarenko - */ -public abstract class PriorityIntentionActionWrapper implements IntentionAction { - private IntentionAction action; - - private PriorityIntentionActionWrapper(@NotNull IntentionAction action) { - this.action = action; - } - - @NotNull - @Override - public String getText() { - return action.getText(); - } - - @NotNull - @Override - public String getFamilyName() { - return action.getFamilyName(); - } - - @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return action.isAvailable(project, editor, file); - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - action.invoke(project, editor, file); - } - - @Override - public boolean startInWriteAction() { - return action.startInWriteAction(); - } - - private static class HighPriorityIntentionActionWrapper extends PriorityIntentionActionWrapper implements HighPriorityAction { - protected HighPriorityIntentionActionWrapper(@NotNull IntentionAction action) { - super(action); - } - } - - private static class NormalPriorityIntentionActionWrapper extends PriorityIntentionActionWrapper { - protected NormalPriorityIntentionActionWrapper(@NotNull IntentionAction action) { - super(action); - } - } - - private static class LowPriorityIntentionActionWrapper extends PriorityIntentionActionWrapper implements LowPriorityAction { - protected LowPriorityIntentionActionWrapper(@NotNull IntentionAction action) { - super(action); - } - } - - @NotNull - public static IntentionAction highPriority(@NotNull IntentionAction action) { - return new HighPriorityIntentionActionWrapper(action); - } - - @NotNull - public static IntentionAction normalPriority(@NotNull IntentionAction action) { - return new NormalPriorityIntentionActionWrapper(action); - } - - @NotNull - public static IntentionAction lowPriority(@NotNull IntentionAction action) { - return new LowPriorityIntentionActionWrapper(action); - } -} +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.intention.impl; + +import com.intellij.codeInsight.intention.HighPriorityAction; +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInsight.intention.LowPriorityAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; + +/** + * @author Danila Ponomarenko + */ +public abstract class PriorityIntentionActionWrapper implements IntentionAction { + private IntentionAction action; + + private PriorityIntentionActionWrapper(@NotNull IntentionAction action) { + this.action = action; + } + + @NotNull + @Override + public String getText() { + return action.getText(); + } + + @NotNull + @Override + public String getFamilyName() { + return action.getFamilyName(); + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + return action.isAvailable(project, editor, file); + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + action.invoke(project, editor, file); + } + + @Override + public boolean startInWriteAction() { + return action.startInWriteAction(); + } + + private static class HighPriorityIntentionActionWrapper extends PriorityIntentionActionWrapper implements HighPriorityAction { + protected HighPriorityIntentionActionWrapper(@NotNull IntentionAction action) { + super(action); + } + } + + private static class NormalPriorityIntentionActionWrapper extends PriorityIntentionActionWrapper { + protected NormalPriorityIntentionActionWrapper(@NotNull IntentionAction action) { + super(action); + } + } + + private static class LowPriorityIntentionActionWrapper extends PriorityIntentionActionWrapper implements LowPriorityAction { + protected LowPriorityIntentionActionWrapper(@NotNull IntentionAction action) { + super(action); + } + } + + @NotNull + public static IntentionAction highPriority(@NotNull IntentionAction action) { + return new HighPriorityIntentionActionWrapper(action); + } + + @NotNull + public static IntentionAction normalPriority(@NotNull IntentionAction action) { + return new NormalPriorityIntentionActionWrapper(action); + } + + @NotNull + public static IntentionAction lowPriority(@NotNull IntentionAction action) { + return new LowPriorityIntentionActionWrapper(action); + } +} diff --git a/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityLocalQuickFixWrapper.java b/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityLocalQuickFixWrapper.java index 895656f5e87c..e9f3d444e457 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityLocalQuickFixWrapper.java +++ b/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityLocalQuickFixWrapper.java @@ -1,85 +1,85 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.intention.impl; - -import com.intellij.codeInsight.intention.HighPriorityAction; -import com.intellij.codeInsight.intention.LowPriorityAction; -import com.intellij.codeInspection.LocalQuickFix; -import com.intellij.codeInspection.ProblemDescriptor; -import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NotNull; - -/** - * @author Danila Ponomarenko - */ -public abstract class PriorityLocalQuickFixWrapper implements LocalQuickFix { - private final LocalQuickFix fix; - - private PriorityLocalQuickFixWrapper(@NotNull LocalQuickFix fix) { - this.fix = fix; - } - - @NotNull - @Override - public String getName() { - return fix.getName(); - } - - @NotNull - @Override - public String getFamilyName() { - return fix.getFamilyName(); - } - - @Override - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - fix.applyFix(project, descriptor); - } - - private static class HighPriorityLocalQuickFixWrapper extends PriorityLocalQuickFixWrapper implements HighPriorityAction { - protected HighPriorityLocalQuickFixWrapper(@NotNull LocalQuickFix fix) { - super(fix); - } - } - - private static class NormalPriorityLocalQuickFixWrapper extends PriorityLocalQuickFixWrapper { - protected NormalPriorityLocalQuickFixWrapper(@NotNull LocalQuickFix fix) { - super(fix); - } - } - - - private static class LowPriorityLocalQuickFixWrapper extends PriorityLocalQuickFixWrapper implements LowPriorityAction { - protected LowPriorityLocalQuickFixWrapper(@NotNull LocalQuickFix fix) { - super(fix); - } - } - - @NotNull - public static LocalQuickFix highPriority(@NotNull LocalQuickFix fix) { - return new HighPriorityLocalQuickFixWrapper(fix); - } - - @NotNull - public static LocalQuickFix normalPriority(@NotNull LocalQuickFix fix) { - return new NormalPriorityLocalQuickFixWrapper(fix); - } - - @NotNull - public static LocalQuickFix lowPriority(@NotNull LocalQuickFix fix) { - return new LowPriorityLocalQuickFixWrapper(fix); - } -} +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.intention.impl; + +import com.intellij.codeInsight.intention.HighPriorityAction; +import com.intellij.codeInsight.intention.LowPriorityAction; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +/** + * @author Danila Ponomarenko + */ +public abstract class PriorityLocalQuickFixWrapper implements LocalQuickFix { + private final LocalQuickFix fix; + + private PriorityLocalQuickFixWrapper(@NotNull LocalQuickFix fix) { + this.fix = fix; + } + + @NotNull + @Override + public String getName() { + return fix.getName(); + } + + @NotNull + @Override + public String getFamilyName() { + return fix.getFamilyName(); + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + fix.applyFix(project, descriptor); + } + + private static class HighPriorityLocalQuickFixWrapper extends PriorityLocalQuickFixWrapper implements HighPriorityAction { + protected HighPriorityLocalQuickFixWrapper(@NotNull LocalQuickFix fix) { + super(fix); + } + } + + private static class NormalPriorityLocalQuickFixWrapper extends PriorityLocalQuickFixWrapper { + protected NormalPriorityLocalQuickFixWrapper(@NotNull LocalQuickFix fix) { + super(fix); + } + } + + + private static class LowPriorityLocalQuickFixWrapper extends PriorityLocalQuickFixWrapper implements LowPriorityAction { + protected LowPriorityLocalQuickFixWrapper(@NotNull LocalQuickFix fix) { + super(fix); + } + } + + @NotNull + public static LocalQuickFix highPriority(@NotNull LocalQuickFix fix) { + return new HighPriorityLocalQuickFixWrapper(fix); + } + + @NotNull + public static LocalQuickFix normalPriority(@NotNull LocalQuickFix fix) { + return new NormalPriorityLocalQuickFixWrapper(fix); + } + + @NotNull + public static LocalQuickFix lowPriority(@NotNull LocalQuickFix fix) { + return new LowPriorityLocalQuickFixWrapper(fix); + } +} diff --git a/platform/lang-api/src/com/intellij/codeInspection/QuickFix.java b/platform/lang-api/src/com/intellij/codeInspection/QuickFix.java index ec102251f097..be5c35281231 100644 --- a/platform/lang-api/src/com/intellij/codeInspection/QuickFix.java +++ b/platform/lang-api/src/com/intellij/codeInspection/QuickFix.java @@ -1,52 +1,52 @@ -/* - * 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.codeInspection; - -import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NotNull; - -/** - * Common base interface for quick fixes provided by local and global inspections. - * - * @author anna - * @since 6.0 - * @see CommonProblemDescriptor#getFixes() - */ -public interface QuickFix { - QuickFix[] EMPTY_ARRAY = new QuickFix[0]; - /** - * Returns the name of the quick fix. - * - * @return the name of the quick fix. - */ - @NotNull - String getName(); - - /** - * @return text to appear in "Apply Fix" popup when multiple Quick Fixes exist (in the results of batch code inspection). For example, - * if the name of the quickfix is "Create template <filename>", the return value of getFamilyName() should be "Create template". - * If the name of the quickfix does not depend on a specific element, simply return getName(). - */ - @NotNull String getFamilyName(); - - /** - * Called to apply the fix. - * - * @param project {@link com.intellij.openapi.project.Project} - * @param descriptor problem reported by the tool which provided this quick fix action - */ - void applyFix(@NotNull Project project, @NotNull D descriptor); -} +/* + * 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.codeInspection; + +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +/** + * Common base interface for quick fixes provided by local and global inspections. + * + * @author anna + * @since 6.0 + * @see CommonProblemDescriptor#getFixes() + */ +public interface QuickFix { + QuickFix[] EMPTY_ARRAY = new QuickFix[0]; + /** + * Returns the name of the quick fix. + * + * @return the name of the quick fix. + */ + @NotNull + String getName(); + + /** + * @return text to appear in "Apply Fix" popup when multiple Quick Fixes exist (in the results of batch code inspection). For example, + * if the name of the quickfix is "Create template <filename>", the return value of getFamilyName() should be "Create template". + * If the name of the quickfix does not depend on a specific element, simply return getName(). + */ + @NotNull String getFamilyName(); + + /** + * Called to apply the fix. + * + * @param project {@link com.intellij.openapi.project.Project} + * @param descriptor problem reported by the tool which provided this quick fix action + */ + void applyFix(@NotNull Project project, @NotNull D descriptor); +} diff --git a/platform/lang-api/src/com/intellij/execution/BeforeRunTaskProvider.java b/platform/lang-api/src/com/intellij/execution/BeforeRunTaskProvider.java index d9b505f0f599..b4c84a65d3d5 100644 --- a/platform/lang-api/src/com/intellij/execution/BeforeRunTaskProvider.java +++ b/platform/lang-api/src/com/intellij/execution/BeforeRunTaskProvider.java @@ -1,92 +1,92 @@ -/* - * 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. - */ - -/* - * Created by IntelliJ IDEA. - * User: Vladislav.Kaznacheev - * Date: Jul 4, 2007 - * Time: 12:33:18 AM - */ -package com.intellij.execution; - -import com.intellij.execution.configurations.RunConfiguration; -import com.intellij.execution.runners.ExecutionEnvironment; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; - -public abstract class BeforeRunTaskProvider { - public static final ExtensionPointName> EXTENSION_POINT_NAME = new ExtensionPointName>("com.intellij.stepsBeforeRunProvider"); - - public static final String RUNNER_ID = "RunnerId"; - - public abstract Key getId(); - - public abstract String getName(); - - @Nullable - public Icon getIcon() { - return null; - } - - public abstract String getDescription(T task); - - - @Nullable - public Icon getTaskIcon(T task) { - return null; - } - - public abstract boolean isConfigurable(); - - /** - * @return 'before run' task for the configuration or null, if the task from this provider is not applicable to the specified configuration - */ - @Nullable - public abstract T createTask(final RunConfiguration runConfiguration); - - /** - * @return true if task configuration is changed - */ - public abstract boolean configureTask(final RunConfiguration runConfiguration, T task); - - public abstract boolean canExecuteTask(RunConfiguration configuration, T task); - - public abstract boolean executeTask(DataContext context, RunConfiguration configuration, ExecutionEnvironment env, T task); - - /** - * - * @return true if at most one task may be configured - */ - public boolean isSingleton() { - return false; - } - - @Nullable - public static BeforeRunTaskProvider getProvider(Project project, Key key) { - BeforeRunTaskProvider[] providers = Extensions.getExtensions(BeforeRunTaskProvider.EXTENSION_POINT_NAME, project); - for (BeforeRunTaskProvider provider : providers) { - if (provider.getId() == key) - return (BeforeRunTaskProvider)provider; - } - return null; - } +/* + * 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. + */ + +/* + * Created by IntelliJ IDEA. + * User: Vladislav.Kaznacheev + * Date: Jul 4, 2007 + * Time: 12:33:18 AM + */ +package com.intellij.execution; + +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Key; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +public abstract class BeforeRunTaskProvider { + public static final ExtensionPointName> EXTENSION_POINT_NAME = new ExtensionPointName>("com.intellij.stepsBeforeRunProvider"); + + public static final String RUNNER_ID = "RunnerId"; + + public abstract Key getId(); + + public abstract String getName(); + + @Nullable + public Icon getIcon() { + return null; + } + + public abstract String getDescription(T task); + + + @Nullable + public Icon getTaskIcon(T task) { + return null; + } + + public abstract boolean isConfigurable(); + + /** + * @return 'before run' task for the configuration or null, if the task from this provider is not applicable to the specified configuration + */ + @Nullable + public abstract T createTask(final RunConfiguration runConfiguration); + + /** + * @return true if task configuration is changed + */ + public abstract boolean configureTask(final RunConfiguration runConfiguration, T task); + + public abstract boolean canExecuteTask(RunConfiguration configuration, T task); + + public abstract boolean executeTask(DataContext context, RunConfiguration configuration, ExecutionEnvironment env, T task); + + /** + * + * @return true if at most one task may be configured + */ + public boolean isSingleton() { + return false; + } + + @Nullable + public static BeforeRunTaskProvider getProvider(Project project, Key key) { + BeforeRunTaskProvider[] providers = Extensions.getExtensions(BeforeRunTaskProvider.EXTENSION_POINT_NAME, project); + for (BeforeRunTaskProvider provider : providers) { + if (provider.getId() == key) + return (BeforeRunTaskProvider)provider; + } + return null; + } } \ No newline at end of file diff --git a/platform/lang-api/src/com/intellij/execution/DefaultExecutionTarget.java b/platform/lang-api/src/com/intellij/execution/DefaultExecutionTarget.java index f3b31a346cdb..4976c0e91076 100644 --- a/platform/lang-api/src/com/intellij/execution/DefaultExecutionTarget.java +++ b/platform/lang-api/src/com/intellij/execution/DefaultExecutionTarget.java @@ -1,48 +1,48 @@ -/* - * 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.execution; - -import com.intellij.ide.IdeBundle; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; - -public class DefaultExecutionTarget extends ExecutionTarget { - public static final ExecutionTarget INSTANCE = new DefaultExecutionTarget(); - - - @NotNull - @Override - public String getId() { - return "default_target"; - } - - @NotNull - @Override - public String getDisplayName() { - return IdeBundle.message("node.default"); - } - - @Override - public Icon getIcon() { - return null; - } - - @Override - public boolean canRun(@NotNull RunnerAndConfigurationSettings configuration) { - return true; - } -} +/* + * 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.execution; + +import com.intellij.ide.IdeBundle; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +public class DefaultExecutionTarget extends ExecutionTarget { + public static final ExecutionTarget INSTANCE = new DefaultExecutionTarget(); + + + @NotNull + @Override + public String getId() { + return "default_target"; + } + + @NotNull + @Override + public String getDisplayName() { + return IdeBundle.message("node.default"); + } + + @Override + public Icon getIcon() { + return null; + } + + @Override + public boolean canRun(@NotNull RunnerAndConfigurationSettings configuration) { + return true; + } +} diff --git a/platform/lang-api/src/com/intellij/execution/ExecutionTarget.java b/platform/lang-api/src/com/intellij/execution/ExecutionTarget.java index b9855dbaa4c7..a0697d2cdfb1 100644 --- a/platform/lang-api/src/com/intellij/execution/ExecutionTarget.java +++ b/platform/lang-api/src/com/intellij/execution/ExecutionTarget.java @@ -1,50 +1,50 @@ -/* - * 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.execution; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; - -public abstract class ExecutionTarget { - @NotNull - public abstract String getId(); - - @NotNull - public abstract String getDisplayName(); - - @Nullable - public abstract Icon getIcon(); - - public abstract boolean canRun(@NotNull RunnerAndConfigurationSettings configuration); - - @Override - public boolean equals(Object obj) { - return obj == this || (getClass().isInstance(obj) && getId().equals(((ExecutionTarget)obj).getId())); - } - - @Override - public int hashCode() { - return getId().hashCode(); - } - - @Override - public String toString() { - return getId(); - } -} +/* + * 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.execution; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +public abstract class ExecutionTarget { + @NotNull + public abstract String getId(); + + @NotNull + public abstract String getDisplayName(); + + @Nullable + public abstract Icon getIcon(); + + public abstract boolean canRun(@NotNull RunnerAndConfigurationSettings configuration); + + @Override + public boolean equals(Object obj) { + return obj == this || (getClass().isInstance(obj) && getId().equals(((ExecutionTarget)obj).getId())); + } + + @Override + public int hashCode() { + return getId().hashCode(); + } + + @Override + public String toString() { + return getId(); + } +} diff --git a/platform/lang-api/src/com/intellij/execution/ExecutionTargetListener.java b/platform/lang-api/src/com/intellij/execution/ExecutionTargetListener.java index 757471cb2fe5..1362fe89a78e 100644 --- a/platform/lang-api/src/com/intellij/execution/ExecutionTargetListener.java +++ b/platform/lang-api/src/com/intellij/execution/ExecutionTargetListener.java @@ -1,22 +1,22 @@ -/* - * 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.execution; - -import org.jetbrains.annotations.NotNull; - -public interface ExecutionTargetListener { - void activeTargetChanged(@NotNull ExecutionTarget newTarget); -} +/* + * 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.execution; + +import org.jetbrains.annotations.NotNull; + +public interface ExecutionTargetListener { + void activeTargetChanged(@NotNull ExecutionTarget newTarget); +} diff --git a/platform/lang-api/src/com/intellij/execution/ExecutionTargetManager.java b/platform/lang-api/src/com/intellij/execution/ExecutionTargetManager.java index d19b79374cfb..b48a2e8919fb 100644 --- a/platform/lang-api/src/com/intellij/execution/ExecutionTargetManager.java +++ b/platform/lang-api/src/com/intellij/execution/ExecutionTargetManager.java @@ -1,73 +1,73 @@ -/* - * 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.execution; - -import com.intellij.openapi.project.Project; -import com.intellij.util.messages.Topic; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collections; -import java.util.List; - -public abstract class ExecutionTargetManager { - public static final Topic TOPIC = Topic.create("ExecutionTarget topic", ExecutionTargetListener.class); - - - @NotNull - public static ExecutionTargetManager getInstance(@NotNull Project project) { - return project.getComponent(ExecutionTargetManager.class); - } - - @NotNull - public static ExecutionTarget getActiveTarget(@NotNull Project project) { - return getInstance(project).getActiveTarget(); - } - - public static void setActiveTarget(@NotNull Project project, @NotNull ExecutionTarget target) { - getInstance(project).setActiveTarget(target); - } - - @NotNull - public static List getTargetsFor(@NotNull Project project, @Nullable RunnerAndConfigurationSettings settings) { - return getInstance(project).getTargetsFor(settings); - } - - @NotNull - public static List getTargetsToChooseFor(@NotNull Project project, @Nullable RunnerAndConfigurationSettings settings) { - List result = getInstance(project).getTargetsFor(settings); - if (result.size() == 1 && DefaultExecutionTarget.INSTANCE.equals(result.get(0))) return Collections.emptyList(); - return result; - } - - public static boolean canRun(@Nullable RunnerAndConfigurationSettings settings, @Nullable ExecutionTarget target) { - return settings != null && target != null && settings.canRunOn(target) && target.canRun(settings); - } - - public static void update(@NotNull Project project) { - getInstance(project).update(); - } - - @NotNull - public abstract ExecutionTarget getActiveTarget(); - - public abstract void setActiveTarget(@NotNull ExecutionTarget target); - - @NotNull - public abstract List getTargetsFor(@Nullable RunnerAndConfigurationSettings settings); - - public abstract void update(); -} +/* + * 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.execution; + +import com.intellij.openapi.project.Project; +import com.intellij.util.messages.Topic; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.List; + +public abstract class ExecutionTargetManager { + public static final Topic TOPIC = Topic.create("ExecutionTarget topic", ExecutionTargetListener.class); + + + @NotNull + public static ExecutionTargetManager getInstance(@NotNull Project project) { + return project.getComponent(ExecutionTargetManager.class); + } + + @NotNull + public static ExecutionTarget getActiveTarget(@NotNull Project project) { + return getInstance(project).getActiveTarget(); + } + + public static void setActiveTarget(@NotNull Project project, @NotNull ExecutionTarget target) { + getInstance(project).setActiveTarget(target); + } + + @NotNull + public static List getTargetsFor(@NotNull Project project, @Nullable RunnerAndConfigurationSettings settings) { + return getInstance(project).getTargetsFor(settings); + } + + @NotNull + public static List getTargetsToChooseFor(@NotNull Project project, @Nullable RunnerAndConfigurationSettings settings) { + List result = getInstance(project).getTargetsFor(settings); + if (result.size() == 1 && DefaultExecutionTarget.INSTANCE.equals(result.get(0))) return Collections.emptyList(); + return result; + } + + public static boolean canRun(@Nullable RunnerAndConfigurationSettings settings, @Nullable ExecutionTarget target) { + return settings != null && target != null && settings.canRunOn(target) && target.canRun(settings); + } + + public static void update(@NotNull Project project) { + getInstance(project).update(); + } + + @NotNull + public abstract ExecutionTarget getActiveTarget(); + + public abstract void setActiveTarget(@NotNull ExecutionTarget target); + + @NotNull + public abstract List getTargetsFor(@Nullable RunnerAndConfigurationSettings settings); + + public abstract void update(); +} diff --git a/platform/lang-api/src/com/intellij/execution/ExecutionTargetProvider.java b/platform/lang-api/src/com/intellij/execution/ExecutionTargetProvider.java index 02d8bb7abfaf..6b3c865a90ae 100644 --- a/platform/lang-api/src/com/intellij/execution/ExecutionTargetProvider.java +++ b/platform/lang-api/src/com/intellij/execution/ExecutionTargetProvider.java @@ -1,31 +1,31 @@ -/* - * 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.execution; - -import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -public abstract class ExecutionTargetProvider { - public static final ExtensionPointName EXTENSION_NAME = - ExtensionPointName.create("com.intellij.executionTargetProvider"); - - @NotNull - public abstract List getTargets(@NotNull Project project, @NotNull RunnerAndConfigurationSettings configuration); -} +/* + * 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.execution; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public abstract class ExecutionTargetProvider { + public static final ExtensionPointName EXTENSION_NAME = + ExtensionPointName.create("com.intellij.executionTargetProvider"); + + @NotNull + public abstract List getTargets(@NotNull Project project, @NotNull RunnerAndConfigurationSettings configuration); +} diff --git a/platform/lang-api/src/com/intellij/execution/RunnerAndConfigurationSettings.java b/platform/lang-api/src/com/intellij/execution/RunnerAndConfigurationSettings.java index 485f7f4e3a64..07cd2441fef4 100644 --- a/platform/lang-api/src/com/intellij/execution/RunnerAndConfigurationSettings.java +++ b/platform/lang-api/src/com/intellij/execution/RunnerAndConfigurationSettings.java @@ -1,72 +1,72 @@ -/* - * 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.execution; - -import com.intellij.execution.configurations.*; -import com.intellij.execution.runners.ProgramRunner; -import com.intellij.openapi.util.Factory; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * User: anna - * Date: Jan 25, 2005 - */ -public interface RunnerAndConfigurationSettings { - @Nullable - ConfigurationFactory getFactory(); - - boolean isTemplate(); - - boolean isTemporary(); - - RunConfiguration getConfiguration(); - - void setName(String name); - - String getName(); - - @NotNull - RunnerSettings getRunnerSettings(@NotNull ProgramRunner runner); - - @NotNull - ConfigurationPerRunnerSettings getConfigurationSettings(@NotNull ProgramRunner runner); - - @Nullable - ConfigurationType getType(); - - void checkSettings() throws RuntimeConfigurationException; - - void checkSettings(@Nullable Executor executor) throws RuntimeConfigurationException; - - boolean canRunOn(@NotNull ExecutionTarget target); - - void setTemporary(boolean temporary); - - Factory createFactory(); - - void setEditBeforeRun(boolean b); - - boolean isEditBeforeRun(); - - void setSingleton(boolean singleton); - - boolean isSingleton(); - - void setFolderName(@Nullable String folderName); - - @Nullable String getFolderName(); -} +/* + * 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.execution; + +import com.intellij.execution.configurations.*; +import com.intellij.execution.runners.ProgramRunner; +import com.intellij.openapi.util.Factory; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * User: anna + * Date: Jan 25, 2005 + */ +public interface RunnerAndConfigurationSettings { + @Nullable + ConfigurationFactory getFactory(); + + boolean isTemplate(); + + boolean isTemporary(); + + RunConfiguration getConfiguration(); + + void setName(String name); + + String getName(); + + @NotNull + RunnerSettings getRunnerSettings(@NotNull ProgramRunner runner); + + @NotNull + ConfigurationPerRunnerSettings getConfigurationSettings(@NotNull ProgramRunner runner); + + @Nullable + ConfigurationType getType(); + + void checkSettings() throws RuntimeConfigurationException; + + void checkSettings(@Nullable Executor executor) throws RuntimeConfigurationException; + + boolean canRunOn(@NotNull ExecutionTarget target); + + void setTemporary(boolean temporary); + + Factory createFactory(); + + void setEditBeforeRun(boolean b); + + boolean isEditBeforeRun(); + + void setSingleton(boolean singleton); + + boolean isSingleton(); + + void setFolderName(@Nullable String folderName); + + @Nullable String getFolderName(); +} diff --git a/platform/lang-api/src/com/intellij/execution/configurations/CommandLineState.java b/platform/lang-api/src/com/intellij/execution/configurations/CommandLineState.java index c242e6f8e3e9..49fe0cecfd7e 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/CommandLineState.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/CommandLineState.java @@ -1,152 +1,152 @@ -/* - * 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.execution.configurations; - -import com.intellij.execution.*; -import com.intellij.execution.executors.DefaultRunExecutor; -import com.intellij.execution.filters.TextConsoleBuilder; -import com.intellij.execution.process.ProcessHandler; -import com.intellij.execution.runners.ExecutionEnvironment; -import com.intellij.execution.runners.ProgramRunner; -import com.intellij.execution.ui.ConsoleView; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.actionSystem.ToggleAction; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.DumbAware; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public abstract class CommandLineState implements RunnableState { - private static final Logger LOG = Logger.getInstance("#com.intellij.execution.configurations.CommandLineState"); - private TextConsoleBuilder myConsoleBuilder; - - private final ExecutionEnvironment myEnvironment; - - protected CommandLineState(ExecutionEnvironment environment) { - myEnvironment = environment; - } - - public ExecutionEnvironment getEnvironment() { - return myEnvironment; - } - - public RunnerSettings getRunnerSettings() { - return myEnvironment.getRunnerSettings(); - } - - public ConfigurationPerRunnerSettings getConfigurationSettings() { - return myEnvironment.getConfigurationSettings(); - } - - @NotNull - public ExecutionTarget getExecutionTarget() { - return myEnvironment.getExecutionTarget(); - } - - @NotNull - public ExecutionResult execute(@NotNull final Executor executor, @NotNull final ProgramRunner runner) throws ExecutionException { - final ProcessHandler processHandler = startProcess(); - final ConsoleView console = createConsole(executor); - if (console != null) { - console.attachToProcess(processHandler); - } - return new DefaultExecutionResult(console, processHandler, createActions(console, processHandler, executor)); - } - - @Nullable - protected ConsoleView createConsole(@NotNull final Executor executor) throws ExecutionException { - final TextConsoleBuilder builder = getConsoleBuilder(); - - return builder != null ? builder.getConsole() - : null; - } - - @NotNull - protected abstract ProcessHandler startProcess() throws ExecutionException; - - protected AnAction[] createActions(final ConsoleView console, final ProcessHandler processHandler) { - return createActions(console, processHandler, null); - } - - protected AnAction[] createActions(final ConsoleView console, final ProcessHandler processHandler, Executor executor) { - if (console == null || !console.canPause() || (executor != null && !DefaultRunExecutor.EXECUTOR_ID.equals(executor.getId()))) { - return new AnAction[0]; - } - return new AnAction[]{new PauseOutputAction(console, processHandler)}; - } - - public TextConsoleBuilder getConsoleBuilder() { - return myConsoleBuilder; - } - - public void setConsoleBuilder(final TextConsoleBuilder consoleBuilder) { - myConsoleBuilder = consoleBuilder; - } - - protected static class PauseOutputAction extends ToggleAction implements DumbAware{ - private final ConsoleView myConsole; - private final ProcessHandler myProcessHandler; - - public PauseOutputAction(final ConsoleView console, final ProcessHandler processHandler) { - super(ExecutionBundle.message("run.configuration.pause.output.action.name"), null, AllIcons.Actions.Pause); - myConsole = console; - myProcessHandler = processHandler; - } - - public boolean isSelected(final AnActionEvent event) { - return myConsole.isOutputPaused(); - } - - public void setSelected(final AnActionEvent event, final boolean flag) { - myConsole.setOutputPaused(flag); - ApplicationManager.getApplication().invokeLater(new Runnable() { - public void run() { - update(event); - } - }); - } - - public void update(final AnActionEvent event) { - super.update(event); - final Presentation presentation = event.getPresentation(); - final boolean isRunning = myProcessHandler != null && !myProcessHandler.isProcessTerminated(); - if (isRunning) { - presentation.setEnabled(true); - } - else { - if (!myConsole.canPause()) { - presentation.setEnabled(false); - return; - } - if (!myConsole.hasDeferredOutput()) { - presentation.setEnabled(false); - } - else { - presentation.setEnabled(true); - myConsole.performWhenNoDeferredOutput(new Runnable() { - public void run() { - update(event); - } - }); - } - } - } - } -} +/* + * 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.execution.configurations; + +import com.intellij.execution.*; +import com.intellij.execution.executors.DefaultRunExecutor; +import com.intellij.execution.filters.TextConsoleBuilder; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.runners.ProgramRunner; +import com.intellij.execution.ui.ConsoleView; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.actionSystem.ToggleAction; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.DumbAware; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class CommandLineState implements RunnableState { + private static final Logger LOG = Logger.getInstance("#com.intellij.execution.configurations.CommandLineState"); + private TextConsoleBuilder myConsoleBuilder; + + private final ExecutionEnvironment myEnvironment; + + protected CommandLineState(ExecutionEnvironment environment) { + myEnvironment = environment; + } + + public ExecutionEnvironment getEnvironment() { + return myEnvironment; + } + + public RunnerSettings getRunnerSettings() { + return myEnvironment.getRunnerSettings(); + } + + public ConfigurationPerRunnerSettings getConfigurationSettings() { + return myEnvironment.getConfigurationSettings(); + } + + @NotNull + public ExecutionTarget getExecutionTarget() { + return myEnvironment.getExecutionTarget(); + } + + @NotNull + public ExecutionResult execute(@NotNull final Executor executor, @NotNull final ProgramRunner runner) throws ExecutionException { + final ProcessHandler processHandler = startProcess(); + final ConsoleView console = createConsole(executor); + if (console != null) { + console.attachToProcess(processHandler); + } + return new DefaultExecutionResult(console, processHandler, createActions(console, processHandler, executor)); + } + + @Nullable + protected ConsoleView createConsole(@NotNull final Executor executor) throws ExecutionException { + final TextConsoleBuilder builder = getConsoleBuilder(); + + return builder != null ? builder.getConsole() + : null; + } + + @NotNull + protected abstract ProcessHandler startProcess() throws ExecutionException; + + protected AnAction[] createActions(final ConsoleView console, final ProcessHandler processHandler) { + return createActions(console, processHandler, null); + } + + protected AnAction[] createActions(final ConsoleView console, final ProcessHandler processHandler, Executor executor) { + if (console == null || !console.canPause() || (executor != null && !DefaultRunExecutor.EXECUTOR_ID.equals(executor.getId()))) { + return new AnAction[0]; + } + return new AnAction[]{new PauseOutputAction(console, processHandler)}; + } + + public TextConsoleBuilder getConsoleBuilder() { + return myConsoleBuilder; + } + + public void setConsoleBuilder(final TextConsoleBuilder consoleBuilder) { + myConsoleBuilder = consoleBuilder; + } + + protected static class PauseOutputAction extends ToggleAction implements DumbAware{ + private final ConsoleView myConsole; + private final ProcessHandler myProcessHandler; + + public PauseOutputAction(final ConsoleView console, final ProcessHandler processHandler) { + super(ExecutionBundle.message("run.configuration.pause.output.action.name"), null, AllIcons.Actions.Pause); + myConsole = console; + myProcessHandler = processHandler; + } + + public boolean isSelected(final AnActionEvent event) { + return myConsole.isOutputPaused(); + } + + public void setSelected(final AnActionEvent event, final boolean flag) { + myConsole.setOutputPaused(flag); + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + update(event); + } + }); + } + + public void update(final AnActionEvent event) { + super.update(event); + final Presentation presentation = event.getPresentation(); + final boolean isRunning = myProcessHandler != null && !myProcessHandler.isProcessTerminated(); + if (isRunning) { + presentation.setEnabled(true); + } + else { + if (!myConsole.canPause()) { + presentation.setEnabled(false); + return; + } + if (!myConsole.hasDeferredOutput()) { + presentation.setEnabled(false); + } + else { + presentation.setEnabled(true); + myConsole.performWhenNoDeferredOutput(new Runnable() { + public void run() { + update(event); + } + }); + } + } + } + } +} 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 9fc3bc46a051..d891f0cde965 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java @@ -1,274 +1,274 @@ -/* - * 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.execution.configurations; - -import com.intellij.diagnostic.logging.LogConsole; -import com.intellij.execution.ExecutionTarget; -import com.intellij.execution.process.ProcessHandler; -import com.intellij.execution.runners.ProgramRunner; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.InvalidDataException; -import com.intellij.openapi.util.UserDataHolderBase; -import com.intellij.openapi.util.WriteExternalException; -import org.jdom.Element; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.util.ArrayList; -import java.util.List; - -/** - * @author dyoma - */ -public abstract class RunConfigurationBase extends UserDataHolderBase implements RunConfiguration, TargetAwareRunProfile { - private final ConfigurationFactory myFactory; - private final Project myProject; - private String myName = ""; - - private ArrayList myLogFiles = new ArrayList(); - private ArrayList myPredefinedLogFiles = new ArrayList(); - - @NonNls private static final String LOG_FILE = "log_file"; - @NonNls private static final String PREDEFINED_LOG_FILE_ELEMENT = "predefined_log_file"; - @NonNls private static final String FILE_OUTPUT = "output_file"; - @NonNls private static final String SAVE = "is_save"; - @NonNls private static final String OUTPUT_FILE = "path"; - @NonNls private static final String SHOW_CONSOLE_ON_STD_OUT = "show_console_on_std_out"; - @NonNls private static final String SHOW_CONSOLE_ON_STD_ERR = "show_console_on_std_err"; - - private final Icon myIcon; - private boolean mySaveOutput = false; - private boolean myShowConsoleOnStdOut = false; - private boolean myShowConsoleOnStdErr = false; - private String myFileOutputPath = null; - - protected RunConfigurationBase(final Project project, final ConfigurationFactory factory, final String name) { - myProject = project; - myFactory = factory; - myName = name; - myIcon = factory.getIcon(); - } - - public int getUniqueID() { - return System.identityHashCode(this); - } - - public final ConfigurationFactory getFactory() { - return myFactory; - } - - public final void setName(final String name) { - myName = name; - } - - public final Project getProject() { - return myProject; - } - - @NotNull - public ConfigurationType getType() { - return myFactory.getType(); - } - - public Icon getIcon() { - return myIcon; - } - - public final String getName() { - return myName; - } - - public final int hashCode() { - return super.hashCode(); - } - - public void checkRunnerSettings(@NotNull ProgramRunner runner, @Nullable RunnerSettings runnerSettings, - @Nullable ConfigurationPerRunnerSettings configurationPerRunnerSettings) throws RuntimeConfigurationException { - } - - public void checkSettingsBeforeRun() throws RuntimeConfigurationException { - } - - public boolean canRunOn(@NotNull ExecutionTarget target) { - return true; - } - - public final boolean equals(final Object obj) { - return super.equals(obj); - } - - public RunConfiguration clone() { - final RunConfigurationBase runConfiguration = (RunConfigurationBase)super.clone(); - runConfiguration.myLogFiles = new ArrayList(myLogFiles); - runConfiguration.myPredefinedLogFiles = new ArrayList(myPredefinedLogFiles); - runConfiguration.myFileOutputPath = myFileOutputPath; - runConfiguration.mySaveOutput = mySaveOutput; - runConfiguration.myShowConsoleOnStdOut = myShowConsoleOnStdOut; - runConfiguration.myShowConsoleOnStdErr = myShowConsoleOnStdErr; - copyCopyableDataTo(runConfiguration); - return runConfiguration; - } - - @Nullable - public LogFileOptions getOptionsForPredefinedLogFile(PredefinedLogFile predefinedLogFile) { - return null; - } - - public void removeAllPredefinedLogFiles() { - myPredefinedLogFiles.clear(); - } - - public void addPredefinedLogFile(PredefinedLogFile predefinedLogFile) { - myPredefinedLogFiles.add(predefinedLogFile); - } - - public ArrayList getPredefinedLogFiles() { - return myPredefinedLogFiles; - } - - public ArrayList getAllLogFiles() { - final ArrayList list = new ArrayList(myLogFiles); - for (PredefinedLogFile predefinedLogFile : myPredefinedLogFiles) { - final LogFileOptions options = getOptionsForPredefinedLogFile(predefinedLogFile); - if (options != null) { - list.add(options); - } - } - return list; - } - - public ArrayList getLogFiles() { - return myLogFiles; - } - - public void addLogFile(String file, String alias, boolean checked){ - myLogFiles.add(new LogFileOptions(alias, file, checked, true, false)); - } - - public void addLogFile(String file, String alias, boolean checked, boolean skipContent, final boolean showAll){ - myLogFiles.add(new LogFileOptions(alias, file, checked, skipContent, showAll)); - } - - public void removeAllLogFiles() { - myLogFiles.clear(); - } - - //invoke before run/debug tabs are shown. - //Should be overriden to add additional tabs for run/debug toolwindow - public void createAdditionalTabComponents(AdditionalTabComponentManager manager, ProcessHandler startedProcess) { - } - - public void customizeLogConsole(LogConsole console) { - } - - public void readExternal(Element element) throws InvalidDataException { - myLogFiles.clear(); - for (final Object o : element.getChildren(LOG_FILE)) { - LogFileOptions logFileOptions = new LogFileOptions(); - logFileOptions.readExternal((Element)o); - myLogFiles.add(logFileOptions); - } - myPredefinedLogFiles.clear(); - final List list = element.getChildren(PREDEFINED_LOG_FILE_ELEMENT); - for (Object fileElement : list) { - final PredefinedLogFile logFile = new PredefinedLogFile(); - logFile.readExternal((Element)fileElement); - myPredefinedLogFiles.add(logFile); - } - final Element fileOutputElement = element.getChild(FILE_OUTPUT); - if (fileOutputElement != null) { - myFileOutputPath = fileOutputElement.getAttributeValue(OUTPUT_FILE); - final String isSave = fileOutputElement.getAttributeValue(SAVE); - mySaveOutput = isSave != null && Boolean.parseBoolean(isSave); - } - myShowConsoleOnStdOut = Boolean.parseBoolean(element.getAttributeValue(SHOW_CONSOLE_ON_STD_OUT)); - myShowConsoleOnStdErr = Boolean.parseBoolean(element.getAttributeValue(SHOW_CONSOLE_ON_STD_ERR)); - } - - public void writeExternal(Element element) throws WriteExternalException { - for (final LogFileOptions options : myLogFiles) { - Element logFile = new Element(LOG_FILE); - options.writeExternal(logFile); - element.addContent(logFile); - } - for (PredefinedLogFile predefinedLogFile : myPredefinedLogFiles) { - Element fileElement = new Element(PREDEFINED_LOG_FILE_ELEMENT); - predefinedLogFile.writeExternal(fileElement); - element.addContent(fileElement); - } - final Element fileOutputPathElement = new Element(FILE_OUTPUT); - if (myFileOutputPath != null) { - fileOutputPathElement.setAttribute(OUTPUT_FILE, myFileOutputPath); - } - fileOutputPathElement.setAttribute(SAVE, String.valueOf(mySaveOutput)); - if (myFileOutputPath != null || mySaveOutput) { - element.addContent(fileOutputPathElement); - } - if (myShowConsoleOnStdOut) {//default value shouldn't be written - element.setAttribute(SHOW_CONSOLE_ON_STD_OUT, String.valueOf(myShowConsoleOnStdOut)); - } - if (myShowConsoleOnStdErr) {//default value shouldn't be written - element.setAttribute(SHOW_CONSOLE_ON_STD_ERR, String.valueOf(myShowConsoleOnStdErr)); - } - } - - public boolean isSaveOutputToFile() { - return mySaveOutput; - } - - public void setSaveOutputToFile(boolean redirectOutput) { - mySaveOutput = redirectOutput; - } - - public boolean isShowConsoleOnStdOut() { - return myShowConsoleOnStdOut; - } - - public void setShowConsoleOnStdOut(boolean showConsoleOnStdOut) { - myShowConsoleOnStdOut = showConsoleOnStdOut; - } - - public boolean isShowConsoleOnStdErr() { - return myShowConsoleOnStdErr; - } - - public void setShowConsoleOnStdErr(boolean showConsoleOnStdErr) { - myShowConsoleOnStdErr = showConsoleOnStdErr; - } - - public String getOutputFilePath() { - return myFileOutputPath; - } - - public void setFileOutputPath(String fileOutputPath) { - myFileOutputPath = fileOutputPath; - } - - public boolean collectOutputFromProcessHandler() { - return true; - } - - public boolean excludeCompileBeforeLaunchOption() { - return false; - } - - @Override - public String toString() { - return getType().getDisplayName() + ": " + getName(); - } -} +/* + * 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.execution.configurations; + +import com.intellij.diagnostic.logging.LogConsole; +import com.intellij.execution.ExecutionTarget; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.runners.ProgramRunner; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.UserDataHolderBase; +import com.intellij.openapi.util.WriteExternalException; +import org.jdom.Element; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author dyoma + */ +public abstract class RunConfigurationBase extends UserDataHolderBase implements RunConfiguration, TargetAwareRunProfile { + private final ConfigurationFactory myFactory; + private final Project myProject; + private String myName = ""; + + private ArrayList myLogFiles = new ArrayList(); + private ArrayList myPredefinedLogFiles = new ArrayList(); + + @NonNls private static final String LOG_FILE = "log_file"; + @NonNls private static final String PREDEFINED_LOG_FILE_ELEMENT = "predefined_log_file"; + @NonNls private static final String FILE_OUTPUT = "output_file"; + @NonNls private static final String SAVE = "is_save"; + @NonNls private static final String OUTPUT_FILE = "path"; + @NonNls private static final String SHOW_CONSOLE_ON_STD_OUT = "show_console_on_std_out"; + @NonNls private static final String SHOW_CONSOLE_ON_STD_ERR = "show_console_on_std_err"; + + private final Icon myIcon; + private boolean mySaveOutput = false; + private boolean myShowConsoleOnStdOut = false; + private boolean myShowConsoleOnStdErr = false; + private String myFileOutputPath = null; + + protected RunConfigurationBase(final Project project, final ConfigurationFactory factory, final String name) { + myProject = project; + myFactory = factory; + myName = name; + myIcon = factory.getIcon(); + } + + public int getUniqueID() { + return System.identityHashCode(this); + } + + public final ConfigurationFactory getFactory() { + return myFactory; + } + + public final void setName(final String name) { + myName = name; + } + + public final Project getProject() { + return myProject; + } + + @NotNull + public ConfigurationType getType() { + return myFactory.getType(); + } + + public Icon getIcon() { + return myIcon; + } + + public final String getName() { + return myName; + } + + public final int hashCode() { + return super.hashCode(); + } + + public void checkRunnerSettings(@NotNull ProgramRunner runner, @Nullable RunnerSettings runnerSettings, + @Nullable ConfigurationPerRunnerSettings configurationPerRunnerSettings) throws RuntimeConfigurationException { + } + + public void checkSettingsBeforeRun() throws RuntimeConfigurationException { + } + + public boolean canRunOn(@NotNull ExecutionTarget target) { + return true; + } + + public final boolean equals(final Object obj) { + return super.equals(obj); + } + + public RunConfiguration clone() { + final RunConfigurationBase runConfiguration = (RunConfigurationBase)super.clone(); + runConfiguration.myLogFiles = new ArrayList(myLogFiles); + runConfiguration.myPredefinedLogFiles = new ArrayList(myPredefinedLogFiles); + runConfiguration.myFileOutputPath = myFileOutputPath; + runConfiguration.mySaveOutput = mySaveOutput; + runConfiguration.myShowConsoleOnStdOut = myShowConsoleOnStdOut; + runConfiguration.myShowConsoleOnStdErr = myShowConsoleOnStdErr; + copyCopyableDataTo(runConfiguration); + return runConfiguration; + } + + @Nullable + public LogFileOptions getOptionsForPredefinedLogFile(PredefinedLogFile predefinedLogFile) { + return null; + } + + public void removeAllPredefinedLogFiles() { + myPredefinedLogFiles.clear(); + } + + public void addPredefinedLogFile(PredefinedLogFile predefinedLogFile) { + myPredefinedLogFiles.add(predefinedLogFile); + } + + public ArrayList getPredefinedLogFiles() { + return myPredefinedLogFiles; + } + + public ArrayList getAllLogFiles() { + final ArrayList list = new ArrayList(myLogFiles); + for (PredefinedLogFile predefinedLogFile : myPredefinedLogFiles) { + final LogFileOptions options = getOptionsForPredefinedLogFile(predefinedLogFile); + if (options != null) { + list.add(options); + } + } + return list; + } + + public ArrayList getLogFiles() { + return myLogFiles; + } + + public void addLogFile(String file, String alias, boolean checked){ + myLogFiles.add(new LogFileOptions(alias, file, checked, true, false)); + } + + public void addLogFile(String file, String alias, boolean checked, boolean skipContent, final boolean showAll){ + myLogFiles.add(new LogFileOptions(alias, file, checked, skipContent, showAll)); + } + + public void removeAllLogFiles() { + myLogFiles.clear(); + } + + //invoke before run/debug tabs are shown. + //Should be overriden to add additional tabs for run/debug toolwindow + public void createAdditionalTabComponents(AdditionalTabComponentManager manager, ProcessHandler startedProcess) { + } + + public void customizeLogConsole(LogConsole console) { + } + + public void readExternal(Element element) throws InvalidDataException { + myLogFiles.clear(); + for (final Object o : element.getChildren(LOG_FILE)) { + LogFileOptions logFileOptions = new LogFileOptions(); + logFileOptions.readExternal((Element)o); + myLogFiles.add(logFileOptions); + } + myPredefinedLogFiles.clear(); + final List list = element.getChildren(PREDEFINED_LOG_FILE_ELEMENT); + for (Object fileElement : list) { + final PredefinedLogFile logFile = new PredefinedLogFile(); + logFile.readExternal((Element)fileElement); + myPredefinedLogFiles.add(logFile); + } + final Element fileOutputElement = element.getChild(FILE_OUTPUT); + if (fileOutputElement != null) { + myFileOutputPath = fileOutputElement.getAttributeValue(OUTPUT_FILE); + final String isSave = fileOutputElement.getAttributeValue(SAVE); + mySaveOutput = isSave != null && Boolean.parseBoolean(isSave); + } + myShowConsoleOnStdOut = Boolean.parseBoolean(element.getAttributeValue(SHOW_CONSOLE_ON_STD_OUT)); + myShowConsoleOnStdErr = Boolean.parseBoolean(element.getAttributeValue(SHOW_CONSOLE_ON_STD_ERR)); + } + + public void writeExternal(Element element) throws WriteExternalException { + for (final LogFileOptions options : myLogFiles) { + Element logFile = new Element(LOG_FILE); + options.writeExternal(logFile); + element.addContent(logFile); + } + for (PredefinedLogFile predefinedLogFile : myPredefinedLogFiles) { + Element fileElement = new Element(PREDEFINED_LOG_FILE_ELEMENT); + predefinedLogFile.writeExternal(fileElement); + element.addContent(fileElement); + } + final Element fileOutputPathElement = new Element(FILE_OUTPUT); + if (myFileOutputPath != null) { + fileOutputPathElement.setAttribute(OUTPUT_FILE, myFileOutputPath); + } + fileOutputPathElement.setAttribute(SAVE, String.valueOf(mySaveOutput)); + if (myFileOutputPath != null || mySaveOutput) { + element.addContent(fileOutputPathElement); + } + if (myShowConsoleOnStdOut) {//default value shouldn't be written + element.setAttribute(SHOW_CONSOLE_ON_STD_OUT, String.valueOf(myShowConsoleOnStdOut)); + } + if (myShowConsoleOnStdErr) {//default value shouldn't be written + element.setAttribute(SHOW_CONSOLE_ON_STD_ERR, String.valueOf(myShowConsoleOnStdErr)); + } + } + + public boolean isSaveOutputToFile() { + return mySaveOutput; + } + + public void setSaveOutputToFile(boolean redirectOutput) { + mySaveOutput = redirectOutput; + } + + public boolean isShowConsoleOnStdOut() { + return myShowConsoleOnStdOut; + } + + public void setShowConsoleOnStdOut(boolean showConsoleOnStdOut) { + myShowConsoleOnStdOut = showConsoleOnStdOut; + } + + public boolean isShowConsoleOnStdErr() { + return myShowConsoleOnStdErr; + } + + public void setShowConsoleOnStdErr(boolean showConsoleOnStdErr) { + myShowConsoleOnStdErr = showConsoleOnStdErr; + } + + public String getOutputFilePath() { + return myFileOutputPath; + } + + public void setFileOutputPath(String fileOutputPath) { + myFileOutputPath = fileOutputPath; + } + + public boolean collectOutputFromProcessHandler() { + return true; + } + + public boolean excludeCompileBeforeLaunchOption() { + return false; + } + + @Override + public String toString() { + return getType().getDisplayName() + ": " + getName(); + } +} diff --git a/platform/lang-api/src/com/intellij/execution/configurations/TargetAwareRunProfile.java b/platform/lang-api/src/com/intellij/execution/configurations/TargetAwareRunProfile.java index 064a334aeef5..d1cfa1dd83e0 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/TargetAwareRunProfile.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/TargetAwareRunProfile.java @@ -1,23 +1,23 @@ -/* - * 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.execution.configurations; - -import com.intellij.execution.ExecutionTarget; -import org.jetbrains.annotations.NotNull; - -public interface TargetAwareRunProfile extends RunProfile { - boolean canRunOn(@NotNull ExecutionTarget target); -} +/* + * 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.execution.configurations; + +import com.intellij.execution.ExecutionTarget; +import org.jetbrains.annotations.NotNull; + +public interface TargetAwareRunProfile extends RunProfile { + boolean canRunOn(@NotNull ExecutionTarget target); +} diff --git a/platform/lang-api/src/com/intellij/formatting/DependentSpacingRule.java b/platform/lang-api/src/com/intellij/formatting/DependentSpacingRule.java index 08db7f599886..a6fe9a2ddb8e 100644 --- a/platform/lang-api/src/com/intellij/formatting/DependentSpacingRule.java +++ b/platform/lang-api/src/com/intellij/formatting/DependentSpacingRule.java @@ -1,95 +1,95 @@ -/* - * 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.formatting; - -import com.intellij.openapi.util.TextRange; -import gnu.trove.TObjectIntHashMap; -import org.jetbrains.annotations.NotNull; - -/** - * Holds settings that should be used if - * {@link Spacing#createDependentLFSpacing(int, int, TextRange, boolean, int, DependentSpacingRule) dependent spacing} - * target region changes its 'contains line feeds' status. - * - * @author Denis Zhdanov - * @since 6/28/12 1:08 PM - */ -public class DependentSpacingRule { - - public enum Anchor { - MIN_LINE_FEEDS, MAX_LINE_FEEDS - } - - public enum Trigger { - HAS_LINE_FEEDS, DOES_NOT_HAVE_LINE_FEEDS - } - - public static final DependentSpacingRule DEFAULT = - new DependentSpacingRule(Trigger.HAS_LINE_FEEDS).registerData(Anchor.MIN_LINE_FEEDS, 1); - - private final TObjectIntHashMap myData = new TObjectIntHashMap(); - - @NotNull private final Trigger myTrigger; - - public DependentSpacingRule(@NotNull Trigger trigger) { - myTrigger = trigger; - } - - @NotNull - public Trigger getTrigger() { - return myTrigger; - } - - /** - * Allows to register given data for the given anchor within the current rule. - * - * @param anchor target anchor - * @param data data to register for the given anchor - * @param data's type - * @see #getData(Anchor) - */ - public DependentSpacingRule registerData(@NotNull Anchor anchor, int data) { - myData.put(anchor, data); - return this; - } - - /** - * @param anchor target data anchor - * @return true if there is a data registered for the given anchor within the current rule; - * false otherwise - */ - public boolean hasData(@NotNull Anchor anchor) { - return myData.containsKey(anchor); - } - - /** - * Allows to retrieve data associated with the given anchor. - * - * @param anchor target anchor - * @param data's type - * @return data associated for the given anchor - * @throws IllegalArgumentException if no data is registered for the given anchor - * (use {@link #hasData(Anchor)} for the preliminary examination) - */ - public int getData(@NotNull Anchor anchor) throws IllegalArgumentException { - if (!myData.containsKey(anchor)) { - throw new IllegalArgumentException(String.format( - "No data is registered for the dependent spacing rule %s. Registered: %s", anchor, myData - )); - } - return myData.get(anchor); - } -} +/* + * 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.formatting; + +import com.intellij.openapi.util.TextRange; +import gnu.trove.TObjectIntHashMap; +import org.jetbrains.annotations.NotNull; + +/** + * Holds settings that should be used if + * {@link Spacing#createDependentLFSpacing(int, int, TextRange, boolean, int, DependentSpacingRule) dependent spacing} + * target region changes its 'contains line feeds' status. + * + * @author Denis Zhdanov + * @since 6/28/12 1:08 PM + */ +public class DependentSpacingRule { + + public enum Anchor { + MIN_LINE_FEEDS, MAX_LINE_FEEDS + } + + public enum Trigger { + HAS_LINE_FEEDS, DOES_NOT_HAVE_LINE_FEEDS + } + + public static final DependentSpacingRule DEFAULT = + new DependentSpacingRule(Trigger.HAS_LINE_FEEDS).registerData(Anchor.MIN_LINE_FEEDS, 1); + + private final TObjectIntHashMap myData = new TObjectIntHashMap(); + + @NotNull private final Trigger myTrigger; + + public DependentSpacingRule(@NotNull Trigger trigger) { + myTrigger = trigger; + } + + @NotNull + public Trigger getTrigger() { + return myTrigger; + } + + /** + * Allows to register given data for the given anchor within the current rule. + * + * @param anchor target anchor + * @param data data to register for the given anchor + * @param data's type + * @see #getData(Anchor) + */ + public DependentSpacingRule registerData(@NotNull Anchor anchor, int data) { + myData.put(anchor, data); + return this; + } + + /** + * @param anchor target data anchor + * @return true if there is a data registered for the given anchor within the current rule; + * false otherwise + */ + public boolean hasData(@NotNull Anchor anchor) { + return myData.containsKey(anchor); + } + + /** + * Allows to retrieve data associated with the given anchor. + * + * @param anchor target anchor + * @param data's type + * @return data associated for the given anchor + * @throws IllegalArgumentException if no data is registered for the given anchor + * (use {@link #hasData(Anchor)} for the preliminary examination) + */ + public int getData(@NotNull Anchor anchor) throws IllegalArgumentException { + if (!myData.containsKey(anchor)) { + throw new IllegalArgumentException(String.format( + "No data is registered for the dependent spacing rule %s. Registered: %s", anchor, myData + )); + } + return myData.get(anchor); + } +} diff --git a/platform/lang-api/src/com/intellij/formatting/Spacing.java b/platform/lang-api/src/com/intellij/formatting/Spacing.java index 108c9ec29a64..923370a9025b 100644 --- a/platform/lang-api/src/com/intellij/formatting/Spacing.java +++ b/platform/lang-api/src/com/intellij/formatting/Spacing.java @@ -1,185 +1,185 @@ -/* - * 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.formatting; - -import com.intellij.openapi.util.TextRange; -import org.jetbrains.annotations.NotNull; - -/** - * The spacing setting for a formatting model block. Indicates the number of spaces and/or - * line breaks that should be inserted between the specified children of the specified block. - * - * @see Block#getSpacing(Block, Block) - */ - -public abstract class Spacing { - private static SpacingFactory myFactory; - - static void setFactory(SpacingFactory factory) { - myFactory = factory; - } - - /** - * Creates a regular spacing setting instance. - * - * @param minSpaces The minimum number of spaces that should be present between the blocks - * to which the spacing setting instance is related. Spaces are inserted - * if there are less than this amount of spaces in the document. - * @param maxSpaces The maximum number of spaces that should be present between the blocks - * to which the spacing setting instance is related, or Integer.MAX_VALUE - * if the number of spaces is not limited. Spaces are deleted if there are - * more than this amount of spaces in the document. - * @param minLineFeeds The minimum number of line breaks that should be present between the blocks - * to which the spacing setting instance is related. - * @param keepLineBreaks Whether the existing line breaks between the blocks should be preserved. - * @param keepBlankLines Whether the existing blank lines between the blocks should be preserved. - * @return the spacing setting instance. - */ - public static Spacing createSpacing(int minSpaces, - int maxSpaces, - int minLineFeeds, - boolean keepLineBreaks, - int keepBlankLines) { - return myFactory.createSpacing(minSpaces, maxSpaces, minLineFeeds, keepLineBreaks, keepBlankLines); - } - - /** - * Creates a regular spacing setting instance. - * - * @param minSpaces The minimum number of spaces that should be present between the blocks - * to which the spacing setting instance is related. Spaces are inserted - * if there are less than this amount of spaces in the document. - * @param maxSpaces The maximum number of spaces that should be present between the blocks - * to which the spacing setting instance is related, or Integer.MAX_VALUE - * if the number of spaces is not limited. Spaces are deleted if there are - * more than this amount of spaces in the document. - * @param minLineFeeds The minimum number of line breaks that should be present between the blocks - * to which the spacing setting instance is related. - * @param keepLineBreaks Whether the existing line breaks between the blocks should be preserved. - * @param keepBlankLines Whether the existing blank lines between the blocks should be preserved. - * @return the spacing setting instance. - */ - public static Spacing createSpacing(int minSpaces, - int maxSpaces, - int minLineFeeds, - boolean keepLineBreaks, - int keepBlankLines, - int prefLineFeeds) { - return myFactory.createSpacing(minSpaces, maxSpaces, minLineFeeds, keepLineBreaks, keepBlankLines, prefLineFeeds); - } - - /** - * Returns a spacing setting instance indicating that no line breaks or spaces can be - * inserted or removed by the formatter between the specified two blocks. - * @return the spacing setting instance. - */ - public static Spacing getReadOnlySpacing() { - return myFactory.getReadOnlySpacing(); - } - - /** - * Creates a spacing setting instance which inserts a line break if the specified text range also - * contains a line break. Used for formatting rules like the "next line if wrapped" brace placement. - * - * @param minSpaces The minimum number of spaces that should be present between the blocks - * to which the spacing setting instance is related. Spaces are inserted - * if there are less than this amount of spaces in the document. - * @param maxSpaces The maximum number of spaces that should be present between the blocks - * to which the spacing setting instance is related, or Integer.MAX_VALUE - * if the number of spaces is not limited. Spaces are deleted if there are - * more than this amount of spaces in the document. - * @param dependency The text range checked for the presence of line breaks. - * @param keepLineBreaks Whether the existing line breaks between the blocks should be preserved. - * @param keepBlankLines Whether the existing blank lines between the blocks should be preserved. - * @return the spacing setting instance. - */ - public static Spacing createDependentLFSpacing(int minSpaces, - int maxSpaces, - TextRange dependency, - boolean keepLineBreaks, - int keepBlankLines) - { - return createDependentLFSpacing(minSpaces, maxSpaces, dependency, keepLineBreaks, keepBlankLines, DependentSpacingRule.DEFAULT); - } - - /** - * Creates a spacing setting instance which uses settings from the given dependent spacing rule if the specified text range changes - * its 'has line feed' status during formatting (new line feed is added and the range hasn't contained them before - * or it contained line feed(s) and it was removed during formatting). - *

- * Used for formatting rules like the "next line if wrapped" brace placement. - * - * @param minSpaces The minimum number of spaces that should be present between the blocks - * to which the spacing setting instance is related. Spaces are inserted - * if there are less than this amount of spaces in the document. - * @param maxSpaces The maximum number of spaces that should be present between the blocks - * to which the spacing setting instance is related, or Integer.MAX_VALUE - * if the number of spaces is not limited. Spaces are deleted if there are - * more than this amount of spaces in the document. - * @param dependencyRange The text range checked for the presence of line breaks. - * @param keepLineBreaks Whether the existing line breaks between the blocks should be preserved. - * @param keepBlankLines Whether the existing blank lines between the blocks should be preserved. - * @param rule settings to use if dependent region changes its 'contains line feed' status during formatting - * @return the spacing setting instance for the given parameters - */ - public static Spacing createDependentLFSpacing(int minSpaces, - int maxSpaces, - @NotNull TextRange dependencyRange, - boolean keepLineBreaks, - int keepBlankLines, - @NotNull DependentSpacingRule rule) - { - return myFactory.createDependentLFSpacing(minSpaces, maxSpaces, dependencyRange, keepLineBreaks, keepBlankLines, rule); - } - - /** - * Creates a spacing setting instance which preserves the presence of spaces between the blocks but, - * if spaces are present, may insert or delete the spaces. Used, for example, for HTML formatting - * where the presence of a whitespace is significant but the specific number of whitespaces at a - * given location is not. - * - * @param keepLineBreaks Whether the existing line breaks between the blocks should be preserved. - * @param keepBlankLines Whether the existing blank lines between the blocks should be preserved. - * @return the spacing setting instance. - */ - public static Spacing createSafeSpacing(boolean keepLineBreaks, - int keepBlankLines) { - return myFactory.createSafeSpacing(keepLineBreaks, keepBlankLines); - } - - /** - * Creates a spacing setting instance that keeps the second child on the first column if it was - * there before the formatting, but may indent the second child if it was not in the first column. - * Used for implementing the "Keep when Reformatting | Comment in first column" setting. - * - * @param minSpaces The minimum number of spaces that should be present between the blocks - * to which the spacing setting instance is related. Spaces are inserted - * if there are less than this amount of spaces in the document. - * @param maxSpaces The maximum number of spaces that should be present between the blocks - * to which the spacing setting instance is related, or Integer.MAX_VALUE - * if the number of spaces is not limited. Spaces are deleted if there are - * more than this amount of spaces in the document. - * @param keepLineBreaks Whether the existing line breaks between the blocks should be preserved. - * @param keepBlankLines Whether the existing blank lines between the blocks should be preserved. - * @return the spacing setting instance. - */ - public static Spacing createKeepingFirstColumnSpacing(final int minSpaces, - final int maxSpaces, - final boolean keepLineBreaks, - final int keepBlankLines) { - return myFactory.createKeepingFirstColumnSpacing(minSpaces, maxSpaces, keepLineBreaks, keepBlankLines); - } -} +/* + * 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.formatting; + +import com.intellij.openapi.util.TextRange; +import org.jetbrains.annotations.NotNull; + +/** + * The spacing setting for a formatting model block. Indicates the number of spaces and/or + * line breaks that should be inserted between the specified children of the specified block. + * + * @see Block#getSpacing(Block, Block) + */ + +public abstract class Spacing { + private static SpacingFactory myFactory; + + static void setFactory(SpacingFactory factory) { + myFactory = factory; + } + + /** + * Creates a regular spacing setting instance. + * + * @param minSpaces The minimum number of spaces that should be present between the blocks + * to which the spacing setting instance is related. Spaces are inserted + * if there are less than this amount of spaces in the document. + * @param maxSpaces The maximum number of spaces that should be present between the blocks + * to which the spacing setting instance is related, or Integer.MAX_VALUE + * if the number of spaces is not limited. Spaces are deleted if there are + * more than this amount of spaces in the document. + * @param minLineFeeds The minimum number of line breaks that should be present between the blocks + * to which the spacing setting instance is related. + * @param keepLineBreaks Whether the existing line breaks between the blocks should be preserved. + * @param keepBlankLines Whether the existing blank lines between the blocks should be preserved. + * @return the spacing setting instance. + */ + public static Spacing createSpacing(int minSpaces, + int maxSpaces, + int minLineFeeds, + boolean keepLineBreaks, + int keepBlankLines) { + return myFactory.createSpacing(minSpaces, maxSpaces, minLineFeeds, keepLineBreaks, keepBlankLines); + } + + /** + * Creates a regular spacing setting instance. + * + * @param minSpaces The minimum number of spaces that should be present between the blocks + * to which the spacing setting instance is related. Spaces are inserted + * if there are less than this amount of spaces in the document. + * @param maxSpaces The maximum number of spaces that should be present between the blocks + * to which the spacing setting instance is related, or Integer.MAX_VALUE + * if the number of spaces is not limited. Spaces are deleted if there are + * more than this amount of spaces in the document. + * @param minLineFeeds The minimum number of line breaks that should be present between the blocks + * to which the spacing setting instance is related. + * @param keepLineBreaks Whether the existing line breaks between the blocks should be preserved. + * @param keepBlankLines Whether the existing blank lines between the blocks should be preserved. + * @return the spacing setting instance. + */ + public static Spacing createSpacing(int minSpaces, + int maxSpaces, + int minLineFeeds, + boolean keepLineBreaks, + int keepBlankLines, + int prefLineFeeds) { + return myFactory.createSpacing(minSpaces, maxSpaces, minLineFeeds, keepLineBreaks, keepBlankLines, prefLineFeeds); + } + + /** + * Returns a spacing setting instance indicating that no line breaks or spaces can be + * inserted or removed by the formatter between the specified two blocks. + * @return the spacing setting instance. + */ + public static Spacing getReadOnlySpacing() { + return myFactory.getReadOnlySpacing(); + } + + /** + * Creates a spacing setting instance which inserts a line break if the specified text range also + * contains a line break. Used for formatting rules like the "next line if wrapped" brace placement. + * + * @param minSpaces The minimum number of spaces that should be present between the blocks + * to which the spacing setting instance is related. Spaces are inserted + * if there are less than this amount of spaces in the document. + * @param maxSpaces The maximum number of spaces that should be present between the blocks + * to which the spacing setting instance is related, or Integer.MAX_VALUE + * if the number of spaces is not limited. Spaces are deleted if there are + * more than this amount of spaces in the document. + * @param dependency The text range checked for the presence of line breaks. + * @param keepLineBreaks Whether the existing line breaks between the blocks should be preserved. + * @param keepBlankLines Whether the existing blank lines between the blocks should be preserved. + * @return the spacing setting instance. + */ + public static Spacing createDependentLFSpacing(int minSpaces, + int maxSpaces, + TextRange dependency, + boolean keepLineBreaks, + int keepBlankLines) + { + return createDependentLFSpacing(minSpaces, maxSpaces, dependency, keepLineBreaks, keepBlankLines, DependentSpacingRule.DEFAULT); + } + + /** + * Creates a spacing setting instance which uses settings from the given dependent spacing rule if the specified text range changes + * its 'has line feed' status during formatting (new line feed is added and the range hasn't contained them before + * or it contained line feed(s) and it was removed during formatting). + *

+ * Used for formatting rules like the "next line if wrapped" brace placement. + * + * @param minSpaces The minimum number of spaces that should be present between the blocks + * to which the spacing setting instance is related. Spaces are inserted + * if there are less than this amount of spaces in the document. + * @param maxSpaces The maximum number of spaces that should be present between the blocks + * to which the spacing setting instance is related, or Integer.MAX_VALUE + * if the number of spaces is not limited. Spaces are deleted if there are + * more than this amount of spaces in the document. + * @param dependencyRange The text range checked for the presence of line breaks. + * @param keepLineBreaks Whether the existing line breaks between the blocks should be preserved. + * @param keepBlankLines Whether the existing blank lines between the blocks should be preserved. + * @param rule settings to use if dependent region changes its 'contains line feed' status during formatting + * @return the spacing setting instance for the given parameters + */ + public static Spacing createDependentLFSpacing(int minSpaces, + int maxSpaces, + @NotNull TextRange dependencyRange, + boolean keepLineBreaks, + int keepBlankLines, + @NotNull DependentSpacingRule rule) + { + return myFactory.createDependentLFSpacing(minSpaces, maxSpaces, dependencyRange, keepLineBreaks, keepBlankLines, rule); + } + + /** + * Creates a spacing setting instance which preserves the presence of spaces between the blocks but, + * if spaces are present, may insert or delete the spaces. Used, for example, for HTML formatting + * where the presence of a whitespace is significant but the specific number of whitespaces at a + * given location is not. + * + * @param keepLineBreaks Whether the existing line breaks between the blocks should be preserved. + * @param keepBlankLines Whether the existing blank lines between the blocks should be preserved. + * @return the spacing setting instance. + */ + public static Spacing createSafeSpacing(boolean keepLineBreaks, + int keepBlankLines) { + return myFactory.createSafeSpacing(keepLineBreaks, keepBlankLines); + } + + /** + * Creates a spacing setting instance that keeps the second child on the first column if it was + * there before the formatting, but may indent the second child if it was not in the first column. + * Used for implementing the "Keep when Reformatting | Comment in first column" setting. + * + * @param minSpaces The minimum number of spaces that should be present between the blocks + * to which the spacing setting instance is related. Spaces are inserted + * if there are less than this amount of spaces in the document. + * @param maxSpaces The maximum number of spaces that should be present between the blocks + * to which the spacing setting instance is related, or Integer.MAX_VALUE + * if the number of spaces is not limited. Spaces are deleted if there are + * more than this amount of spaces in the document. + * @param keepLineBreaks Whether the existing line breaks between the blocks should be preserved. + * @param keepBlankLines Whether the existing blank lines between the blocks should be preserved. + * @return the spacing setting instance. + */ + public static Spacing createKeepingFirstColumnSpacing(final int minSpaces, + final int maxSpaces, + final boolean keepLineBreaks, + final int keepBlankLines) { + return myFactory.createKeepingFirstColumnSpacing(minSpaces, maxSpaces, keepLineBreaks, keepBlankLines); + } +} diff --git a/platform/lang-api/src/com/intellij/formatting/SpacingFactory.java b/platform/lang-api/src/com/intellij/formatting/SpacingFactory.java index 722de75fca23..2c105693a68d 100644 --- a/platform/lang-api/src/com/intellij/formatting/SpacingFactory.java +++ b/platform/lang-api/src/com/intellij/formatting/SpacingFactory.java @@ -1,58 +1,58 @@ -/* - * 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.formatting; - -import com.intellij.openapi.util.TextRange; -import org.jetbrains.annotations.NotNull; - -/** - * Internal interface for creating spacing instances. - */ - -interface SpacingFactory { - - @NotNull - Spacing createSpacing(int minSpaces, - int maxSpaces, - int minLineFeeds, - boolean keepLineBreaks, - int keepBlankLines); - - @NotNull - Spacing getReadOnlySpacing(); - - @NotNull - Spacing createDependentLFSpacing(int minSpaces, - int maxSpaces, - @NotNull TextRange dependencyRange, - boolean keepLineBreaks, - int keepBlankLines, - @NotNull DependentSpacingRule rule); - - @NotNull - Spacing createSafeSpacing(boolean keepLineBreaks, - int keepBlankLines); - - @NotNull - Spacing createKeepingFirstColumnSpacing(final int minSpaces, - final int maxSpaces, - final boolean keepLineBreaks, - final int keepBlankLines); - - @NotNull - Spacing createSpacing(final int minSpaces, final int maxSpaces, final int minLineFeeds, final boolean keepLineBreaks, - final int keepBlankLines, final int prefLineFeeds); -} +/* + * 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.formatting; + +import com.intellij.openapi.util.TextRange; +import org.jetbrains.annotations.NotNull; + +/** + * Internal interface for creating spacing instances. + */ + +interface SpacingFactory { + + @NotNull + Spacing createSpacing(int minSpaces, + int maxSpaces, + int minLineFeeds, + boolean keepLineBreaks, + int keepBlankLines); + + @NotNull + Spacing getReadOnlySpacing(); + + @NotNull + Spacing createDependentLFSpacing(int minSpaces, + int maxSpaces, + @NotNull TextRange dependencyRange, + boolean keepLineBreaks, + int keepBlankLines, + @NotNull DependentSpacingRule rule); + + @NotNull + Spacing createSafeSpacing(boolean keepLineBreaks, + int keepBlankLines); + + @NotNull + Spacing createKeepingFirstColumnSpacing(final int minSpaces, + final int maxSpaces, + final boolean keepLineBreaks, + final int keepBlankLines); + + @NotNull + Spacing createSpacing(final int minSpaces, final int maxSpaces, final int minLineFeeds, final boolean keepLineBreaks, + final int keepBlankLines, final int prefLineFeeds); +} diff --git a/platform/lang-api/src/com/intellij/patterns/PsiElementPattern.java b/platform/lang-api/src/com/intellij/patterns/PsiElementPattern.java index f2d51f676c32..6b784a258300 100644 --- a/platform/lang-api/src/com/intellij/patterns/PsiElementPattern.java +++ b/platform/lang-api/src/com/intellij/patterns/PsiElementPattern.java @@ -1,339 +1,339 @@ -/* - * 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.patterns; - -import com.intellij.lang.ASTNode; -import com.intellij.lang.Language; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; -import com.intellij.psi.meta.PsiMetaData; -import com.intellij.psi.meta.PsiMetaOwner; -import com.intellij.psi.tree.IElementType; -import com.intellij.psi.tree.TokenSet; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.PairProcessor; -import com.intellij.util.ProcessingContext; -import com.intellij.util.ReflectionCache; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; - -import static com.intellij.patterns.PlatformPatterns.psiElement; -import static com.intellij.patterns.StandardPatterns.collection; -import static com.intellij.patterns.StandardPatterns.not; - -/** - * @author peter - */ -public abstract class PsiElementPattern> extends TreeElementPattern { - protected PsiElementPattern(final Class aClass) { - super(aClass); - } - - protected PsiElementPattern(@NotNull final InitialPatternCondition condition) { - super(condition); - } - - protected PsiElement[] getChildren(@NotNull final PsiElement element) { - return element.getChildren(); - } - - protected PsiElement getParent(@NotNull final PsiElement element) { - return element.getContext(); - } - - public Self withElementType(IElementType type) { - return withElementType(PlatformPatterns.elementType().equalTo(type)); - } - - public Self withElementType(TokenSet type) { - return withElementType(PlatformPatterns.elementType().tokenSet(type)); - } - - public Self afterLeaf(@NotNull final String... withText) { - return afterLeaf(psiElement().withText(PlatformPatterns.string().oneOf(withText))); - } - - public Self afterLeaf(@NotNull final ElementPattern pattern) { - return afterLeafSkipping(psiElement().whitespaceCommentEmptyOrError(), pattern); - } - - public Self beforeLeaf(@NotNull final ElementPattern pattern) { - return beforeLeafSkipping(psiElement().whitespaceCommentEmptyOrError(), pattern); - } - - public Self whitespace() { - return withElementType(TokenType.WHITE_SPACE); - } - - public Self whitespaceCommentOrError() { - return andOr(psiElement().whitespace(), psiElement(PsiComment.class), psiElement(PsiErrorElement.class)); - } - - public Self whitespaceCommentEmptyOrError() { - return andOr(psiElement().whitespace(), psiElement(PsiComment.class), psiElement(PsiErrorElement.class), psiElement().withText("")); - } - - public Self withFirstNonWhitespaceChild(@NotNull final ElementPattern pattern) { - return withChildren(collection(PsiElement.class).filter(not(psiElement().whitespace()), collection(PsiElement.class).first(pattern))); - } - - public Self withReference(final Class referenceClass) { - return with(new PatternCondition("withReference") { - @Override - public boolean accepts(@NotNull final T t, final ProcessingContext context) { - for (final PsiReference reference : t.getReferences()) { - if (ReflectionCache.isInstance(reference, referenceClass)) { - return true; - } - } - return false; - } - }); - } - - public Self inFile(@NotNull final ElementPattern filePattern) { - return with(new PatternCondition("inFile") { - public boolean accepts(@NotNull final T t, final ProcessingContext context) { - return filePattern.accepts(t.getContainingFile(), context); - } - }); - } - - public Self inVirtualFile(@NotNull final ElementPattern filePattern) { - return with(new PatternCondition("inVirtualFile") { - public boolean accepts(@NotNull final T t, final ProcessingContext context) { - return filePattern.accepts(t.getContainingFile().getViewProvider().getVirtualFile(), context); - } - }); - } - - public Self equalTo(@NotNull final T o) { - return with(new PatternCondition("equalTo") { - public boolean accepts(@NotNull final T t, final ProcessingContext context) { - return t.getManager().areElementsEquivalent(t, o); - } - - }); - } - - public Self withElementType(final ElementPattern pattern) { - return with(new PatternCondition("withElementType") { - public boolean accepts(@NotNull final T t, final ProcessingContext context) { - final ASTNode node = t.getNode(); - return node != null && pattern.accepts(node.getElementType()); - } - - }); - } - - public Self withText(@NotNull @NonNls final String text) { - return withText(StandardPatterns.string().equalTo(text)); - } - - public Self withoutText(@NotNull final String text) { - return withoutText(StandardPatterns.string().equalTo(text)); - } - - public Self withName(@NotNull @NonNls final String name) { - return withName(StandardPatterns.string().equalTo(name)); - } - - public Self withName(@NotNull final ElementPattern name) { - return with(new PsiNamePatternCondition("withName", name)); - } - - public Self afterLeafSkipping(@NotNull final ElementPattern skip, @NotNull final ElementPattern pattern) { - return with(new PatternCondition("afterLeafSkipping") { - public boolean accepts(@NotNull T t, final ProcessingContext context) { - PsiElement element = t; - while (true) { - element = PsiTreeUtil.prevLeaf(element); - if (element != null && element.getTextLength() == 0) { - continue; - } - - if (!skip.getCondition().accepts(element, context)) { - return pattern.getCondition().accepts(element, context); - } - } - } - - }); - } - - public Self beforeLeafSkipping(@NotNull final ElementPattern skip, @NotNull final ElementPattern pattern) { - return with(new PatternCondition("beforeLeafSkipping") { - public boolean accepts(@NotNull T t, final ProcessingContext context) { - PsiElement element = t; - while (true) { - element = PsiTreeUtil.nextLeaf(element); - if (element != null && element.getTextLength() == 0) { - continue; - } - - if (!skip.getCondition().accepts(element, context)) { - return pattern.getCondition().accepts(element, context); - } - } - } - - }); - } - - public Self atStartOf(@NotNull final ElementPattern pattern) { - return with(new PatternCondition("atStartOf") { - public boolean accepts(@NotNull T t, final ProcessingContext context) { - PsiElement element = t; - while (element != null) { - if (pattern.getCondition().accepts(element, context)) { - return element.getTextRange().getStartOffset() == t.getTextRange().getStartOffset(); - } - element = element.getContext(); - } - return false; - } - }); - } - - public Self withTextLength(@NotNull final ElementPattern lengthPattern) { - return with(new PatternConditionPlus("withTextLength", lengthPattern) { - @Override - public boolean processValues(T t, - ProcessingContext context, - PairProcessor integerProcessingContextPairProcessor) { - return integerProcessingContextPairProcessor.process(t.getTextLength(), context); - } - }); - } - - public Self notEmpty() { - return withTextLengthLongerThan(0); - } - - public Self withTextLengthLongerThan(final int minLength) { - return with(new PatternCondition("withTextLengthLongerThan") { - @Override - public boolean accepts(@NotNull T t, ProcessingContext context) { - return t.getTextLength() > minLength; - } - }); - } - - public Self withText(@NotNull final ElementPattern text) { - return with(_withText(text)); - } - - private PatternCondition _withText(final ElementPattern pattern) { - return new PatternConditionPlus("_withText", pattern) { - @Override - public boolean processValues(T t, - ProcessingContext context, - PairProcessor processor) { - return processor.process(t.getText(), context); - } - }; - } - - public Self withoutText(@NotNull final ElementPattern text) { - return without(_withText(text)); - } - - public Self withLanguage(@NotNull final Language language) { - return with(new PatternCondition("withLanguage") { - public boolean accepts(@NotNull final T t, final ProcessingContext context) { - return t.getLanguage().equals(language); - } - }); - } - - public Self withMetaData(final ElementPattern metaDataPattern) { - return with(new PatternCondition("withMetaData") { - public boolean accepts(@NotNull final T t, final ProcessingContext context) { - return t instanceof PsiMetaOwner && metaDataPattern.accepts(((PsiMetaOwner)t).getMetaData(), context); - } - }); - } - - public Self referencing(final ElementPattern targetPattern) { - return with(new PatternCondition("referencing") { - public boolean accepts(@NotNull final T t, final ProcessingContext context) { - final PsiReference[] references = t.getReferences(); - for (final PsiReference reference : references) { - if (targetPattern.accepts(reference.resolve(), context)) return true; - if (reference instanceof PsiPolyVariantReference) { - for (final ResolveResult result : ((PsiPolyVariantReference)reference).multiResolve(true)) { - if (targetPattern.accepts(result.getElement(), context)) return true; - } - } - } - return false; - } - }); - } - - public Self compiled() { - return with(new PatternCondition("compiled") { - @Override - public boolean accepts(@NotNull T t, ProcessingContext context) { - return t instanceof PsiCompiledElement; - } - }); - } - - public Self withTreeParent(final ElementPattern ancestor) { - return with(new PatternCondition("withTreeParent") { - @Override - public boolean accepts(@NotNull T t, ProcessingContext context) { - return ancestor.accepts(t.getParent(), context); - } - }); - } - - public Self insideStarting(final ElementPattern ancestor) { - return with(new PatternCondition("insideStarting") { - @Override - public boolean accepts(@NotNull PsiElement start, ProcessingContext context) { - PsiElement element = getParent(start); - TextRange range = start.getTextRange(); - if (range == null) return false; - - int startOffset = range.getStartOffset(); - while (element != null && element.getTextRange() != null && element.getTextRange().getStartOffset() == startOffset) { - if (ancestor.accepts(element, context)) { - return true; - } - element = getParent(element); - } - return false; - } - }); - } - - public static class Capture extends PsiElementPattern> { - - protected Capture(final Class aClass) { - super(aClass); - } - - protected Capture(@NotNull final InitialPatternCondition condition) { - super(condition); - } - - - } - -} +/* + * 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.patterns; + +import com.intellij.lang.ASTNode; +import com.intellij.lang.Language; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.psi.meta.PsiMetaData; +import com.intellij.psi.meta.PsiMetaOwner; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.PairProcessor; +import com.intellij.util.ProcessingContext; +import com.intellij.util.ReflectionCache; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import static com.intellij.patterns.PlatformPatterns.psiElement; +import static com.intellij.patterns.StandardPatterns.collection; +import static com.intellij.patterns.StandardPatterns.not; + +/** + * @author peter + */ +public abstract class PsiElementPattern> extends TreeElementPattern { + protected PsiElementPattern(final Class aClass) { + super(aClass); + } + + protected PsiElementPattern(@NotNull final InitialPatternCondition condition) { + super(condition); + } + + protected PsiElement[] getChildren(@NotNull final PsiElement element) { + return element.getChildren(); + } + + protected PsiElement getParent(@NotNull final PsiElement element) { + return element.getContext(); + } + + public Self withElementType(IElementType type) { + return withElementType(PlatformPatterns.elementType().equalTo(type)); + } + + public Self withElementType(TokenSet type) { + return withElementType(PlatformPatterns.elementType().tokenSet(type)); + } + + public Self afterLeaf(@NotNull final String... withText) { + return afterLeaf(psiElement().withText(PlatformPatterns.string().oneOf(withText))); + } + + public Self afterLeaf(@NotNull final ElementPattern pattern) { + return afterLeafSkipping(psiElement().whitespaceCommentEmptyOrError(), pattern); + } + + public Self beforeLeaf(@NotNull final ElementPattern pattern) { + return beforeLeafSkipping(psiElement().whitespaceCommentEmptyOrError(), pattern); + } + + public Self whitespace() { + return withElementType(TokenType.WHITE_SPACE); + } + + public Self whitespaceCommentOrError() { + return andOr(psiElement().whitespace(), psiElement(PsiComment.class), psiElement(PsiErrorElement.class)); + } + + public Self whitespaceCommentEmptyOrError() { + return andOr(psiElement().whitespace(), psiElement(PsiComment.class), psiElement(PsiErrorElement.class), psiElement().withText("")); + } + + public Self withFirstNonWhitespaceChild(@NotNull final ElementPattern pattern) { + return withChildren(collection(PsiElement.class).filter(not(psiElement().whitespace()), collection(PsiElement.class).first(pattern))); + } + + public Self withReference(final Class referenceClass) { + return with(new PatternCondition("withReference") { + @Override + public boolean accepts(@NotNull final T t, final ProcessingContext context) { + for (final PsiReference reference : t.getReferences()) { + if (ReflectionCache.isInstance(reference, referenceClass)) { + return true; + } + } + return false; + } + }); + } + + public Self inFile(@NotNull final ElementPattern filePattern) { + return with(new PatternCondition("inFile") { + public boolean accepts(@NotNull final T t, final ProcessingContext context) { + return filePattern.accepts(t.getContainingFile(), context); + } + }); + } + + public Self inVirtualFile(@NotNull final ElementPattern filePattern) { + return with(new PatternCondition("inVirtualFile") { + public boolean accepts(@NotNull final T t, final ProcessingContext context) { + return filePattern.accepts(t.getContainingFile().getViewProvider().getVirtualFile(), context); + } + }); + } + + public Self equalTo(@NotNull final T o) { + return with(new PatternCondition("equalTo") { + public boolean accepts(@NotNull final T t, final ProcessingContext context) { + return t.getManager().areElementsEquivalent(t, o); + } + + }); + } + + public Self withElementType(final ElementPattern pattern) { + return with(new PatternCondition("withElementType") { + public boolean accepts(@NotNull final T t, final ProcessingContext context) { + final ASTNode node = t.getNode(); + return node != null && pattern.accepts(node.getElementType()); + } + + }); + } + + public Self withText(@NotNull @NonNls final String text) { + return withText(StandardPatterns.string().equalTo(text)); + } + + public Self withoutText(@NotNull final String text) { + return withoutText(StandardPatterns.string().equalTo(text)); + } + + public Self withName(@NotNull @NonNls final String name) { + return withName(StandardPatterns.string().equalTo(name)); + } + + public Self withName(@NotNull final ElementPattern name) { + return with(new PsiNamePatternCondition("withName", name)); + } + + public Self afterLeafSkipping(@NotNull final ElementPattern skip, @NotNull final ElementPattern pattern) { + return with(new PatternCondition("afterLeafSkipping") { + public boolean accepts(@NotNull T t, final ProcessingContext context) { + PsiElement element = t; + while (true) { + element = PsiTreeUtil.prevLeaf(element); + if (element != null && element.getTextLength() == 0) { + continue; + } + + if (!skip.getCondition().accepts(element, context)) { + return pattern.getCondition().accepts(element, context); + } + } + } + + }); + } + + public Self beforeLeafSkipping(@NotNull final ElementPattern skip, @NotNull final ElementPattern pattern) { + return with(new PatternCondition("beforeLeafSkipping") { + public boolean accepts(@NotNull T t, final ProcessingContext context) { + PsiElement element = t; + while (true) { + element = PsiTreeUtil.nextLeaf(element); + if (element != null && element.getTextLength() == 0) { + continue; + } + + if (!skip.getCondition().accepts(element, context)) { + return pattern.getCondition().accepts(element, context); + } + } + } + + }); + } + + public Self atStartOf(@NotNull final ElementPattern pattern) { + return with(new PatternCondition("atStartOf") { + public boolean accepts(@NotNull T t, final ProcessingContext context) { + PsiElement element = t; + while (element != null) { + if (pattern.getCondition().accepts(element, context)) { + return element.getTextRange().getStartOffset() == t.getTextRange().getStartOffset(); + } + element = element.getContext(); + } + return false; + } + }); + } + + public Self withTextLength(@NotNull final ElementPattern lengthPattern) { + return with(new PatternConditionPlus("withTextLength", lengthPattern) { + @Override + public boolean processValues(T t, + ProcessingContext context, + PairProcessor integerProcessingContextPairProcessor) { + return integerProcessingContextPairProcessor.process(t.getTextLength(), context); + } + }); + } + + public Self notEmpty() { + return withTextLengthLongerThan(0); + } + + public Self withTextLengthLongerThan(final int minLength) { + return with(new PatternCondition("withTextLengthLongerThan") { + @Override + public boolean accepts(@NotNull T t, ProcessingContext context) { + return t.getTextLength() > minLength; + } + }); + } + + public Self withText(@NotNull final ElementPattern text) { + return with(_withText(text)); + } + + private PatternCondition _withText(final ElementPattern pattern) { + return new PatternConditionPlus("_withText", pattern) { + @Override + public boolean processValues(T t, + ProcessingContext context, + PairProcessor processor) { + return processor.process(t.getText(), context); + } + }; + } + + public Self withoutText(@NotNull final ElementPattern text) { + return without(_withText(text)); + } + + public Self withLanguage(@NotNull final Language language) { + return with(new PatternCondition("withLanguage") { + public boolean accepts(@NotNull final T t, final ProcessingContext context) { + return t.getLanguage().equals(language); + } + }); + } + + public Self withMetaData(final ElementPattern metaDataPattern) { + return with(new PatternCondition("withMetaData") { + public boolean accepts(@NotNull final T t, final ProcessingContext context) { + return t instanceof PsiMetaOwner && metaDataPattern.accepts(((PsiMetaOwner)t).getMetaData(), context); + } + }); + } + + public Self referencing(final ElementPattern targetPattern) { + return with(new PatternCondition("referencing") { + public boolean accepts(@NotNull final T t, final ProcessingContext context) { + final PsiReference[] references = t.getReferences(); + for (final PsiReference reference : references) { + if (targetPattern.accepts(reference.resolve(), context)) return true; + if (reference instanceof PsiPolyVariantReference) { + for (final ResolveResult result : ((PsiPolyVariantReference)reference).multiResolve(true)) { + if (targetPattern.accepts(result.getElement(), context)) return true; + } + } + } + return false; + } + }); + } + + public Self compiled() { + return with(new PatternCondition("compiled") { + @Override + public boolean accepts(@NotNull T t, ProcessingContext context) { + return t instanceof PsiCompiledElement; + } + }); + } + + public Self withTreeParent(final ElementPattern ancestor) { + return with(new PatternCondition("withTreeParent") { + @Override + public boolean accepts(@NotNull T t, ProcessingContext context) { + return ancestor.accepts(t.getParent(), context); + } + }); + } + + public Self insideStarting(final ElementPattern ancestor) { + return with(new PatternCondition("insideStarting") { + @Override + public boolean accepts(@NotNull PsiElement start, ProcessingContext context) { + PsiElement element = getParent(start); + TextRange range = start.getTextRange(); + if (range == null) return false; + + int startOffset = range.getStartOffset(); + while (element != null && element.getTextRange() != null && element.getTextRange().getStartOffset() == startOffset) { + if (ancestor.accepts(element, context)) { + return true; + } + element = getParent(element); + } + return false; + } + }); + } + + public static class Capture extends PsiElementPattern> { + + protected Capture(final Class aClass) { + super(aClass); + } + + protected Capture(@NotNull final InitialPatternCondition condition) { + super(condition); + } + + + } + +} diff --git a/platform/lang-impl/src/com/intellij/application/options/CodeCompletion.form b/platform/lang-impl/src/com/intellij/application/options/CodeCompletion.form index 19fb01648828..ccbe4f740dc8 100644 --- a/platform/lang-impl/src/com/intellij/application/options/CodeCompletion.form +++ b/platform/lang-impl/src/com/intellij/application/options/CodeCompletion.form @@ -1,235 +1,235 @@ - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/platform/lang-impl/src/com/intellij/application/options/CodeCompletionPanel.java b/platform/lang-impl/src/com/intellij/application/options/CodeCompletionPanel.java index 84105d187390..2ced101371c0 100644 --- a/platform/lang-impl/src/com/intellij/application/options/CodeCompletionPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/CodeCompletionPanel.java @@ -1,237 +1,237 @@ -/* - * 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.application.options; - -import com.intellij.codeInsight.CodeInsightSettings; -import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; -import com.intellij.ide.DataManager; -import com.intellij.ide.ui.UISettings; -import com.intellij.openapi.actionSystem.PlatformDataKeys; -import com.intellij.openapi.application.ApplicationBundle; -import com.intellij.openapi.project.Project; -import org.intellij.lang.annotations.MagicConstant; - -import javax.swing.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -public class CodeCompletionPanel { - JPanel myPanel; - private JCheckBox myCbAutocompletion; - private JTextField myAutocompletionDelayField; - private JCheckBox myCbAutopopupJavaDoc; - private JTextField myAutopopupJavaDocField; - private JCheckBox myCbAutocompleteCommonPrefix; - private JCheckBox myCbShowStaticAfterInstance; - - private JCheckBox myCbOnCodeCompletion; - private JCheckBox myCbOnSmartTypeCompletion; - - private JCheckBox myCbParameterInfoPopup; - private JTextField myParameterInfoDelayField; - private JCheckBox myCbShowFullParameterSignatures; - - private JComboBox myCaseSensitiveCombo; - private JComboBox myFocusLookup; - private JCheckBox myCbSorting; - private static final String CASE_SENSITIVE_ALL = ApplicationBundle.message("combobox.autocomplete.case.sensitive.all"); - private static final String CASE_SENSITIVE_NONE = ApplicationBundle.message("combobox.autocomplete.case.sensitive.none"); - private static final String CASE_SENSITIVE_FIRST_LETTER = ApplicationBundle.message("combobox.autocomplete.case.sensitive.first.letter"); - private static final String[] CASE_VARIANTS = {CASE_SENSITIVE_ALL, CASE_SENSITIVE_NONE, CASE_SENSITIVE_FIRST_LETTER}; - private static final String[] FOCUS_VARIANTS = {"Never", "'Smart'", "Always"}; - - public CodeCompletionPanel(){ - myCaseSensitiveCombo.setModel(new DefaultComboBoxModel(CASE_VARIANTS)); - myFocusLookup.setModel(new DefaultComboBoxModel(FOCUS_VARIANTS)); - - - myCbAutocompletion.addActionListener( - new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - myAutocompletionDelayField.setEnabled(myCbAutocompletion.isSelected()); - } - } - ); - - myCbAutopopupJavaDoc.addActionListener( - new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - myAutopopupJavaDocField.setEnabled(myCbAutopopupJavaDoc.isSelected()); - } - } - ); - - myCbParameterInfoPopup.addActionListener( - new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - myParameterInfoDelayField.setEnabled(myCbParameterInfoPopup.isSelected()); - } - } - ); - - hideOption(myCbShowStaticAfterInstance, OptionId.COMPLETION_SHOW_STATIC_AFTER_IMPORT); - hideOption(myCbOnSmartTypeCompletion, OptionId.COMPLETION_SMART_TYPE); - myCbAutocompleteCommonPrefix.setVisible(false); - - reset(); - } - - private static void hideOption(JComponent component, OptionId id) { - component.setVisible(OptionsApplicabilityFilter.isApplicable(id)); - } - - public void reset() { - CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance(); - - final String value; - switch(codeInsightSettings.COMPLETION_CASE_SENSITIVE){ - case CodeInsightSettings.ALL: - value = CASE_SENSITIVE_ALL; - break; - - case CodeInsightSettings.NONE: - value = CASE_SENSITIVE_NONE; - break; - - default: - value = CASE_SENSITIVE_FIRST_LETTER; - break; - } - myCaseSensitiveCombo.setSelectedItem(value); - - myFocusLookup.setSelectedIndex(Math.min(Math.max(codeInsightSettings.AUTOPOPUP_FOCUS_POLICY - 1, 0), FOCUS_VARIANTS.length - 1)); - - myCbOnCodeCompletion.setSelected(codeInsightSettings.AUTOCOMPLETE_ON_CODE_COMPLETION); - myCbOnSmartTypeCompletion.setSelected(codeInsightSettings.AUTOCOMPLETE_ON_SMART_TYPE_COMPLETION); - myCbAutocompleteCommonPrefix.setSelected(codeInsightSettings.AUTOCOMPLETE_COMMON_PREFIX); - myCbShowStaticAfterInstance.setSelected(codeInsightSettings.SHOW_STATIC_AFTER_INSTANCE); - - myCbAutocompletion.setSelected(codeInsightSettings.AUTO_POPUP_COMPLETION_LOOKUP); - myAutocompletionDelayField.setEnabled(codeInsightSettings.AUTO_POPUP_COMPLETION_LOOKUP); - myAutocompletionDelayField.setText(String.valueOf(codeInsightSettings.AUTO_LOOKUP_DELAY)); - - myCbAutopopupJavaDoc.setSelected(codeInsightSettings.AUTO_POPUP_JAVADOC_INFO); - myAutopopupJavaDocField.setEnabled(codeInsightSettings.AUTO_POPUP_JAVADOC_INFO); - myAutopopupJavaDocField.setText(String.valueOf(codeInsightSettings.JAVADOC_INFO_DELAY)); - - myCbParameterInfoPopup.setSelected(codeInsightSettings.AUTO_POPUP_PARAMETER_INFO); - myParameterInfoDelayField.setEnabled(codeInsightSettings.AUTO_POPUP_PARAMETER_INFO); - myParameterInfoDelayField.setText(String.valueOf(codeInsightSettings.PARAMETER_INFO_DELAY)); - myCbShowFullParameterSignatures.setSelected(codeInsightSettings.SHOW_FULL_SIGNATURES_IN_PARAMETER_INFO); - - myCbAutocompletion.setSelected(codeInsightSettings.AUTO_POPUP_COMPLETION_LOOKUP); - myCbSorting.setSelected(UISettings.getInstance().SORT_LOOKUP_ELEMENTS_LEXICOGRAPHICALLY); - } - - public void apply() { - - CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance(); - - codeInsightSettings.COMPLETION_CASE_SENSITIVE = getCaseSensitiveValue(); - //noinspection MagicConstant - codeInsightSettings.AUTOPOPUP_FOCUS_POLICY = getFocusLookupValue(); - - codeInsightSettings.AUTOCOMPLETE_ON_CODE_COMPLETION = myCbOnCodeCompletion.isSelected(); - codeInsightSettings.AUTOCOMPLETE_ON_SMART_TYPE_COMPLETION = myCbOnSmartTypeCompletion.isSelected(); - codeInsightSettings.AUTOCOMPLETE_COMMON_PREFIX = myCbAutocompleteCommonPrefix.isSelected(); - codeInsightSettings.SHOW_STATIC_AFTER_INSTANCE = myCbShowStaticAfterInstance.isSelected(); - codeInsightSettings.SHOW_FULL_SIGNATURES_IN_PARAMETER_INFO = myCbShowFullParameterSignatures.isSelected(); - - codeInsightSettings.AUTO_POPUP_PARAMETER_INFO = myCbParameterInfoPopup.isSelected(); - codeInsightSettings.AUTO_POPUP_COMPLETION_LOOKUP = myCbAutocompletion.isSelected(); - codeInsightSettings.AUTO_POPUP_JAVADOC_INFO = myCbAutopopupJavaDoc.isSelected(); - - codeInsightSettings.AUTO_LOOKUP_DELAY = getIntegerValue(myAutocompletionDelayField.getText(), 0); - codeInsightSettings.PARAMETER_INFO_DELAY = getIntegerValue(myParameterInfoDelayField.getText(), 0); - codeInsightSettings.JAVADOC_INFO_DELAY = getIntegerValue(myAutopopupJavaDocField.getText(), 0); - - UISettings.getInstance().SORT_LOOKUP_ELEMENTS_LEXICOGRAPHICALLY = myCbSorting.isSelected(); - - final Project project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(myPanel)); - if (project != null){ - DaemonCodeAnalyzer.getInstance(project).settingsChanged(); - } - } - - public boolean isModified() { - CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance(); - boolean isModified = false; - - //noinspection ConstantConditions - isModified |= getCaseSensitiveValue() != codeInsightSettings.COMPLETION_CASE_SENSITIVE; - //noinspection MagicConstant - isModified |= getFocusLookupValue() != codeInsightSettings.AUTOPOPUP_FOCUS_POLICY; - - isModified |= isModified(myCbOnCodeCompletion, codeInsightSettings.AUTOCOMPLETE_ON_CODE_COMPLETION); - isModified |= isModified(myCbOnSmartTypeCompletion, codeInsightSettings.AUTOCOMPLETE_ON_SMART_TYPE_COMPLETION); - isModified |= isModified(myCbAutocompleteCommonPrefix, codeInsightSettings.AUTOCOMPLETE_COMMON_PREFIX); - isModified |= isModified(myCbShowStaticAfterInstance, codeInsightSettings.SHOW_STATIC_AFTER_INSTANCE); - isModified |= isModified(myCbShowFullParameterSignatures, codeInsightSettings.SHOW_FULL_SIGNATURES_IN_PARAMETER_INFO); - isModified |= isModified(myCbParameterInfoPopup, codeInsightSettings.AUTO_POPUP_PARAMETER_INFO); - isModified |= isModified(myCbAutocompletion, codeInsightSettings.AUTO_POPUP_COMPLETION_LOOKUP); - - isModified |= isModified(myCbAutopopupJavaDoc, codeInsightSettings.AUTO_POPUP_JAVADOC_INFO); - isModified |= isModified(myAutocompletionDelayField, codeInsightSettings.AUTO_LOOKUP_DELAY, 0); - isModified |= isModified(myParameterInfoDelayField, codeInsightSettings.PARAMETER_INFO_DELAY, 0); - isModified |= isModified(myAutopopupJavaDocField, codeInsightSettings.JAVADOC_INFO_DELAY, 0); - isModified |= isModified(myCbSorting, UISettings.getInstance().SORT_LOOKUP_ELEMENTS_LEXICOGRAPHICALLY); - - return isModified; - } - - private static boolean isModified(JCheckBox checkBox, boolean value) { - return checkBox.isSelected() != value; - } - - private static boolean isModified(JTextField textField, int value, int defaultValue) { - return getIntegerValue(textField.getText(), defaultValue) != value; - } - - private static int getIntegerValue(String s, int defaultValue) { - int value = defaultValue; - try { - value = Integer.parseInt(s); - if(value < 0) { - return defaultValue; - } - } - catch (NumberFormatException ignored) { - } - return value; - } - - @MagicConstant(intValues = {CodeInsightSettings.ALL, CodeInsightSettings.NONE, CodeInsightSettings.FIRST_LETTER}) - private int getCaseSensitiveValue() { - Object value = myCaseSensitiveCombo.getSelectedItem(); - if (CASE_SENSITIVE_ALL.equals(value)){ - return CodeInsightSettings.ALL; - } - else if (CASE_SENSITIVE_NONE.equals(value)){ - return CodeInsightSettings.NONE; - } - else { - return CodeInsightSettings.FIRST_LETTER; - } - } - - private int getFocusLookupValue() { - return myFocusLookup.getSelectedIndex() + 1; - } +/* + * 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.application.options; + +import com.intellij.codeInsight.CodeInsightSettings; +import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; +import com.intellij.ide.DataManager; +import com.intellij.ide.ui.UISettings; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.application.ApplicationBundle; +import com.intellij.openapi.project.Project; +import org.intellij.lang.annotations.MagicConstant; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class CodeCompletionPanel { + JPanel myPanel; + private JCheckBox myCbAutocompletion; + private JTextField myAutocompletionDelayField; + private JCheckBox myCbAutopopupJavaDoc; + private JTextField myAutopopupJavaDocField; + private JCheckBox myCbAutocompleteCommonPrefix; + private JCheckBox myCbShowStaticAfterInstance; + + private JCheckBox myCbOnCodeCompletion; + private JCheckBox myCbOnSmartTypeCompletion; + + private JCheckBox myCbParameterInfoPopup; + private JTextField myParameterInfoDelayField; + private JCheckBox myCbShowFullParameterSignatures; + + private JComboBox myCaseSensitiveCombo; + private JComboBox myFocusLookup; + private JCheckBox myCbSorting; + private static final String CASE_SENSITIVE_ALL = ApplicationBundle.message("combobox.autocomplete.case.sensitive.all"); + private static final String CASE_SENSITIVE_NONE = ApplicationBundle.message("combobox.autocomplete.case.sensitive.none"); + private static final String CASE_SENSITIVE_FIRST_LETTER = ApplicationBundle.message("combobox.autocomplete.case.sensitive.first.letter"); + private static final String[] CASE_VARIANTS = {CASE_SENSITIVE_ALL, CASE_SENSITIVE_NONE, CASE_SENSITIVE_FIRST_LETTER}; + private static final String[] FOCUS_VARIANTS = {"Never", "'Smart'", "Always"}; + + public CodeCompletionPanel(){ + myCaseSensitiveCombo.setModel(new DefaultComboBoxModel(CASE_VARIANTS)); + myFocusLookup.setModel(new DefaultComboBoxModel(FOCUS_VARIANTS)); + + + myCbAutocompletion.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent event) { + myAutocompletionDelayField.setEnabled(myCbAutocompletion.isSelected()); + } + } + ); + + myCbAutopopupJavaDoc.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent event) { + myAutopopupJavaDocField.setEnabled(myCbAutopopupJavaDoc.isSelected()); + } + } + ); + + myCbParameterInfoPopup.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent event) { + myParameterInfoDelayField.setEnabled(myCbParameterInfoPopup.isSelected()); + } + } + ); + + hideOption(myCbShowStaticAfterInstance, OptionId.COMPLETION_SHOW_STATIC_AFTER_IMPORT); + hideOption(myCbOnSmartTypeCompletion, OptionId.COMPLETION_SMART_TYPE); + myCbAutocompleteCommonPrefix.setVisible(false); + + reset(); + } + + private static void hideOption(JComponent component, OptionId id) { + component.setVisible(OptionsApplicabilityFilter.isApplicable(id)); + } + + public void reset() { + CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance(); + + final String value; + switch(codeInsightSettings.COMPLETION_CASE_SENSITIVE){ + case CodeInsightSettings.ALL: + value = CASE_SENSITIVE_ALL; + break; + + case CodeInsightSettings.NONE: + value = CASE_SENSITIVE_NONE; + break; + + default: + value = CASE_SENSITIVE_FIRST_LETTER; + break; + } + myCaseSensitiveCombo.setSelectedItem(value); + + myFocusLookup.setSelectedIndex(Math.min(Math.max(codeInsightSettings.AUTOPOPUP_FOCUS_POLICY - 1, 0), FOCUS_VARIANTS.length - 1)); + + myCbOnCodeCompletion.setSelected(codeInsightSettings.AUTOCOMPLETE_ON_CODE_COMPLETION); + myCbOnSmartTypeCompletion.setSelected(codeInsightSettings.AUTOCOMPLETE_ON_SMART_TYPE_COMPLETION); + myCbAutocompleteCommonPrefix.setSelected(codeInsightSettings.AUTOCOMPLETE_COMMON_PREFIX); + myCbShowStaticAfterInstance.setSelected(codeInsightSettings.SHOW_STATIC_AFTER_INSTANCE); + + myCbAutocompletion.setSelected(codeInsightSettings.AUTO_POPUP_COMPLETION_LOOKUP); + myAutocompletionDelayField.setEnabled(codeInsightSettings.AUTO_POPUP_COMPLETION_LOOKUP); + myAutocompletionDelayField.setText(String.valueOf(codeInsightSettings.AUTO_LOOKUP_DELAY)); + + myCbAutopopupJavaDoc.setSelected(codeInsightSettings.AUTO_POPUP_JAVADOC_INFO); + myAutopopupJavaDocField.setEnabled(codeInsightSettings.AUTO_POPUP_JAVADOC_INFO); + myAutopopupJavaDocField.setText(String.valueOf(codeInsightSettings.JAVADOC_INFO_DELAY)); + + myCbParameterInfoPopup.setSelected(codeInsightSettings.AUTO_POPUP_PARAMETER_INFO); + myParameterInfoDelayField.setEnabled(codeInsightSettings.AUTO_POPUP_PARAMETER_INFO); + myParameterInfoDelayField.setText(String.valueOf(codeInsightSettings.PARAMETER_INFO_DELAY)); + myCbShowFullParameterSignatures.setSelected(codeInsightSettings.SHOW_FULL_SIGNATURES_IN_PARAMETER_INFO); + + myCbAutocompletion.setSelected(codeInsightSettings.AUTO_POPUP_COMPLETION_LOOKUP); + myCbSorting.setSelected(UISettings.getInstance().SORT_LOOKUP_ELEMENTS_LEXICOGRAPHICALLY); + } + + public void apply() { + + CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance(); + + codeInsightSettings.COMPLETION_CASE_SENSITIVE = getCaseSensitiveValue(); + //noinspection MagicConstant + codeInsightSettings.AUTOPOPUP_FOCUS_POLICY = getFocusLookupValue(); + + codeInsightSettings.AUTOCOMPLETE_ON_CODE_COMPLETION = myCbOnCodeCompletion.isSelected(); + codeInsightSettings.AUTOCOMPLETE_ON_SMART_TYPE_COMPLETION = myCbOnSmartTypeCompletion.isSelected(); + codeInsightSettings.AUTOCOMPLETE_COMMON_PREFIX = myCbAutocompleteCommonPrefix.isSelected(); + codeInsightSettings.SHOW_STATIC_AFTER_INSTANCE = myCbShowStaticAfterInstance.isSelected(); + codeInsightSettings.SHOW_FULL_SIGNATURES_IN_PARAMETER_INFO = myCbShowFullParameterSignatures.isSelected(); + + codeInsightSettings.AUTO_POPUP_PARAMETER_INFO = myCbParameterInfoPopup.isSelected(); + codeInsightSettings.AUTO_POPUP_COMPLETION_LOOKUP = myCbAutocompletion.isSelected(); + codeInsightSettings.AUTO_POPUP_JAVADOC_INFO = myCbAutopopupJavaDoc.isSelected(); + + codeInsightSettings.AUTO_LOOKUP_DELAY = getIntegerValue(myAutocompletionDelayField.getText(), 0); + codeInsightSettings.PARAMETER_INFO_DELAY = getIntegerValue(myParameterInfoDelayField.getText(), 0); + codeInsightSettings.JAVADOC_INFO_DELAY = getIntegerValue(myAutopopupJavaDocField.getText(), 0); + + UISettings.getInstance().SORT_LOOKUP_ELEMENTS_LEXICOGRAPHICALLY = myCbSorting.isSelected(); + + final Project project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(myPanel)); + if (project != null){ + DaemonCodeAnalyzer.getInstance(project).settingsChanged(); + } + } + + public boolean isModified() { + CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance(); + boolean isModified = false; + + //noinspection ConstantConditions + isModified |= getCaseSensitiveValue() != codeInsightSettings.COMPLETION_CASE_SENSITIVE; + //noinspection MagicConstant + isModified |= getFocusLookupValue() != codeInsightSettings.AUTOPOPUP_FOCUS_POLICY; + + isModified |= isModified(myCbOnCodeCompletion, codeInsightSettings.AUTOCOMPLETE_ON_CODE_COMPLETION); + isModified |= isModified(myCbOnSmartTypeCompletion, codeInsightSettings.AUTOCOMPLETE_ON_SMART_TYPE_COMPLETION); + isModified |= isModified(myCbAutocompleteCommonPrefix, codeInsightSettings.AUTOCOMPLETE_COMMON_PREFIX); + isModified |= isModified(myCbShowStaticAfterInstance, codeInsightSettings.SHOW_STATIC_AFTER_INSTANCE); + isModified |= isModified(myCbShowFullParameterSignatures, codeInsightSettings.SHOW_FULL_SIGNATURES_IN_PARAMETER_INFO); + isModified |= isModified(myCbParameterInfoPopup, codeInsightSettings.AUTO_POPUP_PARAMETER_INFO); + isModified |= isModified(myCbAutocompletion, codeInsightSettings.AUTO_POPUP_COMPLETION_LOOKUP); + + isModified |= isModified(myCbAutopopupJavaDoc, codeInsightSettings.AUTO_POPUP_JAVADOC_INFO); + isModified |= isModified(myAutocompletionDelayField, codeInsightSettings.AUTO_LOOKUP_DELAY, 0); + isModified |= isModified(myParameterInfoDelayField, codeInsightSettings.PARAMETER_INFO_DELAY, 0); + isModified |= isModified(myAutopopupJavaDocField, codeInsightSettings.JAVADOC_INFO_DELAY, 0); + isModified |= isModified(myCbSorting, UISettings.getInstance().SORT_LOOKUP_ELEMENTS_LEXICOGRAPHICALLY); + + return isModified; + } + + private static boolean isModified(JCheckBox checkBox, boolean value) { + return checkBox.isSelected() != value; + } + + private static boolean isModified(JTextField textField, int value, int defaultValue) { + return getIntegerValue(textField.getText(), defaultValue) != value; + } + + private static int getIntegerValue(String s, int defaultValue) { + int value = defaultValue; + try { + value = Integer.parseInt(s); + if(value < 0) { + return defaultValue; + } + } + catch (NumberFormatException ignored) { + } + return value; + } + + @MagicConstant(intValues = {CodeInsightSettings.ALL, CodeInsightSettings.NONE, CodeInsightSettings.FIRST_LETTER}) + private int getCaseSensitiveValue() { + Object value = myCaseSensitiveCombo.getSelectedItem(); + if (CASE_SENSITIVE_ALL.equals(value)){ + return CodeInsightSettings.ALL; + } + else if (CASE_SENSITIVE_NONE.equals(value)){ + return CodeInsightSettings.NONE; + } + else { + return CodeInsightSettings.FIRST_LETTER; + } + } + + private int getFocusLookupValue() { + return myFocusLookup.getSelectedIndex() + 1; + } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/application/options/OptionId.java b/platform/lang-impl/src/com/intellij/application/options/OptionId.java index cc56c155109c..2c2f6bcd146c 100644 --- a/platform/lang-impl/src/com/intellij/application/options/OptionId.java +++ b/platform/lang-impl/src/com/intellij/application/options/OptionId.java @@ -1,31 +1,31 @@ -/* - * 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.application.options; - -/** - * @author yole - */ -public class OptionId { - private OptionId() { - } - - public static final OptionId RENAME_IN_PLACE = new OptionId(); - public static final OptionId COMPLETION_SHOW_STATIC_AFTER_IMPORT = new OptionId(); - public static final OptionId COMPLETION_SMART_TYPE = new OptionId(); - @Deprecated public static final OptionId COMPLETION_CLASS_NAME = new OptionId(); - public static final OptionId ICONS_IN_GUTTER = new OptionId(); -} +/* + * 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.application.options; + +/** + * @author yole + */ +public class OptionId { + private OptionId() { + } + + public static final OptionId RENAME_IN_PLACE = new OptionId(); + public static final OptionId COMPLETION_SHOW_STATIC_AFTER_IMPORT = new OptionId(); + public static final OptionId COMPLETION_SMART_TYPE = new OptionId(); + @Deprecated public static final OptionId COMPLETION_CLASS_NAME = new OptionId(); + public static final OptionId ICONS_IN_GUTTER = new OptionId(); +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/CodeInsightSettings.java b/platform/lang-impl/src/com/intellij/codeInsight/CodeInsightSettings.java index c16d93f0a229..52dd2201899d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/CodeInsightSettings.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/CodeInsightSettings.java @@ -1,171 +1,171 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.codeInsight; - -import com.intellij.openapi.application.PathManager; -import com.intellij.openapi.components.*; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.util.ArrayUtil; -import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters; -import com.intellij.util.xmlb.XmlSerializationException; -import com.intellij.util.xmlb.XmlSerializer; -import com.intellij.util.xmlb.annotations.AbstractCollection; -import com.intellij.util.xmlb.annotations.Property; -import org.intellij.lang.annotations.MagicConstant; -import org.jdom.Element; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; - - -@State( - name = "CodeInsightSettings", - storages = { - @Storage( - file = StoragePathMacros.APP_CONFIG + "/editor.codeinsight.xml" - )} -) -public class CodeInsightSettings implements PersistentStateComponent, Cloneable, ExportableComponent { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.CodeInsightSettings"); - - @NonNls public static final String EXTERNAL_FILE_NAME = "editor.codeinsight"; - - public static CodeInsightSettings getInstance() { - return ServiceManager.getService(CodeInsightSettings.class); - } - - @Override - @NotNull - public File[] getExportFiles() { - return new File[]{PathManager.getOptionsFile(EXTERNAL_FILE_NAME)}; - } - - @Override - @NotNull - public String getPresentableName() { - return CodeInsightBundle.message("codeinsight.settings"); - } - - @Override - @Nullable - public CodeInsightSettings clone() { - try { - return (CodeInsightSettings)super.clone(); - } - catch (CloneNotSupportedException e) { - return null; - } - } - - public boolean AUTO_POPUP_PARAMETER_INFO = true; - public int PARAMETER_INFO_DELAY = 1000; - public boolean AUTO_POPUP_JAVADOC_INFO = false; - public int JAVADOC_INFO_DELAY = 1000; - public boolean AUTO_POPUP_COMPLETION_LOOKUP = true; - public int AUTO_LOOKUP_DELAY = 0; - - @MagicConstant(intValues = {ALL, NONE, FIRST_LETTER}) - public int COMPLETION_CASE_SENSITIVE = FIRST_LETTER; - public static final int ALL = 1; - public static final int NONE = 2; - public static final int FIRST_LETTER = 3; - - @MagicConstant(intValues = {NEVER, SMART, ALWAYS}) - public int AUTOPOPUP_FOCUS_POLICY = SMART; - public static final int NEVER = 1; - public static final int SMART = 2; - public static final int ALWAYS = 3; - - public boolean AUTOCOMPLETE_ON_CODE_COMPLETION = true; - public boolean AUTOCOMPLETE_ON_SMART_TYPE_COMPLETION = true; - @Deprecated public boolean AUTOCOMPLETE_ON_CLASS_NAME_COMPLETION = false; - public boolean AUTOCOMPLETE_COMMON_PREFIX = true; - public boolean SHOW_STATIC_AFTER_INSTANCE = false; - - public boolean SHOW_FULL_SIGNATURES_IN_PARAMETER_INFO = false; - - public boolean SMART_INDENT_ON_ENTER = true; - public boolean INSERT_BRACE_ON_ENTER = true; - public boolean INSERT_SCRIPTLET_END_ON_ENTER = true; - public boolean JAVADOC_STUB_ON_ENTER = true; - public boolean SMART_END_ACTION = true; - public boolean JAVADOC_GENERATE_CLOSING_TAG = true; - - public boolean SURROUND_SELECTION_ON_QUOTE_TYPED = false; - - public boolean AUTOINSERT_PAIR_BRACKET = true; - public boolean AUTOINSERT_PAIR_QUOTE = true; - - public int REFORMAT_ON_PASTE = INDENT_EACH_LINE; - public static final int NO_REFORMAT = 1; - public static final int INDENT_BLOCK = 2; - public static final int INDENT_EACH_LINE = 3; - public static final int REFORMAT_BLOCK = 4; - - public boolean INDENT_TO_CARET_ON_PASTE = false; - - public int ADD_IMPORTS_ON_PASTE = ASK; // YES, NO or ASK - public static final int YES = 1; - public static final int NO = 2; - public static final int ASK = 3; - - public boolean HIGHLIGHT_BRACES = true; - public boolean HIGHLIGHT_SCOPE = false; - - public boolean USE_INSTANCEOF_ON_EQUALS_PARAMETER = false; - - public boolean HIGHLIGHT_IDENTIFIER_UNDER_CARET = true; - - public boolean OPTIMIZE_IMPORTS_ON_THE_FLY = false; - public boolean ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY = false; - public boolean JSP_ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY = false; - - @Property(surroundWithTag = false) - @AbstractCollection( - surroundWithTag = false, - elementTag = "EXCLUDED_PACKAGE", - elementValueAttribute = "NAME") - public String[] EXCLUDED_PACKAGES = ArrayUtil.EMPTY_STRING_ARRAY; - - @Override - public void loadState(final Element state) { - try { - XmlSerializer.deserializeInto(this, state); - } - catch (XmlSerializationException e) { - LOG.info(e); - } - } - - @Override - public Element getState() { - Element element = new Element("state"); - writeExternal(element); - return element; - } - - public void writeExternal(final Element element) { - try { - XmlSerializer.serializeInto(this, element, new SkipDefaultValuesSerializationFilters()); - } - catch (XmlSerializationException e) { - LOG.info(e); - } - } -} +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.intellij.codeInsight; + +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.components.*; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.ArrayUtil; +import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters; +import com.intellij.util.xmlb.XmlSerializationException; +import com.intellij.util.xmlb.XmlSerializer; +import com.intellij.util.xmlb.annotations.AbstractCollection; +import com.intellij.util.xmlb.annotations.Property; +import org.intellij.lang.annotations.MagicConstant; +import org.jdom.Element; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; + + +@State( + name = "CodeInsightSettings", + storages = { + @Storage( + file = StoragePathMacros.APP_CONFIG + "/editor.codeinsight.xml" + )} +) +public class CodeInsightSettings implements PersistentStateComponent, Cloneable, ExportableComponent { + private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.CodeInsightSettings"); + + @NonNls public static final String EXTERNAL_FILE_NAME = "editor.codeinsight"; + + public static CodeInsightSettings getInstance() { + return ServiceManager.getService(CodeInsightSettings.class); + } + + @Override + @NotNull + public File[] getExportFiles() { + return new File[]{PathManager.getOptionsFile(EXTERNAL_FILE_NAME)}; + } + + @Override + @NotNull + public String getPresentableName() { + return CodeInsightBundle.message("codeinsight.settings"); + } + + @Override + @Nullable + public CodeInsightSettings clone() { + try { + return (CodeInsightSettings)super.clone(); + } + catch (CloneNotSupportedException e) { + return null; + } + } + + public boolean AUTO_POPUP_PARAMETER_INFO = true; + public int PARAMETER_INFO_DELAY = 1000; + public boolean AUTO_POPUP_JAVADOC_INFO = false; + public int JAVADOC_INFO_DELAY = 1000; + public boolean AUTO_POPUP_COMPLETION_LOOKUP = true; + public int AUTO_LOOKUP_DELAY = 0; + + @MagicConstant(intValues = {ALL, NONE, FIRST_LETTER}) + public int COMPLETION_CASE_SENSITIVE = FIRST_LETTER; + public static final int ALL = 1; + public static final int NONE = 2; + public static final int FIRST_LETTER = 3; + + @MagicConstant(intValues = {NEVER, SMART, ALWAYS}) + public int AUTOPOPUP_FOCUS_POLICY = SMART; + public static final int NEVER = 1; + public static final int SMART = 2; + public static final int ALWAYS = 3; + + public boolean AUTOCOMPLETE_ON_CODE_COMPLETION = true; + public boolean AUTOCOMPLETE_ON_SMART_TYPE_COMPLETION = true; + @Deprecated public boolean AUTOCOMPLETE_ON_CLASS_NAME_COMPLETION = false; + public boolean AUTOCOMPLETE_COMMON_PREFIX = true; + public boolean SHOW_STATIC_AFTER_INSTANCE = false; + + public boolean SHOW_FULL_SIGNATURES_IN_PARAMETER_INFO = false; + + public boolean SMART_INDENT_ON_ENTER = true; + public boolean INSERT_BRACE_ON_ENTER = true; + public boolean INSERT_SCRIPTLET_END_ON_ENTER = true; + public boolean JAVADOC_STUB_ON_ENTER = true; + public boolean SMART_END_ACTION = true; + public boolean JAVADOC_GENERATE_CLOSING_TAG = true; + + public boolean SURROUND_SELECTION_ON_QUOTE_TYPED = false; + + public boolean AUTOINSERT_PAIR_BRACKET = true; + public boolean AUTOINSERT_PAIR_QUOTE = true; + + public int REFORMAT_ON_PASTE = INDENT_EACH_LINE; + public static final int NO_REFORMAT = 1; + public static final int INDENT_BLOCK = 2; + public static final int INDENT_EACH_LINE = 3; + public static final int REFORMAT_BLOCK = 4; + + public boolean INDENT_TO_CARET_ON_PASTE = false; + + public int ADD_IMPORTS_ON_PASTE = ASK; // YES, NO or ASK + public static final int YES = 1; + public static final int NO = 2; + public static final int ASK = 3; + + public boolean HIGHLIGHT_BRACES = true; + public boolean HIGHLIGHT_SCOPE = false; + + public boolean USE_INSTANCEOF_ON_EQUALS_PARAMETER = false; + + public boolean HIGHLIGHT_IDENTIFIER_UNDER_CARET = true; + + public boolean OPTIMIZE_IMPORTS_ON_THE_FLY = false; + public boolean ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY = false; + public boolean JSP_ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY = false; + + @Property(surroundWithTag = false) + @AbstractCollection( + surroundWithTag = false, + elementTag = "EXCLUDED_PACKAGE", + elementValueAttribute = "NAME") + public String[] EXCLUDED_PACKAGES = ArrayUtil.EMPTY_STRING_ARRAY; + + @Override + public void loadState(final Element state) { + try { + XmlSerializer.deserializeInto(this, state); + } + catch (XmlSerializationException e) { + LOG.info(e); + } + } + + @Override + public Element getState() { + Element element = new Element("state"); + writeExternal(element); + return element; + } + + public void writeExternal(final Element element) { + try { + XmlSerializer.serializeInto(this, element, new SkipDefaultValuesSerializationFilters()); + } + catch (XmlSerializationException e) { + LOG.info(e); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionFeatures.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionFeatures.java index 5c8398f08b28..052e87ef4337 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionFeatures.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionFeatures.java @@ -1,38 +1,38 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import org.jetbrains.annotations.NonNls; - -/** - * @author peter - */ -public interface - CodeCompletionFeatures { - @NonNls String EXCLAMATION_FINISH = "editing.completion.finishByExclamation"; - @NonNls String SECOND_BASIC_COMPLETION = "editing.completion.second.basic"; - @NonNls String EDITING_COMPLETION_SMARTTYPE_GENERAL = "editing.completion.smarttype.general"; - @NonNls String EDITING_COMPLETION_BASIC = "editing.completion.basic"; - @NonNls String EDITING_COMPLETION_CLASSNAME = "editing.completion.classname"; - @NonNls String EDITING_COMPLETION_CAMEL_HUMPS = "editing.completion.camelHumps"; - @NonNls String EDITING_COMPLETION_REPLACE = "editing.completion.replace"; - @NonNls String EDITING_COMPLETION_FINISH_BY_DOT_ETC = "editing.completion.finishByDotEtc"; - @NonNls String EDITING_COMPLETION_FINISH_BY_SMART_ENTER = "editing.completion.finishBySmartEnter"; - - @NonNls String EDITING_COMPLETION_CONTROL_ENTER = "editing.completion.finishByControlEnter"; - @NonNls String EDITING_COMPLETION_CONTROL_ARROWS = "editing.completion.cancelByControlArrows"; - @NonNls String EDITING_COMPLETION_CHANGE_SORTING = "editing.completion.changeSorting"; -} +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.completion; + +import org.jetbrains.annotations.NonNls; + +/** + * @author peter + */ +public interface + CodeCompletionFeatures { + @NonNls String EXCLAMATION_FINISH = "editing.completion.finishByExclamation"; + @NonNls String SECOND_BASIC_COMPLETION = "editing.completion.second.basic"; + @NonNls String EDITING_COMPLETION_SMARTTYPE_GENERAL = "editing.completion.smarttype.general"; + @NonNls String EDITING_COMPLETION_BASIC = "editing.completion.basic"; + @NonNls String EDITING_COMPLETION_CLASSNAME = "editing.completion.classname"; + @NonNls String EDITING_COMPLETION_CAMEL_HUMPS = "editing.completion.camelHumps"; + @NonNls String EDITING_COMPLETION_REPLACE = "editing.completion.replace"; + @NonNls String EDITING_COMPLETION_FINISH_BY_DOT_ETC = "editing.completion.finishByDotEtc"; + @NonNls String EDITING_COMPLETION_FINISH_BY_SMART_ENTER = "editing.completion.finishBySmartEnter"; + + @NonNls String EDITING_COMPLETION_CONTROL_ENTER = "editing.completion.finishByControlEnter"; + @NonNls String EDITING_COMPLETION_CONTROL_ARROWS = "editing.completion.cancelByControlArrows"; + @NonNls String EDITING_COMPLETION_CHANGE_SORTING = "editing.completion.changeSorting"; +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/PrefixMatchingWeigher.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/PrefixMatchingWeigher.java index f36763d7ba2e..1dff28843f05 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/PrefixMatchingWeigher.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/PrefixMatchingWeigher.java @@ -1,30 +1,30 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.lookup.LookupElement; -import org.jetbrains.annotations.NotNull; - -/** - * @author peter -*/ -public class PrefixMatchingWeigher extends CompletionWeigher { - - @Override - public Comparable weigh(@NotNull LookupElement element, @NotNull CompletionLocation location) { - throw new UnsupportedOperationException("Not implemented"); - } -} +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.completion; + +import com.intellij.codeInsight.lookup.LookupElement; +import org.jetbrains.annotations.NotNull; + +/** + * @author peter +*/ +public class PrefixMatchingWeigher extends CompletionWeigher { + + @Override + public Comparable weigh(@NotNull LookupElement element, @NotNull CompletionLocation location) { + throw new UnsupportedOperationException("Not implemented"); + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/BaseCodeCompletionAction.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/BaseCodeCompletionAction.java index 918b0f57eff1..dc92fd0d8dc6 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/BaseCodeCompletionAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/BaseCodeCompletionAction.java @@ -1,69 +1,69 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion.actions; - -import com.intellij.codeInsight.completion.CodeCompletionHandlerBase; -import com.intellij.codeInsight.completion.CompletionType; -import com.intellij.codeInsight.hint.HintManagerImpl; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.PlatformDataKeys; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiFile; -import com.intellij.psi.util.PsiUtilBase; - -import java.awt.event.InputEvent; - -/** - * @author peter - */ -public abstract class BaseCodeCompletionAction extends AnAction implements HintManagerImpl.ActionToIgnore, DumbAware { - - protected BaseCodeCompletionAction() { - setEnabledInModalContext(true); - setInjectedContext(true); - } - - protected static void invokeCompletion(AnActionEvent e, CompletionType type, int time) { - Project project = e.getData(PlatformDataKeys.PROJECT); - Editor editor = e.getData(PlatformDataKeys.EDITOR); - assert project != null; - assert editor != null; - InputEvent inputEvent = e.getInputEvent(); - new CodeCompletionHandlerBase(type).invokeCompletion(project, editor, time, inputEvent != null && inputEvent.getModifiers() != 0, false); - } - - @Override - public void update(AnActionEvent e) { - DataContext dataContext = e.getDataContext(); - e.getPresentation().setEnabled(false); - Project project = PlatformDataKeys.PROJECT.getData(dataContext); - if (project == null) return; - - Editor editor = PlatformDataKeys.EDITOR.getData(dataContext); - if (editor == null) return; - - final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project); - if (psiFile == null) return; - - if (!ApplicationManager.getApplication().isUnitTestMode() && !editor.getContentComponent().isShowing()) return; - e.getPresentation().setEnabled(true); - } -} +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.completion.actions; + +import com.intellij.codeInsight.completion.CodeCompletionHandlerBase; +import com.intellij.codeInsight.completion.CompletionType; +import com.intellij.codeInsight.hint.HintManagerImpl; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiUtilBase; + +import java.awt.event.InputEvent; + +/** + * @author peter + */ +public abstract class BaseCodeCompletionAction extends AnAction implements HintManagerImpl.ActionToIgnore, DumbAware { + + protected BaseCodeCompletionAction() { + setEnabledInModalContext(true); + setInjectedContext(true); + } + + protected static void invokeCompletion(AnActionEvent e, CompletionType type, int time) { + Project project = e.getData(PlatformDataKeys.PROJECT); + Editor editor = e.getData(PlatformDataKeys.EDITOR); + assert project != null; + assert editor != null; + InputEvent inputEvent = e.getInputEvent(); + new CodeCompletionHandlerBase(type).invokeCompletion(project, editor, time, inputEvent != null && inputEvent.getModifiers() != 0, false); + } + + @Override + public void update(AnActionEvent e) { + DataContext dataContext = e.getDataContext(); + e.getPresentation().setEnabled(false); + Project project = PlatformDataKeys.PROJECT.getData(dataContext); + if (project == null) return; + + Editor editor = PlatformDataKeys.EDITOR.getData(dataContext); + if (editor == null) return; + + final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project); + if (psiFile == null) return; + + if (!ApplicationManager.getApplication().isUnitTestMode() && !editor.getContentComponent().isShowing()) return; + e.getPresentation().setEnabled(true); + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/ClassNameCompletionAction.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/ClassNameCompletionAction.java index 431b1020cc89..ffb87d79de04 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/ClassNameCompletionAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/ClassNameCompletionAction.java @@ -1,30 +1,30 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES 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.completion.actions; - -import com.intellij.codeInsight.completion.CompletionType; -import com.intellij.openapi.actionSystem.AnActionEvent; - -public class ClassNameCompletionAction extends BaseCodeCompletionAction{ - - @Override - public void actionPerformed(AnActionEvent e) { - invokeCompletion(e, CompletionType.BASIC, 2); - } - - -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.completion.actions; + +import com.intellij.codeInsight.completion.CompletionType; +import com.intellij.openapi.actionSystem.AnActionEvent; + +public class ClassNameCompletionAction extends BaseCodeCompletionAction{ + + @Override + public void actionPerformed(AnActionEvent e) { + invokeCompletion(e, CompletionType.BASIC, 2); + } + + +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/CodeCompletionAction.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/CodeCompletionAction.java index 7e2b9d544566..c3468028fb75 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/CodeCompletionAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/CodeCompletionAction.java @@ -1,36 +1,36 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.codeInsight.completion.actions; - -import com.intellij.codeInsight.completion.CodeCompletionFeatures; -import com.intellij.codeInsight.completion.CompletionType; -import com.intellij.featureStatistics.FeatureUsageTracker; -import com.intellij.openapi.actionSystem.AnActionEvent; - -/** - * @author peter - */ -public class CodeCompletionAction extends BaseCodeCompletionAction { - - @Override - public void actionPerformed(AnActionEvent e) { - FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_BASIC); - invokeCompletion(e, CompletionType.BASIC, 1); - } - - -} +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.intellij.codeInsight.completion.actions; + +import com.intellij.codeInsight.completion.CodeCompletionFeatures; +import com.intellij.codeInsight.completion.CompletionType; +import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.openapi.actionSystem.AnActionEvent; + +/** + * @author peter + */ +public class CodeCompletionAction extends BaseCodeCompletionAction { + + @Override + public void actionPerformed(AnActionEvent e) { + FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_BASIC); + invokeCompletion(e, CompletionType.BASIC, 1); + } + + +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/SmartCodeCompletionAction.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/SmartCodeCompletionAction.java index 2bc2c56dfb51..61f91c3e9ace 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/SmartCodeCompletionAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/SmartCodeCompletionAction.java @@ -1,36 +1,36 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.codeInsight.completion.actions; - -import com.intellij.codeInsight.completion.CodeCompletionFeatures; -import com.intellij.codeInsight.completion.CompletionType; -import com.intellij.featureStatistics.FeatureUsageTracker; -import com.intellij.openapi.actionSystem.AnActionEvent; - -/** - * @author peter - */ -public class SmartCodeCompletionAction extends BaseCodeCompletionAction{ - - @Override - public void actionPerformed(AnActionEvent e) { - FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_SMARTTYPE_GENERAL); - invokeCompletion(e, CompletionType.SMART, 1); - } - - -} +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.intellij.codeInsight.completion.actions; + +import com.intellij.codeInsight.completion.CodeCompletionFeatures; +import com.intellij.codeInsight.completion.CompletionType; +import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.openapi.actionSystem.AnActionEvent; + +/** + * @author peter + */ +public class SmartCodeCompletionAction extends BaseCodeCompletionAction{ + + @Override + public void actionPerformed(AnActionEvent e) { + FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_SMARTTYPE_GENERAL); + invokeCompletion(e, CompletionType.SMART, 1); + } + + +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/DefaultGutterIconNavigationHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/DefaultGutterIconNavigationHandler.java index a79f6fa252a9..98b44f8f2aed 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/DefaultGutterIconNavigationHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/DefaultGutterIconNavigationHandler.java @@ -1,38 +1,38 @@ -package com.intellij.codeInsight.daemon; - -import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator; -import com.intellij.ide.util.DefaultPsiElementCellRenderer; -import com.intellij.psi.NavigatablePsiElement; -import com.intellij.psi.PsiElement; - -import javax.swing.*; -import java.awt.event.MouseEvent; -import java.util.Collection; - -/** -* @author yole -*/ -public class DefaultGutterIconNavigationHandler implements GutterIconNavigationHandler { - private final Collection myReferences; - private final String myTitle; - - public DefaultGutterIconNavigationHandler(Collection references, String title) { - myReferences = references; - myTitle = title; - } - - public Collection getReferences() { - return myReferences; - } - - @Override - public void navigate(MouseEvent e, T elt) { - PsiElementListNavigator.openTargets(e, - myReferences.toArray(new NavigatablePsiElement[myReferences.size()]), - myTitle, null, createListCellRenderer()); - } - - protected ListCellRenderer createListCellRenderer() { - return new DefaultPsiElementCellRenderer(); - } -} +package com.intellij.codeInsight.daemon; + +import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator; +import com.intellij.ide.util.DefaultPsiElementCellRenderer; +import com.intellij.psi.NavigatablePsiElement; +import com.intellij.psi.PsiElement; + +import javax.swing.*; +import java.awt.event.MouseEvent; +import java.util.Collection; + +/** +* @author yole +*/ +public class DefaultGutterIconNavigationHandler implements GutterIconNavigationHandler { + private final Collection myReferences; + private final String myTitle; + + public DefaultGutterIconNavigationHandler(Collection references, String title) { + myReferences = references; + myTitle = title; + } + + public Collection getReferences() { + return myReferences; + } + + @Override + public void navigate(MouseEvent e, T elt) { + PsiElementListNavigator.openTargets(e, + myReferences.toArray(new NavigatablePsiElement[myReferences.size()]), + myTitle, null, createListCellRenderer()); + } + + protected ListCellRenderer createListCellRenderer() { + return new DefaultPsiElementCellRenderer(); + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java index 17cba37be6ed..eb0060166dca 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java @@ -1,879 +1,879 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.codeInsight.daemon.impl; - -import com.intellij.codeHighlighting.Pass; -import com.intellij.codeHighlighting.TextEditorHighlightingPass; -import com.intellij.codeInsight.daemon.DaemonBundle; -import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightLevelUtil; -import com.intellij.codeInsight.problems.ProblemImpl; -import com.intellij.codeInsight.problems.WolfTheProblemSolverImpl; -import com.intellij.concurrency.JobLauncher; -import com.intellij.injected.editor.DocumentWindow; -import com.intellij.lang.Language; -import com.intellij.lang.annotation.HighlightSeverity; -import com.intellij.lang.injection.InjectedLanguageManager; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.HighlighterColors; -import com.intellij.openapi.editor.RangeMarker; -import com.intellij.openapi.editor.colors.EditorColors; -import com.intellij.openapi.editor.colors.EditorColorsManager; -import com.intellij.openapi.editor.colors.EditorColorsScheme; -import com.intellij.openapi.editor.colors.TextAttributesKey; -import com.intellij.openapi.editor.ex.MarkupModelEx; -import com.intellij.openapi.editor.ex.RangeHighlighterEx; -import com.intellij.openapi.editor.impl.DocumentMarkupModel; -import com.intellij.openapi.editor.markup.MarkupModel; -import com.intellij.openapi.editor.markup.TextAttributes; -import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.fileTypes.SyntaxHighlighter; -import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.DumbService; -import com.intellij.openapi.project.IndexNotReadyException; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.*; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.problems.Problem; -import com.intellij.problems.WolfTheProblemSolver; -import com.intellij.psi.*; -import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; -import com.intellij.psi.impl.source.tree.injected.Place; -import com.intellij.psi.search.PsiTodoSearchHelper; -import com.intellij.psi.search.TodoItem; -import com.intellij.psi.tree.IElementType; -import com.intellij.util.Processor; -import com.intellij.util.SmartList; -import com.intellij.util.containers.Stack; -import com.intellij.util.containers.TransferToEDTQueue; -import com.intellij.util.ui.UIUtil; -import gnu.trove.THashMap; -import gnu.trove.THashSet; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.*; -import java.util.*; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingPass implements DumbAware { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass"); - static final String PRESENTABLE_NAME = DaemonBundle.message("pass.syntax"); - private static final Key HAS_ERROR_ELEMENT = Key.create("HAS_ERROR_ELEMENT"); - private static final JobLauncher JobUtil = JobLauncher.getInstance(); - - private final int myStartOffset; - private final int myEndOffset; - private final boolean myUpdateAll; - private final ProperTextRange myPriorityRange; - private final Editor myEditor; - - private final List myHighlights = new ArrayList(); - - protected volatile boolean myHasErrorElement; - private volatile boolean myErrorFound; - private static final Comparator VISITOR_ORDER_COMPARATOR = new Comparator() { - @Override - public int compare(final HighlightVisitor o1, final HighlightVisitor o2) { - return o1.order() - o2.order(); - } - }; - private volatile Runnable myApplyCommand; - private final EditorColorsScheme myGlobalScheme; - - public GeneralHighlightingPass(@NotNull Project project, - @NotNull PsiFile file, - @NotNull Document document, - int startOffset, - int endOffset, - boolean updateAll) { - this(project, file, document, startOffset, endOffset, updateAll, new ProperTextRange(0,document.getTextLength()), null); - } - public GeneralHighlightingPass(@NotNull Project project, - @NotNull PsiFile file, - @NotNull Document document, - int startOffset, - int endOffset, - boolean updateAll, - @NotNull ProperTextRange priorityRange, - @Nullable Editor editor) { - super(project, document, PRESENTABLE_NAME, file, true); - myStartOffset = startOffset; - myEndOffset = endOffset; - myUpdateAll = updateAll; - myPriorityRange = priorityRange; - myEditor = editor; - - LOG.assertTrue(file.isValid()); - setId(Pass.UPDATE_ALL); - myHasErrorElement = !isWholeFileHighlighting() && Boolean.TRUE.equals(myFile.getUserData(HAS_ERROR_ELEMENT)); - FileStatusMap fileStatusMap = ((DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(myProject)).getFileStatusMap(); - myErrorFound = !isWholeFileHighlighting() && fileStatusMap.wasErrorFound(myDocument); - - myApplyCommand = new Runnable() { - @Override - public void run() { - ProperTextRange range = new ProperTextRange(myStartOffset, myEndOffset); - MarkupModel model = DocumentMarkupModel.forDocument(myDocument, myProject, true); - UpdateHighlightersUtil.cleanFileLevelHighlights(myProject, Pass.UPDATE_ALL,myFile); - final EditorColorsScheme colorsScheme = getColorsScheme(); - UpdateHighlightersUtil.setHighlightersInRange(myProject, myDocument, range, colorsScheme, myHighlights, (MarkupModelEx)model, Pass.UPDATE_ALL); - } - }; - - // initial guess to show correct progress in the traffic light icon - setProgressLimit(document.getTextLength()/2); // approx number of PSI elements = file length/2 - myGlobalScheme = EditorColorsManager.getInstance().getGlobalScheme(); - } - - private static final Key HIGHLIGHT_VISITOR_INSTANCE_COUNT = new Key("HIGHLIGHT_VISITOR_INSTANCE_COUNT"); - @NotNull - private HighlightVisitor[] getHighlightVisitors() { - int oldCount = incVisitorUsageCount(1); - HighlightVisitor[] highlightVisitors = createHighlightVisitors(); - if (oldCount != 0) { - HighlightVisitor[] clones = new HighlightVisitor[highlightVisitors.length]; - for (int i = 0; i < highlightVisitors.length; i++) { - HighlightVisitor highlightVisitor = highlightVisitors[i]; - clones[i] = highlightVisitor.clone(); - } - highlightVisitors = clones; - } - return highlightVisitors; - } - - protected HighlightVisitor[] createHighlightVisitors() { - return Extensions.getExtensions(HighlightVisitor.EP_HIGHLIGHT_VISITOR, myProject); - } - - // returns old value - private int incVisitorUsageCount(int delta) { - AtomicInteger count = myProject.getUserData(HIGHLIGHT_VISITOR_INSTANCE_COUNT); - if (count == null) { - count = ((UserDataHolderEx)myProject).putUserDataIfAbsent(HIGHLIGHT_VISITOR_INSTANCE_COUNT, new AtomicInteger(0)); - } - int old = count.getAndAdd(delta); - assert old + delta >= 0 : old +";" + delta; - return old; - } - - @Override - protected void collectInformationWithProgress(final ProgressIndicator progress) { - final Set gotHighlights = new THashSet(100); - final Set outsideResult = new THashSet(100); - - DaemonCodeAnalyzer daemonCodeAnalyzer = DaemonCodeAnalyzer.getInstance(myProject); - HighlightVisitor[] highlightVisitors = getHighlightVisitors(); - final List inside = new ArrayList(); - final List outside = new ArrayList(); - try { - final HighlightVisitor[] filteredVisitors = filterVisitors(highlightVisitors, myFile); - Divider.divideInsideAndOutside(myFile, myStartOffset, myEndOffset, myPriorityRange, inside, outside, - HighlightLevelUtil.AnalysisLevel.HIGHLIGHT,false); - - setProgressLimit((long)(inside.size()+outside.size())); - - final boolean forceHighlightParents = forceHighlightParents(); - - if (!isDumbMode()) { - highlightTodos(myFile, myDocument.getCharsSequence(), myStartOffset, myEndOffset, progress, myPriorityRange, gotHighlights, outsideResult); - } - - collectHighlights(inside, new Runnable() { - @Override - public void run() { - // all infos for the "injected fragment for the host which is inside" are indeed inside - // but some of the infos for the "injected fragment for the host which is outside" can be still inside - Set injectedResult = new THashSet(); - final Set injected = new THashSet(); - getInjectedPsiFiles(inside, outside, progress, injected); - if (!addInjectedPsiHighlights(injected, progress, Collections.synchronizedSet(injectedResult))) throw new ProcessCanceledException(); - final List injectionsOutside = new ArrayList(gotHighlights.size()); - - Set result; - synchronized (injectedResult) { - // sync here because all writes happened in another thread - result = injectedResult; - } - for (HighlightInfo info : result) { - if (myPriorityRange.containsRange(info.getStartOffset(), info.getEndOffset())) { - gotHighlights.add(info); - } - else { - // nonconditionally apply injected results regardless whether they are in myStartOffset,myEndOffset - injectionsOutside.add(info); - } - } - - if (outsideResult.isEmpty() && injectionsOutside.isEmpty()) { - return; // apply only result (by default apply command) and only within inside - } - - final ProperTextRange priorityIntersection = myPriorityRange.intersection(new TextRange(myStartOffset, myEndOffset)); - if ((!inside.isEmpty() || !gotHighlights.isEmpty()) && priorityIntersection != null) { // do not apply when there were no elements to highlight - // clear infos found in visible area to avoid applying them twice - final List toApplyInside = new ArrayList(gotHighlights); - myHighlights.addAll(toApplyInside); - gotHighlights.clear(); - gotHighlights.addAll(outsideResult); - final long modificationStamp = myDocument.getModificationStamp(); - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - if (myProject.isDisposed() || modificationStamp != myDocument.getModificationStamp()) return; - MarkupModel markupModel = DocumentMarkupModel.forDocument(myDocument, myProject, true); - - UpdateHighlightersUtil.setHighlightersInRange(myProject, myDocument, priorityIntersection, getColorsScheme(), toApplyInside, - (MarkupModelEx)markupModel, Pass.UPDATE_ALL); - if (myEditor != null) { - new ShowAutoImportPass(myProject, myFile, myEditor).applyInformationToEditor(); - } - } - }); - } - - myApplyCommand = new Runnable() { - @Override - public void run() { - ProperTextRange range = new ProperTextRange(myStartOffset, myEndOffset); - - List toApply = new ArrayList(); - for (HighlightInfo info : gotHighlights) { - if (!range.containsRange(info.getStartOffset(), info.getEndOffset())) continue; - if (!myPriorityRange.containsRange(info.getStartOffset(), info.getEndOffset())) { - toApply.add(info); - } - } - toApply.addAll(injectionsOutside); - - UpdateHighlightersUtil.setHighlightersOutsideRange(myProject, myDocument, toApply, getColorsScheme(), - myStartOffset, myEndOffset, myPriorityRange, Pass.UPDATE_ALL); - } - }; - } - }, outside, progress, filteredVisitors, gotHighlights, forceHighlightParents); - - if (myUpdateAll) { - ((DaemonCodeAnalyzerImpl)daemonCodeAnalyzer).getFileStatusMap().setErrorFoundFlag(myDocument, myErrorFound); - } - } - finally { - incVisitorUsageCount(-1); - } - myHighlights.addAll(gotHighlights); - } - - private void getInjectedPsiFiles(@NotNull final List elements1, - @NotNull final List elements2, - @NotNull final ProgressIndicator progress, - @NotNull final Set outInjected) { - List injected = InjectedLanguageUtil.getCachedInjectedDocuments(myFile); - Collection hosts = new THashSet(elements1.size() + elements2.size() + injected.size()); - - //rehighlight all injected PSI regardless the range, - //since change in one place can lead to invalidation of injected PSI in (completely) other place. - for (DocumentWindow documentRange : injected) { - progress.checkCanceled(); - if (!documentRange.isValid()) continue; - PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(documentRange); - if (file == null) continue; - PsiElement context = InjectedLanguageManager.getInstance(file.getProject()).getInjectionHost(file); - if (context != null - && context.isValid() - && !file.getProject().isDisposed() - && (myUpdateAll || new ProperTextRange(myStartOffset, myEndOffset).intersects(context.getTextRange()))) { - hosts.add(context); - } - } - hosts.addAll(elements1); - hosts.addAll(elements2); - - final PsiLanguageInjectionHost.InjectedPsiVisitor visitor = new PsiLanguageInjectionHost.InjectedPsiVisitor() { - @Override - public void visit(@NotNull PsiFile injectedPsi, @NotNull List places) { - synchronized (outInjected) { - outInjected.add(injectedPsi); - } - } - }; - if (!JobUtil.invokeConcurrentlyUnderProgress(new ArrayList(hosts), progress, false, - new Processor() { - @Override - public boolean process(PsiElement element) { - progress.checkCanceled(); - InjectedLanguageUtil.enumerate(element, myFile, false, visitor); - return true; - } - })) { - throw new ProcessCanceledException(); - } - } - - // returns false if canceled - private boolean addInjectedPsiHighlights(@NotNull final Set injectedFiles, - @NotNull final ProgressIndicator progress, - @NotNull final Collection outInfos) { - if (injectedFiles.isEmpty()) return true; - final InjectedLanguageManager injectedLanguageManager = InjectedLanguageManager.getInstance(myProject); - final TextAttributes injectedAttributes = myGlobalScheme.getAttributes(EditorColors.INJECTED_LANGUAGE_FRAGMENT); - - return JobUtil.invokeConcurrentlyUnderProgress(new ArrayList(injectedFiles), progress, isFailFastOnAcquireReadAction(), - new Processor() { - @Override - public boolean process(final PsiFile injectedPsi) { - DocumentWindow documentWindow = (DocumentWindow)PsiDocumentManager.getInstance(myProject).getCachedDocument(injectedPsi); - if (documentWindow == null) return true; - Place places = InjectedLanguageUtil.getShreds(injectedPsi); - for (PsiLanguageInjectionHost.Shred place : places) { - TextRange textRange = place.getRangeInsideHost().shiftRight(place.getHost().getTextRange().getStartOffset()); - if (textRange.isEmpty()) continue; - String desc = injectedPsi.getLanguage().getDisplayName() + ": " + injectedPsi.getText(); - HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.INJECTED_LANGUAGE_BACKGROUND, - textRange, null, desc, injectedAttributes); - info.fromInjection = true; - outInfos.add(info); - } - - HighlightInfoHolder holder = createInfoHolder(injectedPsi); - runHighlightVisitorsForInjected(injectedPsi, holder, progress); - for (int i = 0; i < holder.size(); i++) { - HighlightInfo info = holder.get(i); - final int startOffset = documentWindow.injectedToHost(info.startOffset); - final TextRange fixedTextRange = getFixedTextRange(documentWindow, startOffset); - addPatchedInfos(info, injectedPsi, documentWindow, injectedLanguageManager, fixedTextRange, outInfos); - } - holder.clear(); - highlightInjectedSyntax(injectedPsi, holder); - for (int i = 0; i < holder.size(); i++) { - HighlightInfo info = holder.get(i); - final int startOffset = info.startOffset; - final TextRange fixedTextRange = getFixedTextRange(documentWindow, startOffset); - if (fixedTextRange == null) { - info.fromInjection = true; - outInfos.add(info); - } - else { - HighlightInfo patched = new HighlightInfo(info.forcedTextAttributes, info.forcedTextAttributesKey, - info.type, fixedTextRange.getStartOffset(), fixedTextRange.getEndOffset(), - info.description, info.toolTip, info.type.getSeverity(null), - info.isAfterEndOfLine, null, false); - patched.fromInjection = true; - outInfos.add(patched); - } - } - - if (!isDumbMode()) { - List todos = new ArrayList(); - highlightTodos(injectedPsi, injectedPsi.getText(), 0, injectedPsi.getTextLength(), progress, myPriorityRange, todos, todos); - for (HighlightInfo info : todos) { - addPatchedInfos(info, injectedPsi, documentWindow, injectedLanguageManager, null, outInfos); - } - } - return true; - } - }); - } - - protected boolean isFailFastOnAcquireReadAction() { - return true; - } - - @Nullable("null means invalid") - private static TextRange getFixedTextRange(@NotNull DocumentWindow documentWindow, int startOffset) { - final TextRange fixedTextRange; - TextRange textRange = documentWindow.getHostRange(startOffset); - if (textRange == null) { - // todo[cdr] check this fix. prefix/suffix code annotation case - textRange = findNearestTextRange(documentWindow, startOffset); - if (textRange == null) return null; - final boolean isBefore = startOffset < textRange.getStartOffset(); - fixedTextRange = new ProperTextRange(isBefore ? textRange.getStartOffset() - 1 : textRange.getEndOffset(), - isBefore ? textRange.getStartOffset() : textRange.getEndOffset() + 1); - } - else { - fixedTextRange = null; - } - return fixedTextRange; - } - - private static void addPatchedInfos(@NotNull HighlightInfo info, - @NotNull PsiFile injectedPsi, - @NotNull DocumentWindow documentWindow, - @NotNull InjectedLanguageManager injectedLanguageManager, - @Nullable TextRange fixedTextRange, - @NotNull Collection out) { - ProperTextRange textRange = new ProperTextRange(info.startOffset, info.endOffset); - List editables = injectedLanguageManager.intersectWithAllEditableFragments(injectedPsi, textRange); - for (TextRange editable : editables) { - TextRange hostRange = fixedTextRange == null ? documentWindow.injectedToHost(editable) : fixedTextRange; - - boolean isAfterEndOfLine = info.isAfterEndOfLine; - if (isAfterEndOfLine) { - // convert injected afterEndOfLine to either host' afterEndOfLine or not-afterEndOfLine highlight of the injected fragment boundary - int hostEndOffset = hostRange.getEndOffset(); - int lineNumber = documentWindow.getDelegate().getLineNumber(hostEndOffset); - int hostLineEndOffset = documentWindow.getDelegate().getLineEndOffset(lineNumber); - if (hostEndOffset < hostLineEndOffset) { - // convert to non-afterEndOfLine - isAfterEndOfLine = false; - hostRange = new ProperTextRange(hostRange.getStartOffset(), hostEndOffset+1); - } - } - - HighlightInfo patched = - new HighlightInfo(info.forcedTextAttributes, info.forcedTextAttributesKey, info.type, - hostRange.getStartOffset(), hostRange.getEndOffset(), - info.description, info.toolTip, info.type.getSeverity(null), isAfterEndOfLine, null, false); - patched.setHint(info.hasHint()); - patched.setGutterIconRenderer(info.getGutterIconRenderer()); - - if (info.quickFixActionRanges != null) { - for (Pair pair : info.quickFixActionRanges) { - TextRange quickfixTextRange = pair.getSecond(); - List editableQF = injectedLanguageManager.intersectWithAllEditableFragments(injectedPsi, quickfixTextRange); - for (TextRange editableRange : editableQF) { - HighlightInfo.IntentionActionDescriptor descriptor = pair.getFirst(); - if (patched.quickFixActionRanges == null) patched.quickFixActionRanges = new ArrayList>(); - TextRange hostEditableRange = documentWindow.injectedToHost(editableRange); - patched.quickFixActionRanges.add(Pair.create(descriptor, hostEditableRange)); - } - } - } - patched.fromInjection = true; - out.add(patched); - } - } - - // finds the first nearest text range - @Nullable("null means invalid") - private static TextRange findNearestTextRange(final DocumentWindow documentWindow, final int startOffset) { - TextRange textRange = null; - for (Segment marker : documentWindow.getHostRanges()) { - TextRange curRange = ProperTextRange.create(marker); - if (curRange.getStartOffset() > startOffset && textRange != null) break; - textRange = curRange; - } - return textRange; - } - - private void runHighlightVisitorsForInjected(@NotNull PsiFile injectedPsi, - @NotNull final HighlightInfoHolder holder, - @NotNull final ProgressIndicator progress) { - HighlightVisitor[] visitors = getHighlightVisitors(); - try { - HighlightVisitor[] filtered = filterVisitors(visitors, injectedPsi); - final List elements = CollectHighlightsUtil.getElementsInRange(injectedPsi, 0, injectedPsi.getTextLength()); - for (final HighlightVisitor visitor : filtered) { - visitor.analyze(injectedPsi, true, holder, new Runnable() { - @Override - public void run() { - for (PsiElement element : elements) { - progress.checkCanceled(); - visitor.visit(element); - } - } - }); - } - } - finally { - incVisitorUsageCount(-1); - } - } - - private void highlightInjectedSyntax(final PsiFile injectedPsi, HighlightInfoHolder holder) { - List, TextRange>> tokens = InjectedLanguageUtil - .getHighlightTokens(injectedPsi); - if (tokens == null) return; - - final Language injectedLanguage = injectedPsi.getLanguage(); - Project project = injectedPsi.getProject(); - SyntaxHighlighter syntaxHighlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(injectedLanguage, project, injectedPsi.getVirtualFile()); - final TextAttributes defaultAttrs = myGlobalScheme.getAttributes(HighlighterColors.TEXT); - - for (Trinity, TextRange> token : tokens) { - ProgressManager.checkCanceled(); - IElementType tokenType = token.getFirst(); - PsiLanguageInjectionHost injectionHost = token.getSecond().getElement(); - if (injectionHost == null) continue; - TextRange textRange = token.getThird(); - TextAttributesKey[] keys = syntaxHighlighter.getTokenHighlights(tokenType); - if (textRange.getLength() == 0) continue; - - TextRange annRange = textRange.shiftRight(injectionHost.getTextRange().getStartOffset()); - // force attribute colors to override host' ones - TextAttributes attributes = null; - for(TextAttributesKey key:keys) { - TextAttributes attrs2 = myGlobalScheme.getAttributes(key); - if (attrs2 != null) { - attributes = attributes == null ? attrs2 : TextAttributes.merge(attributes, attrs2); - } - } - TextAttributes forcedAttributes; - if (attributes == null || attributes.isEmpty() || attributes.equals(defaultAttrs)) { - forcedAttributes = TextAttributes.ERASE_MARKER; - } - else { - HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.INJECTED_LANGUAGE_FRAGMENT, annRange, null,null,TextAttributes.ERASE_MARKER); - holder.add(info); - - Color back = attributes.getBackgroundColor() == null ? myGlobalScheme.getDefaultBackground() : attributes.getBackgroundColor(); - Color fore = attributes.getForegroundColor() == null ? myGlobalScheme.getDefaultForeground() : attributes.getForegroundColor(); - forcedAttributes = new TextAttributes(fore, back, attributes.getEffectColor(), attributes.getEffectType(), attributes.getFontType()); - } - - HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.INJECTED_LANGUAGE_FRAGMENT, annRange, null,null,forcedAttributes); - holder.add(info); - } - } - - private boolean isWholeFileHighlighting() { - return myUpdateAll && myStartOffset == 0 && myEndOffset == myDocument.getTextLength(); - } - - @Override - protected void applyInformationWithProgress() { - myFile.putUserData(HAS_ERROR_ELEMENT, myHasErrorElement); - - myApplyCommand.run(); - - if (myUpdateAll) { - reportErrorsToWolf(); - } - } - - @Override - @NotNull - public List getInfos() { - return new ArrayList(myHighlights); - } - - private void collectHighlights(@NotNull final List elements1, - @NotNull final Runnable after1, - @NotNull final List elements2, - @NotNull final ProgressIndicator progress, - @NotNull final HighlightVisitor[] visitors, - @NotNull final Set gotHighlights, - final boolean forceHighlightParents) { - final Set skipParentsSet = new THashSet(); - - // TODO - add color scheme to holder - final HighlightInfoHolder holder = createInfoHolder(myFile); - - final int chunkSize = Math.max(1, (elements1.size()+elements2.size()) / 100); // one percent precision is enough - - final Map ranges2markersCache = new THashMap(); - final TransferToEDTQueue myTransferToEDTQueue - = new TransferToEDTQueue("Apply highlighting results", new Processor() { - @Override - public boolean process(HighlightInfo info) { - ApplicationManager.getApplication().assertIsDispatchThread(); - final EditorColorsScheme colorsScheme = getColorsScheme(); - UpdateHighlightersUtil.addHighlighterToEditorIncrementally(myProject, myDocument, myFile, myStartOffset, myEndOffset, - info, colorsScheme, Pass.UPDATE_ALL, ranges2markersCache); - - return true; - } - }, new Condition() { - @Override - public boolean value(Object o) { - return myProject.isDisposed() || progress.isCanceled(); - } - }, 200); - - - final Runnable action = new Runnable() { - @Override - public void run() { - Stack>> nested = new Stack>>(); - boolean failed = false; - //noinspection unchecked - for (List elements : new List[]{elements1, elements2}) { - nested.clear(); - int nextLimit = chunkSize; - for (int i = 0; i < elements.size(); i++) { - PsiElement element = elements.get(i); - progress.checkCanceled(); - - PsiElement parent = element.getParent(); - if (element != myFile && !skipParentsSet.isEmpty() && element.getFirstChild() != null && skipParentsSet.contains(element)) { - skipParentsSet.add(parent); - continue; - } - - if (element instanceof PsiErrorElement) { - myHasErrorElement = true; - } - holder.clear(); - - for (final HighlightVisitor visitor : visitors) { - try { - visitor.visit(element); - } - catch (ProcessCanceledException e) { - throw e; - } - catch (IndexNotReadyException e) { - throw e; - } - catch (WolfTheProblemSolverImpl.HaveGotErrorException e) { - throw e; - } - catch (Exception e) { - if (!failed) { - LOG.error(e); - } - failed = true; - } - } - - if (i == nextLimit) { - advanceProgress(chunkSize); - nextLimit = i + chunkSize; - } - - TextRange elementRange = element.getTextRange(); - List infosForThisRange = holder.size() == 0 ? null : new ArrayList(holder.size()); - for (int j = 0; j < holder.size(); j++) { - final HighlightInfo info = holder.get(j); - assert info != null; - // have to filter out already obtained highlights - if (!gotHighlights.add(info)) continue; - boolean isError = info.getSeverity() == HighlightSeverity.ERROR; - if (isError) { - if (!forceHighlightParents) { - skipParentsSet.add(parent); - } - myErrorFound = true; - } - // if this highlight info range is exactly the same as the element range we are visiting - // that means we can clear this highlight as soon as visitors won't produce any highlights during visiting the same range next time. - info.bijective = elementRange.equalsToRange(info.startOffset, info.endOffset); - - myTransferToEDTQueue.offer(info); - infosForThisRange.add(info); - } - // include infos which we got while visiting nested elements with the same range - while (true) { - if (!nested.isEmpty() && elementRange.contains(nested.peek().first)) { - Pair> old = nested.pop(); - if (elementRange.equals(old.first)) { - if (infosForThisRange == null) { - infosForThisRange = old.second; - } - else if (old.second != null){ - infosForThisRange.addAll(old.second); - } - } - } - else { - break; - } - } - nested.push(Pair.create(elementRange, infosForThisRange)); - if (parent == null || !Comparing.equal(elementRange, parent.getTextRange())) { - killAbandonedHighlightsUnder(elementRange, infosForThisRange, progress); - } - } - advanceProgress(elements.size() - (nextLimit-chunkSize)); - if (elements == elements1) after1.run(); - } - } - }; - - analyzeByVisitors(progress, visitors, holder, 0, action); - } - - protected void killAbandonedHighlightsUnder(@NotNull final TextRange range, - @Nullable final List holder, - @NotNull final ProgressIndicator progress) { - DaemonCodeAnalyzerImpl.processHighlights(getDocument(), myProject, null, range.getStartOffset(), range.getEndOffset(), new Processor() { - @Override - public boolean process(final HighlightInfo existing) { - if (existing.bijective && - existing.group == Pass.UPDATE_ALL && - range.equalsToRange(existing.getActualStartOffset(), existing.getActualEndOffset())) { - if (holder != null) { - for (HighlightInfo created : holder) { - if (existing.equalsByActualOffset(created)) return true; - } - } - // seems that highlight info "existing" is going to disappear - // remove it earlier - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - RangeHighlighterEx highlighter = existing.highlighter; - if (!progress.isCanceled() && highlighter != null) { - highlighter.dispose(); - } - } - }); - } - return true; - } - }); - } - - private void analyzeByVisitors(@NotNull final ProgressIndicator progress, - @NotNull final HighlightVisitor[] visitors, - @NotNull final HighlightInfoHolder holder, - final int i, - @NotNull final Runnable action) { - if (i == visitors.length) { - action.run(); - } - else { - if (!visitors[i].analyze(myFile, myUpdateAll, holder, new Runnable() { - @Override - public void run() { - analyzeByVisitors(progress, visitors, holder, i+1, action); - } - })) { - cancelAndRestartDaemonLater(progress, myProject, this); - } - } - } - - @NotNull - private static HighlightVisitor[] filterVisitors(@NotNull HighlightVisitor[] highlightVisitors, @NotNull PsiFile file) { - final List visitors = new ArrayList(highlightVisitors.length); - List list = Arrays.asList(highlightVisitors); - for (HighlightVisitor visitor : DumbService.getInstance(file.getProject()).filterByDumbAwareness(list)) { - if (visitor.suitableForFile(file)) visitors.add(visitor); - } - LOG.assertTrue(!visitors.isEmpty(), list); - - HighlightVisitor[] visitorArray = visitors.toArray(new HighlightVisitor[visitors.size()]); - Arrays.sort(visitorArray, VISITOR_ORDER_COMPARATOR); - return visitorArray; - } - - static void cancelAndRestartDaemonLater(ProgressIndicator progress, final Project project, TextEditorHighlightingPass pass) throws ProcessCanceledException { - PassExecutorService.log(progress, pass, "Cancel and restart"); - progress.cancel(); - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - try { - Thread.sleep(new Random().nextInt(100)); - } - catch (InterruptedException e) { - LOG.error(e); - } - DaemonCodeAnalyzer.getInstance(project).restart(); - } - }, project.getDisposed()); - throw new ProcessCanceledException(); - } - - private boolean forceHighlightParents() { - boolean forceHighlightParents = false; - for(HighlightRangeExtension extension: Extensions.getExtensions(HighlightRangeExtension.EP_NAME)) { - if (extension.isForceHighlightParents(myFile)) { - forceHighlightParents = true; - break; - } - } - return forceHighlightParents; - } - - protected HighlightInfoHolder createInfoHolder(final PsiFile file) { - final HighlightInfoFilter[] filters = ApplicationManager.getApplication().getExtensions(HighlightInfoFilter.EXTENSION_POINT_NAME); - return new HighlightInfoHolder(file, getColorsScheme(), filters); - } - - private static void highlightTodos(@NotNull PsiFile file, - @NotNull CharSequence text, - int startOffset, - int endOffset, - @NotNull ProgressIndicator progress, - @NotNull ProperTextRange priorityRange, - @NotNull Collection result, - @NotNull Collection outsideResult) { - PsiTodoSearchHelper helper = PsiTodoSearchHelper.SERVICE.getInstance(file.getProject()); - TodoItem[] todoItems = helper.findTodoItems(file, startOffset, endOffset); - if (todoItems.length == 0) return; - - for (TodoItem todoItem : todoItems) { - progress.checkCanceled(); - TextRange range = todoItem.getTextRange(); - String description = text.subSequence(range.getStartOffset(), range.getEndOffset()).toString(); - TextAttributes attributes = todoItem.getPattern().getAttributes().getTextAttributes(); - HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.TODO, range, description, description, attributes); - assert info != null; - if (priorityRange.containsRange(info.getStartOffset(), info.getEndOffset())) { - result.add(info); - } - else { - outsideResult.add(info); - } - } - } - - private void reportErrorsToWolf() { - if (!myFile.getViewProvider().isPhysical()) return; // e.g. errors in evaluate expression - Project project = myFile.getProject(); - if (!PsiManager.getInstance(project).isInProject(myFile)) return; // do not report problems in libraries - VirtualFile file = myFile.getVirtualFile(); - if (file == null) return; - - List problems = convertToProblems(getInfos(), file, myHasErrorElement); - WolfTheProblemSolver wolf = WolfTheProblemSolver.getInstance(project); - - boolean hasErrors = DaemonCodeAnalyzerImpl.hasErrors(project, getDocument()); - if (!hasErrors || isWholeFileHighlighting()) { - wolf.reportProblems(file, problems); - } - else { - wolf.weHaveGotProblems(file, problems); - } - } - - @Override - public double getProgress() { - // do not show progress of visible highlighters update - return myUpdateAll ? super.getProgress() : -1; - } - - private static List convertToProblems(@NotNull Collection infos, - @NotNull VirtualFile file, - final boolean hasErrorElement) { - List problems = new SmartList(); - for (HighlightInfo info : infos) { - if (info.getSeverity() == HighlightSeverity.ERROR) { - Problem problem = new ProblemImpl(file, info, hasErrorElement); - problems.add(problem); - } - } - return problems; - } - - @Override - public String toString() { - return super.toString() + " updateAll="+myUpdateAll+" range=("+myStartOffset+","+myEndOffset+")"; - } -} +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.intellij.codeInsight.daemon.impl; + +import com.intellij.codeHighlighting.Pass; +import com.intellij.codeHighlighting.TextEditorHighlightingPass; +import com.intellij.codeInsight.daemon.DaemonBundle; +import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightLevelUtil; +import com.intellij.codeInsight.problems.ProblemImpl; +import com.intellij.codeInsight.problems.WolfTheProblemSolverImpl; +import com.intellij.concurrency.JobLauncher; +import com.intellij.injected.editor.DocumentWindow; +import com.intellij.lang.Language; +import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.lang.injection.InjectedLanguageManager; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.HighlighterColors; +import com.intellij.openapi.editor.RangeMarker; +import com.intellij.openapi.editor.colors.EditorColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.openapi.editor.ex.MarkupModelEx; +import com.intellij.openapi.editor.ex.RangeHighlighterEx; +import com.intellij.openapi.editor.impl.DocumentMarkupModel; +import com.intellij.openapi.editor.markup.MarkupModel; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.fileTypes.SyntaxHighlighter; +import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.project.IndexNotReadyException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.*; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.problems.Problem; +import com.intellij.problems.WolfTheProblemSolver; +import com.intellij.psi.*; +import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; +import com.intellij.psi.impl.source.tree.injected.Place; +import com.intellij.psi.search.PsiTodoSearchHelper; +import com.intellij.psi.search.TodoItem; +import com.intellij.psi.tree.IElementType; +import com.intellij.util.Processor; +import com.intellij.util.SmartList; +import com.intellij.util.containers.Stack; +import com.intellij.util.containers.TransferToEDTQueue; +import com.intellij.util.ui.UIUtil; +import gnu.trove.THashMap; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.util.*; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingPass implements DumbAware { + private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass"); + static final String PRESENTABLE_NAME = DaemonBundle.message("pass.syntax"); + private static final Key HAS_ERROR_ELEMENT = Key.create("HAS_ERROR_ELEMENT"); + private static final JobLauncher JobUtil = JobLauncher.getInstance(); + + private final int myStartOffset; + private final int myEndOffset; + private final boolean myUpdateAll; + private final ProperTextRange myPriorityRange; + private final Editor myEditor; + + private final List myHighlights = new ArrayList(); + + protected volatile boolean myHasErrorElement; + private volatile boolean myErrorFound; + private static final Comparator VISITOR_ORDER_COMPARATOR = new Comparator() { + @Override + public int compare(final HighlightVisitor o1, final HighlightVisitor o2) { + return o1.order() - o2.order(); + } + }; + private volatile Runnable myApplyCommand; + private final EditorColorsScheme myGlobalScheme; + + public GeneralHighlightingPass(@NotNull Project project, + @NotNull PsiFile file, + @NotNull Document document, + int startOffset, + int endOffset, + boolean updateAll) { + this(project, file, document, startOffset, endOffset, updateAll, new ProperTextRange(0,document.getTextLength()), null); + } + public GeneralHighlightingPass(@NotNull Project project, + @NotNull PsiFile file, + @NotNull Document document, + int startOffset, + int endOffset, + boolean updateAll, + @NotNull ProperTextRange priorityRange, + @Nullable Editor editor) { + super(project, document, PRESENTABLE_NAME, file, true); + myStartOffset = startOffset; + myEndOffset = endOffset; + myUpdateAll = updateAll; + myPriorityRange = priorityRange; + myEditor = editor; + + LOG.assertTrue(file.isValid()); + setId(Pass.UPDATE_ALL); + myHasErrorElement = !isWholeFileHighlighting() && Boolean.TRUE.equals(myFile.getUserData(HAS_ERROR_ELEMENT)); + FileStatusMap fileStatusMap = ((DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(myProject)).getFileStatusMap(); + myErrorFound = !isWholeFileHighlighting() && fileStatusMap.wasErrorFound(myDocument); + + myApplyCommand = new Runnable() { + @Override + public void run() { + ProperTextRange range = new ProperTextRange(myStartOffset, myEndOffset); + MarkupModel model = DocumentMarkupModel.forDocument(myDocument, myProject, true); + UpdateHighlightersUtil.cleanFileLevelHighlights(myProject, Pass.UPDATE_ALL,myFile); + final EditorColorsScheme colorsScheme = getColorsScheme(); + UpdateHighlightersUtil.setHighlightersInRange(myProject, myDocument, range, colorsScheme, myHighlights, (MarkupModelEx)model, Pass.UPDATE_ALL); + } + }; + + // initial guess to show correct progress in the traffic light icon + setProgressLimit(document.getTextLength()/2); // approx number of PSI elements = file length/2 + myGlobalScheme = EditorColorsManager.getInstance().getGlobalScheme(); + } + + private static final Key HIGHLIGHT_VISITOR_INSTANCE_COUNT = new Key("HIGHLIGHT_VISITOR_INSTANCE_COUNT"); + @NotNull + private HighlightVisitor[] getHighlightVisitors() { + int oldCount = incVisitorUsageCount(1); + HighlightVisitor[] highlightVisitors = createHighlightVisitors(); + if (oldCount != 0) { + HighlightVisitor[] clones = new HighlightVisitor[highlightVisitors.length]; + for (int i = 0; i < highlightVisitors.length; i++) { + HighlightVisitor highlightVisitor = highlightVisitors[i]; + clones[i] = highlightVisitor.clone(); + } + highlightVisitors = clones; + } + return highlightVisitors; + } + + protected HighlightVisitor[] createHighlightVisitors() { + return Extensions.getExtensions(HighlightVisitor.EP_HIGHLIGHT_VISITOR, myProject); + } + + // returns old value + private int incVisitorUsageCount(int delta) { + AtomicInteger count = myProject.getUserData(HIGHLIGHT_VISITOR_INSTANCE_COUNT); + if (count == null) { + count = ((UserDataHolderEx)myProject).putUserDataIfAbsent(HIGHLIGHT_VISITOR_INSTANCE_COUNT, new AtomicInteger(0)); + } + int old = count.getAndAdd(delta); + assert old + delta >= 0 : old +";" + delta; + return old; + } + + @Override + protected void collectInformationWithProgress(final ProgressIndicator progress) { + final Set gotHighlights = new THashSet(100); + final Set outsideResult = new THashSet(100); + + DaemonCodeAnalyzer daemonCodeAnalyzer = DaemonCodeAnalyzer.getInstance(myProject); + HighlightVisitor[] highlightVisitors = getHighlightVisitors(); + final List inside = new ArrayList(); + final List outside = new ArrayList(); + try { + final HighlightVisitor[] filteredVisitors = filterVisitors(highlightVisitors, myFile); + Divider.divideInsideAndOutside(myFile, myStartOffset, myEndOffset, myPriorityRange, inside, outside, + HighlightLevelUtil.AnalysisLevel.HIGHLIGHT,false); + + setProgressLimit((long)(inside.size()+outside.size())); + + final boolean forceHighlightParents = forceHighlightParents(); + + if (!isDumbMode()) { + highlightTodos(myFile, myDocument.getCharsSequence(), myStartOffset, myEndOffset, progress, myPriorityRange, gotHighlights, outsideResult); + } + + collectHighlights(inside, new Runnable() { + @Override + public void run() { + // all infos for the "injected fragment for the host which is inside" are indeed inside + // but some of the infos for the "injected fragment for the host which is outside" can be still inside + Set injectedResult = new THashSet(); + final Set injected = new THashSet(); + getInjectedPsiFiles(inside, outside, progress, injected); + if (!addInjectedPsiHighlights(injected, progress, Collections.synchronizedSet(injectedResult))) throw new ProcessCanceledException(); + final List injectionsOutside = new ArrayList(gotHighlights.size()); + + Set result; + synchronized (injectedResult) { + // sync here because all writes happened in another thread + result = injectedResult; + } + for (HighlightInfo info : result) { + if (myPriorityRange.containsRange(info.getStartOffset(), info.getEndOffset())) { + gotHighlights.add(info); + } + else { + // nonconditionally apply injected results regardless whether they are in myStartOffset,myEndOffset + injectionsOutside.add(info); + } + } + + if (outsideResult.isEmpty() && injectionsOutside.isEmpty()) { + return; // apply only result (by default apply command) and only within inside + } + + final ProperTextRange priorityIntersection = myPriorityRange.intersection(new TextRange(myStartOffset, myEndOffset)); + if ((!inside.isEmpty() || !gotHighlights.isEmpty()) && priorityIntersection != null) { // do not apply when there were no elements to highlight + // clear infos found in visible area to avoid applying them twice + final List toApplyInside = new ArrayList(gotHighlights); + myHighlights.addAll(toApplyInside); + gotHighlights.clear(); + gotHighlights.addAll(outsideResult); + final long modificationStamp = myDocument.getModificationStamp(); + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + if (myProject.isDisposed() || modificationStamp != myDocument.getModificationStamp()) return; + MarkupModel markupModel = DocumentMarkupModel.forDocument(myDocument, myProject, true); + + UpdateHighlightersUtil.setHighlightersInRange(myProject, myDocument, priorityIntersection, getColorsScheme(), toApplyInside, + (MarkupModelEx)markupModel, Pass.UPDATE_ALL); + if (myEditor != null) { + new ShowAutoImportPass(myProject, myFile, myEditor).applyInformationToEditor(); + } + } + }); + } + + myApplyCommand = new Runnable() { + @Override + public void run() { + ProperTextRange range = new ProperTextRange(myStartOffset, myEndOffset); + + List toApply = new ArrayList(); + for (HighlightInfo info : gotHighlights) { + if (!range.containsRange(info.getStartOffset(), info.getEndOffset())) continue; + if (!myPriorityRange.containsRange(info.getStartOffset(), info.getEndOffset())) { + toApply.add(info); + } + } + toApply.addAll(injectionsOutside); + + UpdateHighlightersUtil.setHighlightersOutsideRange(myProject, myDocument, toApply, getColorsScheme(), + myStartOffset, myEndOffset, myPriorityRange, Pass.UPDATE_ALL); + } + }; + } + }, outside, progress, filteredVisitors, gotHighlights, forceHighlightParents); + + if (myUpdateAll) { + ((DaemonCodeAnalyzerImpl)daemonCodeAnalyzer).getFileStatusMap().setErrorFoundFlag(myDocument, myErrorFound); + } + } + finally { + incVisitorUsageCount(-1); + } + myHighlights.addAll(gotHighlights); + } + + private void getInjectedPsiFiles(@NotNull final List elements1, + @NotNull final List elements2, + @NotNull final ProgressIndicator progress, + @NotNull final Set outInjected) { + List injected = InjectedLanguageUtil.getCachedInjectedDocuments(myFile); + Collection hosts = new THashSet(elements1.size() + elements2.size() + injected.size()); + + //rehighlight all injected PSI regardless the range, + //since change in one place can lead to invalidation of injected PSI in (completely) other place. + for (DocumentWindow documentRange : injected) { + progress.checkCanceled(); + if (!documentRange.isValid()) continue; + PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(documentRange); + if (file == null) continue; + PsiElement context = InjectedLanguageManager.getInstance(file.getProject()).getInjectionHost(file); + if (context != null + && context.isValid() + && !file.getProject().isDisposed() + && (myUpdateAll || new ProperTextRange(myStartOffset, myEndOffset).intersects(context.getTextRange()))) { + hosts.add(context); + } + } + hosts.addAll(elements1); + hosts.addAll(elements2); + + final PsiLanguageInjectionHost.InjectedPsiVisitor visitor = new PsiLanguageInjectionHost.InjectedPsiVisitor() { + @Override + public void visit(@NotNull PsiFile injectedPsi, @NotNull List places) { + synchronized (outInjected) { + outInjected.add(injectedPsi); + } + } + }; + if (!JobUtil.invokeConcurrentlyUnderProgress(new ArrayList(hosts), progress, false, + new Processor() { + @Override + public boolean process(PsiElement element) { + progress.checkCanceled(); + InjectedLanguageUtil.enumerate(element, myFile, false, visitor); + return true; + } + })) { + throw new ProcessCanceledException(); + } + } + + // returns false if canceled + private boolean addInjectedPsiHighlights(@NotNull final Set injectedFiles, + @NotNull final ProgressIndicator progress, + @NotNull final Collection outInfos) { + if (injectedFiles.isEmpty()) return true; + final InjectedLanguageManager injectedLanguageManager = InjectedLanguageManager.getInstance(myProject); + final TextAttributes injectedAttributes = myGlobalScheme.getAttributes(EditorColors.INJECTED_LANGUAGE_FRAGMENT); + + return JobUtil.invokeConcurrentlyUnderProgress(new ArrayList(injectedFiles), progress, isFailFastOnAcquireReadAction(), + new Processor() { + @Override + public boolean process(final PsiFile injectedPsi) { + DocumentWindow documentWindow = (DocumentWindow)PsiDocumentManager.getInstance(myProject).getCachedDocument(injectedPsi); + if (documentWindow == null) return true; + Place places = InjectedLanguageUtil.getShreds(injectedPsi); + for (PsiLanguageInjectionHost.Shred place : places) { + TextRange textRange = place.getRangeInsideHost().shiftRight(place.getHost().getTextRange().getStartOffset()); + if (textRange.isEmpty()) continue; + String desc = injectedPsi.getLanguage().getDisplayName() + ": " + injectedPsi.getText(); + HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.INJECTED_LANGUAGE_BACKGROUND, + textRange, null, desc, injectedAttributes); + info.fromInjection = true; + outInfos.add(info); + } + + HighlightInfoHolder holder = createInfoHolder(injectedPsi); + runHighlightVisitorsForInjected(injectedPsi, holder, progress); + for (int i = 0; i < holder.size(); i++) { + HighlightInfo info = holder.get(i); + final int startOffset = documentWindow.injectedToHost(info.startOffset); + final TextRange fixedTextRange = getFixedTextRange(documentWindow, startOffset); + addPatchedInfos(info, injectedPsi, documentWindow, injectedLanguageManager, fixedTextRange, outInfos); + } + holder.clear(); + highlightInjectedSyntax(injectedPsi, holder); + for (int i = 0; i < holder.size(); i++) { + HighlightInfo info = holder.get(i); + final int startOffset = info.startOffset; + final TextRange fixedTextRange = getFixedTextRange(documentWindow, startOffset); + if (fixedTextRange == null) { + info.fromInjection = true; + outInfos.add(info); + } + else { + HighlightInfo patched = new HighlightInfo(info.forcedTextAttributes, info.forcedTextAttributesKey, + info.type, fixedTextRange.getStartOffset(), fixedTextRange.getEndOffset(), + info.description, info.toolTip, info.type.getSeverity(null), + info.isAfterEndOfLine, null, false); + patched.fromInjection = true; + outInfos.add(patched); + } + } + + if (!isDumbMode()) { + List todos = new ArrayList(); + highlightTodos(injectedPsi, injectedPsi.getText(), 0, injectedPsi.getTextLength(), progress, myPriorityRange, todos, todos); + for (HighlightInfo info : todos) { + addPatchedInfos(info, injectedPsi, documentWindow, injectedLanguageManager, null, outInfos); + } + } + return true; + } + }); + } + + protected boolean isFailFastOnAcquireReadAction() { + return true; + } + + @Nullable("null means invalid") + private static TextRange getFixedTextRange(@NotNull DocumentWindow documentWindow, int startOffset) { + final TextRange fixedTextRange; + TextRange textRange = documentWindow.getHostRange(startOffset); + if (textRange == null) { + // todo[cdr] check this fix. prefix/suffix code annotation case + textRange = findNearestTextRange(documentWindow, startOffset); + if (textRange == null) return null; + final boolean isBefore = startOffset < textRange.getStartOffset(); + fixedTextRange = new ProperTextRange(isBefore ? textRange.getStartOffset() - 1 : textRange.getEndOffset(), + isBefore ? textRange.getStartOffset() : textRange.getEndOffset() + 1); + } + else { + fixedTextRange = null; + } + return fixedTextRange; + } + + private static void addPatchedInfos(@NotNull HighlightInfo info, + @NotNull PsiFile injectedPsi, + @NotNull DocumentWindow documentWindow, + @NotNull InjectedLanguageManager injectedLanguageManager, + @Nullable TextRange fixedTextRange, + @NotNull Collection out) { + ProperTextRange textRange = new ProperTextRange(info.startOffset, info.endOffset); + List editables = injectedLanguageManager.intersectWithAllEditableFragments(injectedPsi, textRange); + for (TextRange editable : editables) { + TextRange hostRange = fixedTextRange == null ? documentWindow.injectedToHost(editable) : fixedTextRange; + + boolean isAfterEndOfLine = info.isAfterEndOfLine; + if (isAfterEndOfLine) { + // convert injected afterEndOfLine to either host' afterEndOfLine or not-afterEndOfLine highlight of the injected fragment boundary + int hostEndOffset = hostRange.getEndOffset(); + int lineNumber = documentWindow.getDelegate().getLineNumber(hostEndOffset); + int hostLineEndOffset = documentWindow.getDelegate().getLineEndOffset(lineNumber); + if (hostEndOffset < hostLineEndOffset) { + // convert to non-afterEndOfLine + isAfterEndOfLine = false; + hostRange = new ProperTextRange(hostRange.getStartOffset(), hostEndOffset+1); + } + } + + HighlightInfo patched = + new HighlightInfo(info.forcedTextAttributes, info.forcedTextAttributesKey, info.type, + hostRange.getStartOffset(), hostRange.getEndOffset(), + info.description, info.toolTip, info.type.getSeverity(null), isAfterEndOfLine, null, false); + patched.setHint(info.hasHint()); + patched.setGutterIconRenderer(info.getGutterIconRenderer()); + + if (info.quickFixActionRanges != null) { + for (Pair pair : info.quickFixActionRanges) { + TextRange quickfixTextRange = pair.getSecond(); + List editableQF = injectedLanguageManager.intersectWithAllEditableFragments(injectedPsi, quickfixTextRange); + for (TextRange editableRange : editableQF) { + HighlightInfo.IntentionActionDescriptor descriptor = pair.getFirst(); + if (patched.quickFixActionRanges == null) patched.quickFixActionRanges = new ArrayList>(); + TextRange hostEditableRange = documentWindow.injectedToHost(editableRange); + patched.quickFixActionRanges.add(Pair.create(descriptor, hostEditableRange)); + } + } + } + patched.fromInjection = true; + out.add(patched); + } + } + + // finds the first nearest text range + @Nullable("null means invalid") + private static TextRange findNearestTextRange(final DocumentWindow documentWindow, final int startOffset) { + TextRange textRange = null; + for (Segment marker : documentWindow.getHostRanges()) { + TextRange curRange = ProperTextRange.create(marker); + if (curRange.getStartOffset() > startOffset && textRange != null) break; + textRange = curRange; + } + return textRange; + } + + private void runHighlightVisitorsForInjected(@NotNull PsiFile injectedPsi, + @NotNull final HighlightInfoHolder holder, + @NotNull final ProgressIndicator progress) { + HighlightVisitor[] visitors = getHighlightVisitors(); + try { + HighlightVisitor[] filtered = filterVisitors(visitors, injectedPsi); + final List elements = CollectHighlightsUtil.getElementsInRange(injectedPsi, 0, injectedPsi.getTextLength()); + for (final HighlightVisitor visitor : filtered) { + visitor.analyze(injectedPsi, true, holder, new Runnable() { + @Override + public void run() { + for (PsiElement element : elements) { + progress.checkCanceled(); + visitor.visit(element); + } + } + }); + } + } + finally { + incVisitorUsageCount(-1); + } + } + + private void highlightInjectedSyntax(final PsiFile injectedPsi, HighlightInfoHolder holder) { + List, TextRange>> tokens = InjectedLanguageUtil + .getHighlightTokens(injectedPsi); + if (tokens == null) return; + + final Language injectedLanguage = injectedPsi.getLanguage(); + Project project = injectedPsi.getProject(); + SyntaxHighlighter syntaxHighlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(injectedLanguage, project, injectedPsi.getVirtualFile()); + final TextAttributes defaultAttrs = myGlobalScheme.getAttributes(HighlighterColors.TEXT); + + for (Trinity, TextRange> token : tokens) { + ProgressManager.checkCanceled(); + IElementType tokenType = token.getFirst(); + PsiLanguageInjectionHost injectionHost = token.getSecond().getElement(); + if (injectionHost == null) continue; + TextRange textRange = token.getThird(); + TextAttributesKey[] keys = syntaxHighlighter.getTokenHighlights(tokenType); + if (textRange.getLength() == 0) continue; + + TextRange annRange = textRange.shiftRight(injectionHost.getTextRange().getStartOffset()); + // force attribute colors to override host' ones + TextAttributes attributes = null; + for(TextAttributesKey key:keys) { + TextAttributes attrs2 = myGlobalScheme.getAttributes(key); + if (attrs2 != null) { + attributes = attributes == null ? attrs2 : TextAttributes.merge(attributes, attrs2); + } + } + TextAttributes forcedAttributes; + if (attributes == null || attributes.isEmpty() || attributes.equals(defaultAttrs)) { + forcedAttributes = TextAttributes.ERASE_MARKER; + } + else { + HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.INJECTED_LANGUAGE_FRAGMENT, annRange, null,null,TextAttributes.ERASE_MARKER); + holder.add(info); + + Color back = attributes.getBackgroundColor() == null ? myGlobalScheme.getDefaultBackground() : attributes.getBackgroundColor(); + Color fore = attributes.getForegroundColor() == null ? myGlobalScheme.getDefaultForeground() : attributes.getForegroundColor(); + forcedAttributes = new TextAttributes(fore, back, attributes.getEffectColor(), attributes.getEffectType(), attributes.getFontType()); + } + + HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.INJECTED_LANGUAGE_FRAGMENT, annRange, null,null,forcedAttributes); + holder.add(info); + } + } + + private boolean isWholeFileHighlighting() { + return myUpdateAll && myStartOffset == 0 && myEndOffset == myDocument.getTextLength(); + } + + @Override + protected void applyInformationWithProgress() { + myFile.putUserData(HAS_ERROR_ELEMENT, myHasErrorElement); + + myApplyCommand.run(); + + if (myUpdateAll) { + reportErrorsToWolf(); + } + } + + @Override + @NotNull + public List getInfos() { + return new ArrayList(myHighlights); + } + + private void collectHighlights(@NotNull final List elements1, + @NotNull final Runnable after1, + @NotNull final List elements2, + @NotNull final ProgressIndicator progress, + @NotNull final HighlightVisitor[] visitors, + @NotNull final Set gotHighlights, + final boolean forceHighlightParents) { + final Set skipParentsSet = new THashSet(); + + // TODO - add color scheme to holder + final HighlightInfoHolder holder = createInfoHolder(myFile); + + final int chunkSize = Math.max(1, (elements1.size()+elements2.size()) / 100); // one percent precision is enough + + final Map ranges2markersCache = new THashMap(); + final TransferToEDTQueue myTransferToEDTQueue + = new TransferToEDTQueue("Apply highlighting results", new Processor() { + @Override + public boolean process(HighlightInfo info) { + ApplicationManager.getApplication().assertIsDispatchThread(); + final EditorColorsScheme colorsScheme = getColorsScheme(); + UpdateHighlightersUtil.addHighlighterToEditorIncrementally(myProject, myDocument, myFile, myStartOffset, myEndOffset, + info, colorsScheme, Pass.UPDATE_ALL, ranges2markersCache); + + return true; + } + }, new Condition() { + @Override + public boolean value(Object o) { + return myProject.isDisposed() || progress.isCanceled(); + } + }, 200); + + + final Runnable action = new Runnable() { + @Override + public void run() { + Stack>> nested = new Stack>>(); + boolean failed = false; + //noinspection unchecked + for (List elements : new List[]{elements1, elements2}) { + nested.clear(); + int nextLimit = chunkSize; + for (int i = 0; i < elements.size(); i++) { + PsiElement element = elements.get(i); + progress.checkCanceled(); + + PsiElement parent = element.getParent(); + if (element != myFile && !skipParentsSet.isEmpty() && element.getFirstChild() != null && skipParentsSet.contains(element)) { + skipParentsSet.add(parent); + continue; + } + + if (element instanceof PsiErrorElement) { + myHasErrorElement = true; + } + holder.clear(); + + for (final HighlightVisitor visitor : visitors) { + try { + visitor.visit(element); + } + catch (ProcessCanceledException e) { + throw e; + } + catch (IndexNotReadyException e) { + throw e; + } + catch (WolfTheProblemSolverImpl.HaveGotErrorException e) { + throw e; + } + catch (Exception e) { + if (!failed) { + LOG.error(e); + } + failed = true; + } + } + + if (i == nextLimit) { + advanceProgress(chunkSize); + nextLimit = i + chunkSize; + } + + TextRange elementRange = element.getTextRange(); + List infosForThisRange = holder.size() == 0 ? null : new ArrayList(holder.size()); + for (int j = 0; j < holder.size(); j++) { + final HighlightInfo info = holder.get(j); + assert info != null; + // have to filter out already obtained highlights + if (!gotHighlights.add(info)) continue; + boolean isError = info.getSeverity() == HighlightSeverity.ERROR; + if (isError) { + if (!forceHighlightParents) { + skipParentsSet.add(parent); + } + myErrorFound = true; + } + // if this highlight info range is exactly the same as the element range we are visiting + // that means we can clear this highlight as soon as visitors won't produce any highlights during visiting the same range next time. + info.bijective = elementRange.equalsToRange(info.startOffset, info.endOffset); + + myTransferToEDTQueue.offer(info); + infosForThisRange.add(info); + } + // include infos which we got while visiting nested elements with the same range + while (true) { + if (!nested.isEmpty() && elementRange.contains(nested.peek().first)) { + Pair> old = nested.pop(); + if (elementRange.equals(old.first)) { + if (infosForThisRange == null) { + infosForThisRange = old.second; + } + else if (old.second != null){ + infosForThisRange.addAll(old.second); + } + } + } + else { + break; + } + } + nested.push(Pair.create(elementRange, infosForThisRange)); + if (parent == null || !Comparing.equal(elementRange, parent.getTextRange())) { + killAbandonedHighlightsUnder(elementRange, infosForThisRange, progress); + } + } + advanceProgress(elements.size() - (nextLimit-chunkSize)); + if (elements == elements1) after1.run(); + } + } + }; + + analyzeByVisitors(progress, visitors, holder, 0, action); + } + + protected void killAbandonedHighlightsUnder(@NotNull final TextRange range, + @Nullable final List holder, + @NotNull final ProgressIndicator progress) { + DaemonCodeAnalyzerImpl.processHighlights(getDocument(), myProject, null, range.getStartOffset(), range.getEndOffset(), new Processor() { + @Override + public boolean process(final HighlightInfo existing) { + if (existing.bijective && + existing.group == Pass.UPDATE_ALL && + range.equalsToRange(existing.getActualStartOffset(), existing.getActualEndOffset())) { + if (holder != null) { + for (HighlightInfo created : holder) { + if (existing.equalsByActualOffset(created)) return true; + } + } + // seems that highlight info "existing" is going to disappear + // remove it earlier + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + RangeHighlighterEx highlighter = existing.highlighter; + if (!progress.isCanceled() && highlighter != null) { + highlighter.dispose(); + } + } + }); + } + return true; + } + }); + } + + private void analyzeByVisitors(@NotNull final ProgressIndicator progress, + @NotNull final HighlightVisitor[] visitors, + @NotNull final HighlightInfoHolder holder, + final int i, + @NotNull final Runnable action) { + if (i == visitors.length) { + action.run(); + } + else { + if (!visitors[i].analyze(myFile, myUpdateAll, holder, new Runnable() { + @Override + public void run() { + analyzeByVisitors(progress, visitors, holder, i+1, action); + } + })) { + cancelAndRestartDaemonLater(progress, myProject, this); + } + } + } + + @NotNull + private static HighlightVisitor[] filterVisitors(@NotNull HighlightVisitor[] highlightVisitors, @NotNull PsiFile file) { + final List visitors = new ArrayList(highlightVisitors.length); + List list = Arrays.asList(highlightVisitors); + for (HighlightVisitor visitor : DumbService.getInstance(file.getProject()).filterByDumbAwareness(list)) { + if (visitor.suitableForFile(file)) visitors.add(visitor); + } + LOG.assertTrue(!visitors.isEmpty(), list); + + HighlightVisitor[] visitorArray = visitors.toArray(new HighlightVisitor[visitors.size()]); + Arrays.sort(visitorArray, VISITOR_ORDER_COMPARATOR); + return visitorArray; + } + + static void cancelAndRestartDaemonLater(ProgressIndicator progress, final Project project, TextEditorHighlightingPass pass) throws ProcessCanceledException { + PassExecutorService.log(progress, pass, "Cancel and restart"); + progress.cancel(); + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(new Random().nextInt(100)); + } + catch (InterruptedException e) { + LOG.error(e); + } + DaemonCodeAnalyzer.getInstance(project).restart(); + } + }, project.getDisposed()); + throw new ProcessCanceledException(); + } + + private boolean forceHighlightParents() { + boolean forceHighlightParents = false; + for(HighlightRangeExtension extension: Extensions.getExtensions(HighlightRangeExtension.EP_NAME)) { + if (extension.isForceHighlightParents(myFile)) { + forceHighlightParents = true; + break; + } + } + return forceHighlightParents; + } + + protected HighlightInfoHolder createInfoHolder(final PsiFile file) { + final HighlightInfoFilter[] filters = ApplicationManager.getApplication().getExtensions(HighlightInfoFilter.EXTENSION_POINT_NAME); + return new HighlightInfoHolder(file, getColorsScheme(), filters); + } + + private static void highlightTodos(@NotNull PsiFile file, + @NotNull CharSequence text, + int startOffset, + int endOffset, + @NotNull ProgressIndicator progress, + @NotNull ProperTextRange priorityRange, + @NotNull Collection result, + @NotNull Collection outsideResult) { + PsiTodoSearchHelper helper = PsiTodoSearchHelper.SERVICE.getInstance(file.getProject()); + TodoItem[] todoItems = helper.findTodoItems(file, startOffset, endOffset); + if (todoItems.length == 0) return; + + for (TodoItem todoItem : todoItems) { + progress.checkCanceled(); + TextRange range = todoItem.getTextRange(); + String description = text.subSequence(range.getStartOffset(), range.getEndOffset()).toString(); + TextAttributes attributes = todoItem.getPattern().getAttributes().getTextAttributes(); + HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.TODO, range, description, description, attributes); + assert info != null; + if (priorityRange.containsRange(info.getStartOffset(), info.getEndOffset())) { + result.add(info); + } + else { + outsideResult.add(info); + } + } + } + + private void reportErrorsToWolf() { + if (!myFile.getViewProvider().isPhysical()) return; // e.g. errors in evaluate expression + Project project = myFile.getProject(); + if (!PsiManager.getInstance(project).isInProject(myFile)) return; // do not report problems in libraries + VirtualFile file = myFile.getVirtualFile(); + if (file == null) return; + + List problems = convertToProblems(getInfos(), file, myHasErrorElement); + WolfTheProblemSolver wolf = WolfTheProblemSolver.getInstance(project); + + boolean hasErrors = DaemonCodeAnalyzerImpl.hasErrors(project, getDocument()); + if (!hasErrors || isWholeFileHighlighting()) { + wolf.reportProblems(file, problems); + } + else { + wolf.weHaveGotProblems(file, problems); + } + } + + @Override + public double getProgress() { + // do not show progress of visible highlighters update + return myUpdateAll ? super.getProgress() : -1; + } + + private static List convertToProblems(@NotNull Collection infos, + @NotNull VirtualFile file, + final boolean hasErrorElement) { + List problems = new SmartList(); + for (HighlightInfo info : infos) { + if (info.getSeverity() == HighlightSeverity.ERROR) { + Problem problem = new ProblemImpl(file, info, hasErrorElement); + problems.add(problem); + } + } + return problems; + } + + @Override + public String toString() { + return super.toString() + " updateAll="+myUpdateAll+" range=("+myStartOffset+","+myEndOffset+")"; + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/FileReferenceQuickFixProvider.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/FileReferenceQuickFixProvider.java index 3f70b7cf2545..25443fb894d8 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/FileReferenceQuickFixProvider.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/FileReferenceQuickFixProvider.java @@ -1,178 +1,178 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.codeInsight.daemon.quickFix; - -import com.intellij.codeInsight.daemon.impl.HighlightInfo; -import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction; -import com.intellij.codeInsight.daemon.impl.quickfix.RenameFileFix; -import com.intellij.codeInspection.LocalQuickFix; -import com.intellij.ide.fileTemplates.FileTemplate; -import com.intellij.ide.fileTemplates.FileTemplateManager; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.FileTypeManager; -import com.intellij.openapi.fileTypes.UnknownFileType; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtil; -import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFileSystemItem; -import com.intellij.psi.PsiNamedElement; -import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference; -import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -/** - * @author Maxim.Mossienko - */ -public class FileReferenceQuickFixProvider { - private FileReferenceQuickFixProvider() {} - - public static List registerQuickFix(final HighlightInfo info, final FileReference reference) { - final FileReferenceSet fileReferenceSet = reference.getFileReferenceSet(); - int index = reference.getIndex(); - - if (index < 0) return Collections.emptyList(); - final String newFileName = reference.getFileNameToCreate(); - - // check if we could create file - if (newFileName.length() == 0 || - newFileName.indexOf('\\') != -1 || - newFileName.indexOf('*') != -1 || - newFileName.indexOf('?') != -1 || - SystemInfo.isWindows && newFileName.indexOf(':') != -1) { - return Collections.emptyList(); - } - - PsiFileSystemItem context = null; - if(index > 0) { - context = fileReferenceSet.getReference(index - 1).resolve(); - } else { // index == 0 - final Collection defaultContexts = fileReferenceSet.getDefaultContexts(); - if (defaultContexts.isEmpty()) { - return Collections.emptyList(); - } - - PsiElement element = reference.getElement(); - Module module = element != null ? ModuleUtil.findModuleForPsiElement(element) : null; - - for (PsiFileSystemItem defaultContext : defaultContexts) { - if (defaultContext != null) { - final VirtualFile virtualFile = defaultContext.getVirtualFile(); - if (virtualFile != null && defaultContext.isDirectory() && virtualFile.isInLocalFileSystem()) { - if (context == null) { - context = defaultContext; - } - else if (module != null && module == getModuleForContext(defaultContext)) { - // fixes IDEA-64156 - // todo: fix it on PsiFileReferenceHelper level in 10.X - context = defaultContext; - break; - } - } - } - } - if (context == null && ApplicationManager.getApplication().isUnitTestMode()) { - context = defaultContexts.iterator().next(); - } - } - if (context == null) return Collections.emptyList(); - - final VirtualFile virtualFile = context.getVirtualFile(); - if (virtualFile == null) return Collections.emptyList(); - - final PsiDirectory directory = context.getManager().findDirectory(virtualFile); - if (directory == null) return Collections.emptyList(); - - if (fileReferenceSet.isCaseSensitive()) { - final PsiElement psiElement = reference.innerSingleResolve(false); - - if (psiElement instanceof PsiNamedElement) { - final String existingElementName = ((PsiNamedElement)psiElement).getName(); - - final RenameFileReferenceIntentionAction renameRefAction = new RenameFileReferenceIntentionAction(existingElementName, reference); - QuickFixAction.registerQuickFixAction(info, renameRefAction); - - final RenameFileFix renameFileFix = new RenameFileFix(newFileName); - QuickFixAction.registerQuickFixAction(info, renameFileFix); - return Arrays.asList(renameRefAction, renameFileFix); - } - } - - final boolean isdirectory; - - if (!reference.isLast()) { - // directory - try { - directory.checkCreateSubdirectory(newFileName); - } catch(IncorrectOperationException ex) { - return Collections.emptyList(); - } - isdirectory = true; - } else { - FileType ft = FileTypeManager.getInstance().getFileTypeByFileName(newFileName); - if (ft instanceof UnknownFileType) return Collections.emptyList(); - - try { - directory.checkCreateFile(newFileName); - } catch(IncorrectOperationException ex) { - return Collections.emptyList(); - } - - isdirectory = false; - } - - final CreateFileFix action = new CreateFileFix(isdirectory, newFileName, directory) { - @Override - protected String getFileText() { - if (!isdirectory) { - String templateName = reference.getNewFileTemplateName(); - if (templateName != null) { - FileTemplate template = FileTemplateManager.getInstance().getTemplate(templateName); - if (template != null) { - try { - return template.getText(FileTemplateManager.getInstance().getDefaultProperties(directory.getProject())); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - } - } - return super.getFileText(); - } - }; - QuickFixAction.registerQuickFixAction(info, action); - return Arrays.asList(action); - } - - - @Nullable - private static Module getModuleForContext(@NotNull PsiFileSystemItem context) { - VirtualFile file = context.getVirtualFile(); - return file != null ? ModuleUtil.findModuleForFile(file, context.getProject()) : null; - } -} +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.intellij.codeInsight.daemon.quickFix; + +import com.intellij.codeInsight.daemon.impl.HighlightInfo; +import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction; +import com.intellij.codeInsight.daemon.impl.quickfix.RenameFileFix; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.ide.fileTemplates.FileTemplate; +import com.intellij.ide.fileTemplates.FileTemplateManager; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypeManager; +import com.intellij.openapi.fileTypes.UnknownFileType; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFileSystemItem; +import com.intellij.psi.PsiNamedElement; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * @author Maxim.Mossienko + */ +public class FileReferenceQuickFixProvider { + private FileReferenceQuickFixProvider() {} + + public static List registerQuickFix(final HighlightInfo info, final FileReference reference) { + final FileReferenceSet fileReferenceSet = reference.getFileReferenceSet(); + int index = reference.getIndex(); + + if (index < 0) return Collections.emptyList(); + final String newFileName = reference.getFileNameToCreate(); + + // check if we could create file + if (newFileName.length() == 0 || + newFileName.indexOf('\\') != -1 || + newFileName.indexOf('*') != -1 || + newFileName.indexOf('?') != -1 || + SystemInfo.isWindows && newFileName.indexOf(':') != -1) { + return Collections.emptyList(); + } + + PsiFileSystemItem context = null; + if(index > 0) { + context = fileReferenceSet.getReference(index - 1).resolve(); + } else { // index == 0 + final Collection defaultContexts = fileReferenceSet.getDefaultContexts(); + if (defaultContexts.isEmpty()) { + return Collections.emptyList(); + } + + PsiElement element = reference.getElement(); + Module module = element != null ? ModuleUtil.findModuleForPsiElement(element) : null; + + for (PsiFileSystemItem defaultContext : defaultContexts) { + if (defaultContext != null) { + final VirtualFile virtualFile = defaultContext.getVirtualFile(); + if (virtualFile != null && defaultContext.isDirectory() && virtualFile.isInLocalFileSystem()) { + if (context == null) { + context = defaultContext; + } + else if (module != null && module == getModuleForContext(defaultContext)) { + // fixes IDEA-64156 + // todo: fix it on PsiFileReferenceHelper level in 10.X + context = defaultContext; + break; + } + } + } + } + if (context == null && ApplicationManager.getApplication().isUnitTestMode()) { + context = defaultContexts.iterator().next(); + } + } + if (context == null) return Collections.emptyList(); + + final VirtualFile virtualFile = context.getVirtualFile(); + if (virtualFile == null) return Collections.emptyList(); + + final PsiDirectory directory = context.getManager().findDirectory(virtualFile); + if (directory == null) return Collections.emptyList(); + + if (fileReferenceSet.isCaseSensitive()) { + final PsiElement psiElement = reference.innerSingleResolve(false); + + if (psiElement instanceof PsiNamedElement) { + final String existingElementName = ((PsiNamedElement)psiElement).getName(); + + final RenameFileReferenceIntentionAction renameRefAction = new RenameFileReferenceIntentionAction(existingElementName, reference); + QuickFixAction.registerQuickFixAction(info, renameRefAction); + + final RenameFileFix renameFileFix = new RenameFileFix(newFileName); + QuickFixAction.registerQuickFixAction(info, renameFileFix); + return Arrays.asList(renameRefAction, renameFileFix); + } + } + + final boolean isdirectory; + + if (!reference.isLast()) { + // directory + try { + directory.checkCreateSubdirectory(newFileName); + } catch(IncorrectOperationException ex) { + return Collections.emptyList(); + } + isdirectory = true; + } else { + FileType ft = FileTypeManager.getInstance().getFileTypeByFileName(newFileName); + if (ft instanceof UnknownFileType) return Collections.emptyList(); + + try { + directory.checkCreateFile(newFileName); + } catch(IncorrectOperationException ex) { + return Collections.emptyList(); + } + + isdirectory = false; + } + + final CreateFileFix action = new CreateFileFix(isdirectory, newFileName, directory) { + @Override + protected String getFileText() { + if (!isdirectory) { + String templateName = reference.getNewFileTemplateName(); + if (templateName != null) { + FileTemplate template = FileTemplateManager.getInstance().getTemplate(templateName); + if (template != null) { + try { + return template.getText(FileTemplateManager.getInstance().getDefaultProperties(directory.getProject())); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + } + } + return super.getFileText(); + } + }; + QuickFixAction.registerQuickFixAction(info, action); + return Arrays.asList(action); + } + + + @Nullable + private static Module getModuleForContext(@NotNull PsiFileSystemItem context) { + VirtualFile file = context.getVirtualFile(); + return file != null ? ModuleUtil.findModuleForFile(file, context.getProject()) : null; + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java index c7aee0629817..86ea6e97d1f3 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java @@ -1,126 +1,126 @@ -/* - * Copyright 2000-2010 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES 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.editorActions; - -import com.intellij.codeInsight.AutoPopupController; -import com.intellij.codeInsight.completion.CodeCompletionHandlerBase; -import com.intellij.codeInsight.completion.CompletionPhase; -import com.intellij.codeInsight.completion.CompletionType; -import com.intellij.codeInsight.completion.impl.CompletionServiceImpl; -import com.intellij.codeInsight.lookup.LookupManager; -import com.intellij.codeInsight.lookup.impl.LookupImpl; -import com.intellij.openapi.application.ApplicationManager; -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.IndexNotReadyException; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiFile; -import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; -import org.jetbrains.annotations.NotNull; - -/** - * @author peter - */ -public class CompletionAutoPopupHandler extends TypedHandlerDelegate { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.editorActions.CompletionAutoPopupHandler"); - public static volatile boolean ourTestingAutopopup = false; - - @Override - public Result checkAutoPopup(char charTyped, final Project project, final Editor editor, final PsiFile file) { - CompletionPhase oldPhase = CompletionServiceImpl.getCompletionPhase(); - if (oldPhase instanceof CompletionPhase.EmptyAutoPopup && ((CompletionPhase.EmptyAutoPopup)oldPhase).editor != editor) { - CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion); - } - - - if (oldPhase instanceof CompletionPhase.CommittingDocuments && ((CompletionPhase.CommittingDocuments)oldPhase).restartCompletion()) { - return Result.STOP; - } - - LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor); - if (lookup != null) { - if (editor.getSelectionModel().hasSelection()) { - lookup.performGuardedChange(new Runnable() { - @Override - public void run() { - EditorModificationUtil.deleteSelectedText(editor); - } - }); - } - return Result.STOP; - } - - if (Character.isLetter(charTyped) || charTyped == '_') { - AutoPopupController.getInstance(project).scheduleAutoPopup(editor, null); - return Result.STOP; - } - - if (CompletionServiceImpl.isPhase(CompletionPhase.EmptyAutoPopup.class, CompletionPhase.CommittingDocuments.class)) { - CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion); - } - return Result.CONTINUE; - } - - public static void invokeCompletion(CompletionType completionType, - boolean autopopup, - Project project, Editor editor, int time, boolean restart) { - if (editor.isDisposed()) return; - - // retrieve the injected file from scratch since our typing might have destroyed the old one completely - Editor topLevelEditor = InjectedLanguageUtil.getTopLevelEditor(editor); - PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(topLevelEditor.getDocument()); - if (file == null) return; - - PsiFile topLevelFile = InjectedLanguageUtil.getTopLevelFile(file); - if (!PsiDocumentManager.getInstance(project).isCommitted(editor.getDocument())) { - LOG.error("Non-committed document"); - PsiDocumentManager.getInstance(project).commitAllDocuments(); - } - Editor newEditor = InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(topLevelEditor, topLevelFile); - try { - new CodeCompletionHandlerBase(completionType, false, autopopup, false).invokeCompletion(project, newEditor, time, false, restart); - } - catch (IndexNotReadyException ignored) { - } - } - - public static void runLaterWithCommitted(@NotNull final Project project, - @NotNull final Document document, - @NotNull final Runnable runnable) { - final long beforeStamp = document.getModificationStamp(); - PsiDocumentManager.getInstance(project).performWhenAllCommitted(new Runnable() { - @Override - public void run() { - // later because we may end up in write action here if there was a synchronous commit - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - if (beforeStamp != document.getModificationStamp()) { - // no luck, will try later - runLaterWithCommitted(project, document, runnable); - } - else { - runnable.run(); - } - } - }, project.getDisposed()); - } - }); - } -} +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.editorActions; + +import com.intellij.codeInsight.AutoPopupController; +import com.intellij.codeInsight.completion.CodeCompletionHandlerBase; +import com.intellij.codeInsight.completion.CompletionPhase; +import com.intellij.codeInsight.completion.CompletionType; +import com.intellij.codeInsight.completion.impl.CompletionServiceImpl; +import com.intellij.codeInsight.lookup.LookupManager; +import com.intellij.codeInsight.lookup.impl.LookupImpl; +import com.intellij.openapi.application.ApplicationManager; +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.IndexNotReadyException; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; +import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; +import org.jetbrains.annotations.NotNull; + +/** + * @author peter + */ +public class CompletionAutoPopupHandler extends TypedHandlerDelegate { + private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.editorActions.CompletionAutoPopupHandler"); + public static volatile boolean ourTestingAutopopup = false; + + @Override + public Result checkAutoPopup(char charTyped, final Project project, final Editor editor, final PsiFile file) { + CompletionPhase oldPhase = CompletionServiceImpl.getCompletionPhase(); + if (oldPhase instanceof CompletionPhase.EmptyAutoPopup && ((CompletionPhase.EmptyAutoPopup)oldPhase).editor != editor) { + CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion); + } + + + if (oldPhase instanceof CompletionPhase.CommittingDocuments && ((CompletionPhase.CommittingDocuments)oldPhase).restartCompletion()) { + return Result.STOP; + } + + LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor); + if (lookup != null) { + if (editor.getSelectionModel().hasSelection()) { + lookup.performGuardedChange(new Runnable() { + @Override + public void run() { + EditorModificationUtil.deleteSelectedText(editor); + } + }); + } + return Result.STOP; + } + + if (Character.isLetter(charTyped) || charTyped == '_') { + AutoPopupController.getInstance(project).scheduleAutoPopup(editor, null); + return Result.STOP; + } + + if (CompletionServiceImpl.isPhase(CompletionPhase.EmptyAutoPopup.class, CompletionPhase.CommittingDocuments.class)) { + CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion); + } + return Result.CONTINUE; + } + + public static void invokeCompletion(CompletionType completionType, + boolean autopopup, + Project project, Editor editor, int time, boolean restart) { + if (editor.isDisposed()) return; + + // retrieve the injected file from scratch since our typing might have destroyed the old one completely + Editor topLevelEditor = InjectedLanguageUtil.getTopLevelEditor(editor); + PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(topLevelEditor.getDocument()); + if (file == null) return; + + PsiFile topLevelFile = InjectedLanguageUtil.getTopLevelFile(file); + if (!PsiDocumentManager.getInstance(project).isCommitted(editor.getDocument())) { + LOG.error("Non-committed document"); + PsiDocumentManager.getInstance(project).commitAllDocuments(); + } + Editor newEditor = InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(topLevelEditor, topLevelFile); + try { + new CodeCompletionHandlerBase(completionType, false, autopopup, false).invokeCompletion(project, newEditor, time, false, restart); + } + catch (IndexNotReadyException ignored) { + } + } + + public static void runLaterWithCommitted(@NotNull final Project project, + @NotNull final Document document, + @NotNull final Runnable runnable) { + final long beforeStamp = document.getModificationStamp(); + PsiDocumentManager.getInstance(project).performWhenAllCommitted(new Runnable() { + @Override + public void run() { + // later because we may end up in write action here if there was a synchronous commit + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + if (beforeStamp != document.getModificationStamp()) { + // no luck, will try later + runLaterWithCommitted(project, document, runnable); + } + else { + runnable.run(); + } + } + }, project.getDisposed()); + } + }); + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditAction.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditAction.java index d12551c73db5..d94322f2a73d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditAction.java @@ -1,140 +1,140 @@ -/* - * Copyright 2006 Sascha Weinreuter - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.intention.impl; - -import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.codeInsight.intention.LowPriorityAction; -import com.intellij.injected.editor.DocumentWindow; -import com.intellij.lang.Language; -import com.intellij.lang.injection.InjectedLanguageManager; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.popup.Balloon; -import com.intellij.openapi.util.*; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.*; -import java.util.List; - -/** - * "Quick Edit Language" intention action that provides an editor which shows an injected language - * fragment's complete prefix and suffix in non-editable areas and allows to edit the fragment - * without having to consider any additional escaping rules (e.g. when editing regexes in String - * literals). - * - * @author Gregory Shrago - * @author Konstantin Bulenkov - */ -public class QuickEditAction implements IntentionAction, LowPriorityAction { - public static final Key QUICK_EDIT_HANDLER = Key.create("QUICK_EDIT_HANDLER"); - public static final Key EDIT_ACTION_AVAILABLE = Key.create("EDIT_ACTION_AVAILABLE"); - private String myLastLanguageName; - - @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return getRangePair(file, editor) != null; - } - - @Nullable - protected Pair getRangePair(final PsiFile file, final Editor editor) { - final int offset = editor.getCaretModel().getOffset(); - final PsiLanguageInjectionHost host = - PsiTreeUtil.getParentOfType(file.findElementAt(offset), PsiLanguageInjectionHost.class, false); - if (host == null || ElementManipulators.getManipulator(host) == null) return null; - final List> injections = InjectedLanguageManager.getInstance(host.getProject()).getInjectedPsiFiles(host); - if (injections == null || injections.isEmpty()) return null; - final int offsetInElement = offset - host.getTextRange().getStartOffset(); - final Pair rangePair = ContainerUtil.find(injections, new Condition>() { - @Override - public boolean value(final Pair pair) { - return pair.second.containsRange(offsetInElement, offsetInElement); - } - }); - if (rangePair != null) { - final Language language = rangePair.first.getContainingFile().getLanguage(); - final Object action = language.getUserData(EDIT_ACTION_AVAILABLE); - if (action != null && action.equals(false)) return null; - - myLastLanguageName = language.getDisplayName(); - } - return rangePair; - } - - @Override - public void invoke(@NotNull final Project project, final Editor editor, PsiFile file) throws IncorrectOperationException { - final int offset = editor.getCaretModel().getOffset(); - final Pair pair = getRangePair(file, editor); - assert pair != null; - final PsiFile injectedFile = (PsiFile)pair.first; - final int injectedOffset = ((DocumentWindow)PsiDocumentManager.getInstance(project).getDocument(injectedFile)).hostToInjected(offset); - QuickEditHandler handler = getHandler(project, injectedFile, editor, file); - if (!ApplicationManager.getApplication().isUnitTestMode()) { - handler.navigate(injectedOffset); - } - } - - @Override - public boolean startInWriteAction() { - return false; - } - - @NotNull - private QuickEditHandler getHandler(Project project, PsiFile injectedFile, Editor editor, PsiFile origFile) { - QuickEditHandler handler = injectedFile.getUserData(QUICK_EDIT_HANDLER); - if (handler != null && handler.isValid()) { - return handler; - } - handler = new QuickEditHandler(project, injectedFile, origFile, editor, this); - injectedFile.putUserData(QUICK_EDIT_HANDLER, handler); - return handler; - } - - protected boolean isShowInBalloon() { - return false; - } - - @Nullable - protected JComponent createBalloonComponent(PsiFile file, Ref ref) { - return null; - } - - @Override - @NotNull - public String getText() { - return "Edit "+ StringUtil.notNullize(myLastLanguageName, "Injected")+" Fragment"; - } - - @Override - @NotNull - public String getFamilyName() { - return "Edit Injected Fragment"; - } - - public static Balloon.Position getBalloonPosition(Editor editor) { - final int line = editor.getCaretModel().getVisualPosition().line; - final Rectangle area = editor.getScrollingModel().getVisibleArea(); - int startLine = area.y / editor.getLineHeight() + 1; - return (line - startLine) * editor.getLineHeight() < 200 ? Balloon.Position.below : Balloon.Position.above; - } -} +/* + * Copyright 2006 Sascha Weinreuter + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.intention.impl; + +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInsight.intention.LowPriorityAction; +import com.intellij.injected.editor.DocumentWindow; +import com.intellij.lang.Language; +import com.intellij.lang.injection.InjectedLanguageManager; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.Balloon; +import com.intellij.openapi.util.*; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.util.List; + +/** + * "Quick Edit Language" intention action that provides an editor which shows an injected language + * fragment's complete prefix and suffix in non-editable areas and allows to edit the fragment + * without having to consider any additional escaping rules (e.g. when editing regexes in String + * literals). + * + * @author Gregory Shrago + * @author Konstantin Bulenkov + */ +public class QuickEditAction implements IntentionAction, LowPriorityAction { + public static final Key QUICK_EDIT_HANDLER = Key.create("QUICK_EDIT_HANDLER"); + public static final Key EDIT_ACTION_AVAILABLE = Key.create("EDIT_ACTION_AVAILABLE"); + private String myLastLanguageName; + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + return getRangePair(file, editor) != null; + } + + @Nullable + protected Pair getRangePair(final PsiFile file, final Editor editor) { + final int offset = editor.getCaretModel().getOffset(); + final PsiLanguageInjectionHost host = + PsiTreeUtil.getParentOfType(file.findElementAt(offset), PsiLanguageInjectionHost.class, false); + if (host == null || ElementManipulators.getManipulator(host) == null) return null; + final List> injections = InjectedLanguageManager.getInstance(host.getProject()).getInjectedPsiFiles(host); + if (injections == null || injections.isEmpty()) return null; + final int offsetInElement = offset - host.getTextRange().getStartOffset(); + final Pair rangePair = ContainerUtil.find(injections, new Condition>() { + @Override + public boolean value(final Pair pair) { + return pair.second.containsRange(offsetInElement, offsetInElement); + } + }); + if (rangePair != null) { + final Language language = rangePair.first.getContainingFile().getLanguage(); + final Object action = language.getUserData(EDIT_ACTION_AVAILABLE); + if (action != null && action.equals(false)) return null; + + myLastLanguageName = language.getDisplayName(); + } + return rangePair; + } + + @Override + public void invoke(@NotNull final Project project, final Editor editor, PsiFile file) throws IncorrectOperationException { + final int offset = editor.getCaretModel().getOffset(); + final Pair pair = getRangePair(file, editor); + assert pair != null; + final PsiFile injectedFile = (PsiFile)pair.first; + final int injectedOffset = ((DocumentWindow)PsiDocumentManager.getInstance(project).getDocument(injectedFile)).hostToInjected(offset); + QuickEditHandler handler = getHandler(project, injectedFile, editor, file); + if (!ApplicationManager.getApplication().isUnitTestMode()) { + handler.navigate(injectedOffset); + } + } + + @Override + public boolean startInWriteAction() { + return false; + } + + @NotNull + private QuickEditHandler getHandler(Project project, PsiFile injectedFile, Editor editor, PsiFile origFile) { + QuickEditHandler handler = injectedFile.getUserData(QUICK_EDIT_HANDLER); + if (handler != null && handler.isValid()) { + return handler; + } + handler = new QuickEditHandler(project, injectedFile, origFile, editor, this); + injectedFile.putUserData(QUICK_EDIT_HANDLER, handler); + return handler; + } + + protected boolean isShowInBalloon() { + return false; + } + + @Nullable + protected JComponent createBalloonComponent(PsiFile file, Ref ref) { + return null; + } + + @Override + @NotNull + public String getText() { + return "Edit "+ StringUtil.notNullize(myLastLanguageName, "Injected")+" Fragment"; + } + + @Override + @NotNull + public String getFamilyName() { + return "Edit Injected Fragment"; + } + + public static Balloon.Position getBalloonPosition(Editor editor) { + final int line = editor.getCaretModel().getVisualPosition().line; + final Rectangle area = editor.getScrollingModel().getVisibleArea(); + int startLine = area.y / editor.getLineHeight() + 1; + return (line - startLine) * editor.getLineHeight() < 200 ? Balloon.Position.below : Balloon.Position.above; + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/macro/BaseCompleteMacro.java b/platform/lang-impl/src/com/intellij/codeInsight/template/macro/BaseCompleteMacro.java index 2a491361f27a..009ec240496b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/macro/BaseCompleteMacro.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/macro/BaseCompleteMacro.java @@ -1,166 +1,166 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.codeInsight.template.macro; - -import com.intellij.codeInsight.lookup.*; -import com.intellij.codeInsight.template.*; -import com.intellij.codeInsight.template.Result; -import com.intellij.codeInsight.template.impl.TemplateManagerImpl; -import com.intellij.codeInsight.template.impl.TemplateState; -import com.intellij.openapi.application.*; -import com.intellij.openapi.command.CommandProcessor; -import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiFile; -import com.intellij.psi.util.PsiUtilBase; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; - -public abstract class BaseCompleteMacro extends Macro { - private final String myName; - - protected BaseCompleteMacro(@NonNls String name) { - myName = name; - } - - @Override - public String getName() { - return myName; - } - - @Override - public String getPresentableName() { - return myName + "()"; - } - - @Override - @NotNull - public String getDefaultValue() { - return "a"; - } - - @Override - public final Result calculateResult(@NotNull Expression[] params, final ExpressionContext context) { - return new InvokeActionResult( - new Runnable() { - @Override - public void run() { - invokeCompletion(context); - } - } - ); - } - - private void invokeCompletion(final ExpressionContext context) { - final Project project = context.getProject(); - final Editor editor = context.getEditor(); - - final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project); - Runnable runnable = new Runnable() { - @Override - public void run() { - if (project.isDisposed() || editor.isDisposed() || psiFile == null || !psiFile.isValid()) return; - - CommandProcessor.getInstance().executeCommand(project, new Runnable() { - @Override - public void run() { - invokeCompletionHandler(project, editor); - Lookup lookup = LookupManager.getInstance(project).getActiveLookup(); - - if (lookup != null) { - lookup.addLookupListener(new MyLookupListener(context)); - } - else { - considerNextTab(editor); - } - } - }, "", null); - } - }; - if (ApplicationManager.getApplication().isUnitTestMode()) { - runnable.run(); - } else { - ApplicationManager.getApplication().invokeLater(runnable); - } - } - - private static void considerNextTab(Editor editor) { - TemplateState templateState = TemplateManagerImpl.getTemplateState(editor); - if (templateState != null) { - TextRange range = templateState.getCurrentVariableRange(); - if (range != null && range.getLength() > 0 && editor.getCaretModel().getOffset() == range.getEndOffset()) { - templateState.nextTab(); - } - } - } - - protected abstract void invokeCompletionHandler(Project project, Editor editor); - - private static class MyLookupListener extends LookupAdapter { - private final ExpressionContext myContext; - - public MyLookupListener(@NotNull ExpressionContext context) { - myContext = context; - } - - @Override - public void itemSelected(LookupEvent event) { - LookupElement item = event.getItem(); - if (item == null) return; - - char c = event.getCompletionChar(); - if (!LookupEvent.isSpecialCompletionChar(c)) { - return; - } - - for(TemplateCompletionProcessor processor: Extensions.getExtensions(TemplateCompletionProcessor.EP_NAME)) { - if (!processor.nextTabOnItemSelected(myContext, item)) { - return; - } - } - - final Project project = myContext.getProject(); - if (project == null) { - return; - } - - Runnable runnable = new Runnable() { - @Override - public void run() { - new WriteCommandAction(project) { - @Override - protected void run(com.intellij.openapi.application.Result result) throws Throwable { - Editor editor = myContext.getEditor(); - if (editor != null) { - considerNextTab(editor); - } - } - }.execute(); - } - }; - if (ApplicationManager.getApplication().isUnitTestMode()) { - runnable.run(); - } else { - ApplicationManager.getApplication().invokeLater(runnable, ModalityState.current(), project.getDisposed()); - } - - } - } -} +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.intellij.codeInsight.template.macro; + +import com.intellij.codeInsight.lookup.*; +import com.intellij.codeInsight.template.*; +import com.intellij.codeInsight.template.Result; +import com.intellij.codeInsight.template.impl.TemplateManagerImpl; +import com.intellij.codeInsight.template.impl.TemplateState; +import com.intellij.openapi.application.*; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiUtilBase; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +public abstract class BaseCompleteMacro extends Macro { + private final String myName; + + protected BaseCompleteMacro(@NonNls String name) { + myName = name; + } + + @Override + public String getName() { + return myName; + } + + @Override + public String getPresentableName() { + return myName + "()"; + } + + @Override + @NotNull + public String getDefaultValue() { + return "a"; + } + + @Override + public final Result calculateResult(@NotNull Expression[] params, final ExpressionContext context) { + return new InvokeActionResult( + new Runnable() { + @Override + public void run() { + invokeCompletion(context); + } + } + ); + } + + private void invokeCompletion(final ExpressionContext context) { + final Project project = context.getProject(); + final Editor editor = context.getEditor(); + + final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project); + Runnable runnable = new Runnable() { + @Override + public void run() { + if (project.isDisposed() || editor.isDisposed() || psiFile == null || !psiFile.isValid()) return; + + CommandProcessor.getInstance().executeCommand(project, new Runnable() { + @Override + public void run() { + invokeCompletionHandler(project, editor); + Lookup lookup = LookupManager.getInstance(project).getActiveLookup(); + + if (lookup != null) { + lookup.addLookupListener(new MyLookupListener(context)); + } + else { + considerNextTab(editor); + } + } + }, "", null); + } + }; + if (ApplicationManager.getApplication().isUnitTestMode()) { + runnable.run(); + } else { + ApplicationManager.getApplication().invokeLater(runnable); + } + } + + private static void considerNextTab(Editor editor) { + TemplateState templateState = TemplateManagerImpl.getTemplateState(editor); + if (templateState != null) { + TextRange range = templateState.getCurrentVariableRange(); + if (range != null && range.getLength() > 0 && editor.getCaretModel().getOffset() == range.getEndOffset()) { + templateState.nextTab(); + } + } + } + + protected abstract void invokeCompletionHandler(Project project, Editor editor); + + private static class MyLookupListener extends LookupAdapter { + private final ExpressionContext myContext; + + public MyLookupListener(@NotNull ExpressionContext context) { + myContext = context; + } + + @Override + public void itemSelected(LookupEvent event) { + LookupElement item = event.getItem(); + if (item == null) return; + + char c = event.getCompletionChar(); + if (!LookupEvent.isSpecialCompletionChar(c)) { + return; + } + + for(TemplateCompletionProcessor processor: Extensions.getExtensions(TemplateCompletionProcessor.EP_NAME)) { + if (!processor.nextTabOnItemSelected(myContext, item)) { + return; + } + } + + final Project project = myContext.getProject(); + if (project == null) { + return; + } + + Runnable runnable = new Runnable() { + @Override + public void run() { + new WriteCommandAction(project) { + @Override + protected void run(com.intellij.openapi.application.Result result) throws Throwable { + Editor editor = myContext.getEditor(); + if (editor != null) { + considerNextTab(editor); + } + } + }.execute(); + } + }; + if (ApplicationManager.getApplication().isUnitTestMode()) { + runnable.run(); + } else { + ApplicationManager.getApplication().invokeLater(runnable, ModalityState.current(), project.getDisposed()); + } + + } + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/macro/ClassNameCompleteMacro.java b/platform/lang-impl/src/com/intellij/codeInsight/template/macro/ClassNameCompleteMacro.java index 1d894317c7b1..94b7f564ce31 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/macro/ClassNameCompleteMacro.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/macro/ClassNameCompleteMacro.java @@ -1,33 +1,33 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.codeInsight.template.macro; - -import com.intellij.codeInsight.completion.CodeCompletionHandlerBase; -import com.intellij.codeInsight.completion.CompletionType; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; - -public class ClassNameCompleteMacro extends BaseCompleteMacro { - public ClassNameCompleteMacro() { - super("classNameComplete"); - } - - @Override - protected void invokeCompletionHandler(Project project, Editor editor) { - new CodeCompletionHandlerBase(CompletionType.BASIC, false, false, true).invokeCompletion(project, editor, 2); - } +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.intellij.codeInsight.template.macro; + +import com.intellij.codeInsight.completion.CodeCompletionHandlerBase; +import com.intellij.codeInsight.completion.CompletionType; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; + +public class ClassNameCompleteMacro extends BaseCompleteMacro { + public ClassNameCompleteMacro() { + super("classNameComplete"); + } + + @Override + protected void invokeCompletionHandler(Project project, Editor editor) { + new CodeCompletionHandlerBase(CompletionType.BASIC, false, false, true).invokeCompletion(project, editor, 2); + } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/macro/CompleteMacro.java b/platform/lang-impl/src/com/intellij/codeInsight/template/macro/CompleteMacro.java index d8a479dff22c..14a341d14ae8 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/macro/CompleteMacro.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/macro/CompleteMacro.java @@ -1,35 +1,35 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.codeInsight.template.macro; - -import com.intellij.codeInsight.completion.CodeCompletionHandlerBase; -import com.intellij.codeInsight.completion.CompletionType; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; - -public class CompleteMacro extends BaseCompleteMacro { - public CompleteMacro() { - super("complete"); - } - - @Override - protected void invokeCompletionHandler(Project project, Editor editor) { - new CodeCompletionHandlerBase(CompletionType.BASIC, ApplicationManager.getApplication().isUnitTestMode(), false, true) - .invokeCompletion(project, editor, 1); - } +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.intellij.codeInsight.template.macro; + +import com.intellij.codeInsight.completion.CodeCompletionHandlerBase; +import com.intellij.codeInsight.completion.CompletionType; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; + +public class CompleteMacro extends BaseCompleteMacro { + public CompleteMacro() { + super("complete"); + } + + @Override + protected void invokeCompletionHandler(Project project, Editor editor) { + new CodeCompletionHandlerBase(CompletionType.BASIC, ApplicationManager.getApplication().isUnitTestMode(), false, true) + .invokeCompletion(project, editor, 1); + } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/macro/CompleteSmartMacro.java b/platform/lang-impl/src/com/intellij/codeInsight/template/macro/CompleteSmartMacro.java index 709c285dd898..64e3fa2dd3fc 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/macro/CompleteSmartMacro.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/macro/CompleteSmartMacro.java @@ -1,33 +1,33 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.codeInsight.template.macro; - -import com.intellij.codeInsight.completion.CodeCompletionHandlerBase; -import com.intellij.codeInsight.completion.CompletionType; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; - -public class CompleteSmartMacro extends BaseCompleteMacro { - public CompleteSmartMacro() { - super("completeSmart"); - } - - @Override - protected void invokeCompletionHandler(Project project, Editor editor) { - new CodeCompletionHandlerBase(CompletionType.SMART).invokeCompletion(project, editor, 1); - } +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.intellij.codeInsight.template.macro; + +import com.intellij.codeInsight.completion.CodeCompletionHandlerBase; +import com.intellij.codeInsight.completion.CompletionType; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; + +public class CompleteSmartMacro extends BaseCompleteMacro { + public CompleteSmartMacro() { + super("completeSmart"); + } + + @Override + protected void invokeCompletionHandler(Project project, Editor editor) { + new CodeCompletionHandlerBase(CompletionType.SMART).invokeCompletion(project, editor, 1); + } } \ No newline at end of file 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 138d7fa0f75a..36417036642d 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/actions/InspectionListCellRenderer.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/actions/InspectionListCellRenderer.java @@ -1,117 +1,117 @@ -/* - * Copyright 2000-2010 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES 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.actions; - -import com.intellij.codeInspection.InspectionProfileEntry; -import com.intellij.codeInspection.ex.LocalInspectionToolWrapper; -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.ui.SimpleColoredComponent; -import com.intellij.ui.SimpleTextAttributes; -import com.intellij.ui.speedSearch.SpeedSearchUtil; -import com.intellij.util.text.Matcher; -import com.intellij.util.text.MatcherHolder; -import com.intellij.util.ui.EmptyIcon; -import com.intellij.util.ui.UIUtil; - -import javax.swing.*; -import java.awt.*; - -/** -* @author Konstantin Bulenkov -*/ -@SuppressWarnings({"GtkPreferredJComboBoxRenderer"}) -public class InspectionListCellRenderer extends DefaultListCellRenderer implements MatcherHolder { - private static final Icon EMPTY_ICON = EmptyIcon.ICON_18; - - private Matcher myMatcher; - private final SimpleTextAttributes SELECTED; - private final SimpleTextAttributes PLAIN; - - public InspectionListCellRenderer() { - SELECTED = new SimpleTextAttributes(UIUtil.getListSelectionBackground(), - UIUtil.getListSelectionForeground(), - Color.RED, - SimpleTextAttributes.STYLE_PLAIN); - PLAIN = new SimpleTextAttributes(UIUtil.getListBackground(), - UIUtil.getListForeground(), - Color.RED, - SimpleTextAttributes.STYLE_PLAIN); - } - - - public Component getListCellRendererComponent(JList list, Object value, int index, boolean sel, boolean focus) { - final JPanel panel = new JPanel(new BorderLayout()); - panel.setOpaque(true); - - final Color bg = sel ? UIUtil.getListSelectionBackground() : UIUtil.getListBackground(); - final Color fg = sel ? UIUtil.getListSelectionForeground() : UIUtil.getListForeground(); - panel.setBackground(bg); - panel.setForeground(fg); - - SimpleTextAttributes attr = sel ? SELECTED : PLAIN; - if (value instanceof InspectionProfileEntry) { - final InspectionProfileEntry tool = (InspectionProfileEntry)value; - final SimpleColoredComponent c = new SimpleColoredComponent(); - SpeedSearchUtil.appendColoredFragmentForMatcher(" " + tool.getDisplayName(), c, attr, myMatcher, bg, sel); - panel.add(c, BorderLayout.WEST); - - final SimpleColoredComponent group = new SimpleColoredComponent(); - SpeedSearchUtil.appendColoredFragmentForMatcher(tool.getGroupDisplayName() + " ", group, attr, myMatcher, bg, sel); - final JPanel right = new JPanel(new BorderLayout()); - right.setBackground(bg); - right.setForeground(fg); - right.add(group, BorderLayout.CENTER); - final JLabel icon = new JLabel(getIcon(tool)); - icon.setBackground(bg); - icon.setForeground(fg); - right.add(icon, BorderLayout.EAST); - panel.add(right, BorderLayout.EAST); - } - else { - // E.g. "..." item - return value == ChooseByNameBase.NON_PREFIX_SEPARATOR ? ChooseByNameBase.renderNonPrefixSeparatorComponent(UIUtil.getListBackground()) : - super.getListCellRendererComponent(list, value, index, sel, focus); - } - - return panel; - } - - private static Icon getIcon(InspectionProfileEntry tool) { - Icon icon = null; - if (tool instanceof LocalInspectionToolWrapper) { - final Language language = Language.findLanguageByID(((LocalInspectionToolWrapper)tool).getLanguage()); - if (language != null) { - final LanguageFileType fileType = language.getAssociatedFileType(); - if (fileType != null) { - icon = fileType.getIcon(); - } - } - } - if (icon == null) { - icon = UnknownFileType.INSTANCE.getIcon(); - } - assert icon != null; - return icon; - } - - @Override - public void setPatternMatcher(Matcher matcher) { - myMatcher = matcher; - } -} +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.actions; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.intellij.codeInspection.ex.LocalInspectionToolWrapper; +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.ui.SimpleColoredComponent; +import com.intellij.ui.SimpleTextAttributes; +import com.intellij.ui.speedSearch.SpeedSearchUtil; +import com.intellij.util.text.Matcher; +import com.intellij.util.text.MatcherHolder; +import com.intellij.util.ui.EmptyIcon; +import com.intellij.util.ui.UIUtil; + +import javax.swing.*; +import java.awt.*; + +/** +* @author Konstantin Bulenkov +*/ +@SuppressWarnings({"GtkPreferredJComboBoxRenderer"}) +public class InspectionListCellRenderer extends DefaultListCellRenderer implements MatcherHolder { + private static final Icon EMPTY_ICON = EmptyIcon.ICON_18; + + private Matcher myMatcher; + private final SimpleTextAttributes SELECTED; + private final SimpleTextAttributes PLAIN; + + public InspectionListCellRenderer() { + SELECTED = new SimpleTextAttributes(UIUtil.getListSelectionBackground(), + UIUtil.getListSelectionForeground(), + Color.RED, + SimpleTextAttributes.STYLE_PLAIN); + PLAIN = new SimpleTextAttributes(UIUtil.getListBackground(), + UIUtil.getListForeground(), + Color.RED, + SimpleTextAttributes.STYLE_PLAIN); + } + + + public Component getListCellRendererComponent(JList list, Object value, int index, boolean sel, boolean focus) { + final JPanel panel = new JPanel(new BorderLayout()); + panel.setOpaque(true); + + final Color bg = sel ? UIUtil.getListSelectionBackground() : UIUtil.getListBackground(); + final Color fg = sel ? UIUtil.getListSelectionForeground() : UIUtil.getListForeground(); + panel.setBackground(bg); + panel.setForeground(fg); + + SimpleTextAttributes attr = sel ? SELECTED : PLAIN; + if (value instanceof InspectionProfileEntry) { + final InspectionProfileEntry tool = (InspectionProfileEntry)value; + final SimpleColoredComponent c = new SimpleColoredComponent(); + SpeedSearchUtil.appendColoredFragmentForMatcher(" " + tool.getDisplayName(), c, attr, myMatcher, bg, sel); + panel.add(c, BorderLayout.WEST); + + final SimpleColoredComponent group = new SimpleColoredComponent(); + SpeedSearchUtil.appendColoredFragmentForMatcher(tool.getGroupDisplayName() + " ", group, attr, myMatcher, bg, sel); + final JPanel right = new JPanel(new BorderLayout()); + right.setBackground(bg); + right.setForeground(fg); + right.add(group, BorderLayout.CENTER); + final JLabel icon = new JLabel(getIcon(tool)); + icon.setBackground(bg); + icon.setForeground(fg); + right.add(icon, BorderLayout.EAST); + panel.add(right, BorderLayout.EAST); + } + else { + // E.g. "..." item + return value == ChooseByNameBase.NON_PREFIX_SEPARATOR ? ChooseByNameBase.renderNonPrefixSeparatorComponent(UIUtil.getListBackground()) : + super.getListCellRendererComponent(list, value, index, sel, focus); + } + + return panel; + } + + private static Icon getIcon(InspectionProfileEntry tool) { + Icon icon = null; + if (tool instanceof LocalInspectionToolWrapper) { + final Language language = Language.findLanguageByID(((LocalInspectionToolWrapper)tool).getLanguage()); + if (language != null) { + final LanguageFileType fileType = language.getAssociatedFileType(); + if (fileType != null) { + icon = fileType.getIcon(); + } + } + } + if (icon == null) { + icon = UnknownFileType.INSTANCE.getIcon(); + } + assert icon != null; + return icon; + } + + @Override + public void setPatternMatcher(Matcher matcher) { + myMatcher = matcher; + } +} diff --git a/platform/lang-impl/src/com/intellij/execution/DefaultExecutionTargetProvider.java b/platform/lang-impl/src/com/intellij/execution/DefaultExecutionTargetProvider.java index 596991d8459c..b4aa30713f72 100644 --- a/platform/lang-impl/src/com/intellij/execution/DefaultExecutionTargetProvider.java +++ b/platform/lang-impl/src/com/intellij/execution/DefaultExecutionTargetProvider.java @@ -1,30 +1,30 @@ -/* - * 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.execution; - -import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NotNull; - -import java.util.Collections; -import java.util.List; - -public class DefaultExecutionTargetProvider extends ExecutionTargetProvider { - @NotNull - @Override - public List getTargets(@NotNull Project project, @NotNull RunnerAndConfigurationSettings configuration) { - return Collections.singletonList(DefaultExecutionTarget.INSTANCE); - } -} +/* + * 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.execution; + +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +public class DefaultExecutionTargetProvider extends ExecutionTargetProvider { + @NotNull + @Override + public List getTargets(@NotNull Project project, @NotNull RunnerAndConfigurationSettings configuration) { + return Collections.singletonList(DefaultExecutionTarget.INSTANCE); + } +} diff --git a/platform/lang-impl/src/com/intellij/execution/ExecutionTargetManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/ExecutionTargetManagerImpl.java index fdf08f10cf6a..d0170430613e 100644 --- a/platform/lang-impl/src/com/intellij/execution/ExecutionTargetManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/ExecutionTargetManagerImpl.java @@ -1,188 +1,188 @@ -/* - * 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.execution; - -import com.intellij.execution.impl.RunManagerImpl; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.*; -import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.project.Project; -import com.intellij.util.containers.ContainerUtil; -import org.jdom.Element; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - - -@State(name = "ExecutionTargetManager", storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE, scheme = StorageScheme.DEFAULT)}) -public class ExecutionTargetManagerImpl extends ExecutionTargetManager implements ProjectComponent, PersistentStateComponent { - @NotNull private final Project myProject; - @NotNull private final Object myActiveTargetLock = new Object(); - @Nullable private ExecutionTarget myActiveTarget; - - @Nullable private String mySavedActiveTargetId; - - public ExecutionTargetManagerImpl(@NotNull Project project) { - myProject = project; - } - - @Override - public void projectOpened() { - } - - @Override - public void projectClosed() { - } - - @Override - public Element getState() { - synchronized (myActiveTargetLock) { - Element state = new Element("state"); - - String id = myActiveTarget == null ? mySavedActiveTargetId : myActiveTarget.getId(); - if (id != null) state.setAttribute("SELECTED_TARGET", id); - return state; - } - } - - @Override - public void loadState(Element state) { - synchronized (myActiveTargetLock) { - if (myActiveTarget == null && mySavedActiveTargetId == null) { - mySavedActiveTargetId = state.getAttributeValue("SELECTED_TARGET"); - } - } - } - - @Override - public void initComponent() { - RunManagerImpl.getInstanceImpl(myProject).addRunManagerListener(new RunManagerAdapter() { - @Override - public void runConfigurationChanged(@NotNull RunnerAndConfigurationSettings settings) { - if (settings == RunManager.getInstance(myProject).getSelectedConfiguration()) { - updateActiveTarget(settings); - } - } - - @Override - public void runConfigurationSelected() { - updateActiveTarget(); - } - }); - } - - @Override - public void disposeComponent() { - } - - @NotNull - @Override - public String getComponentName() { - return ExecutionTargetManager.class.getName(); - } - - @NotNull - @Override - public ExecutionTarget getActiveTarget() { - ApplicationManager.getApplication().assertReadAccessAllowed(); - synchronized (myActiveTargetLock) { - if (myActiveTarget == null) { - updateActiveTarget(); - } - return myActiveTarget; - } - } - - @Override - public void setActiveTarget(@NotNull ExecutionTarget target) { - ApplicationManager.getApplication().assertIsDispatchThread(); - synchronized (myActiveTargetLock) { - updateActiveTarget(RunManager.getInstance(myProject).getSelectedConfiguration(), target); - } - } - - private void updateActiveTarget() { - updateActiveTarget(RunManager.getInstance(myProject).getSelectedConfiguration()); - } - - private void updateActiveTarget(@Nullable RunnerAndConfigurationSettings settings) { - updateActiveTarget(settings, null); - } - - private void updateActiveTarget(@Nullable RunnerAndConfigurationSettings settings, @Nullable ExecutionTarget toSelect) { - List suitable = settings == null ? Collections.singletonList(DefaultExecutionTarget.INSTANCE) - : getTargetsFor(settings); - ExecutionTarget toNotify = null; - synchronized (myActiveTargetLock) { - if (toSelect == null) toSelect = myActiveTarget; - - int index = -1; - if (toSelect != null) { - index = suitable.indexOf(toSelect); - } - else if (mySavedActiveTargetId != null) { - for (int i = 0, size = suitable.size(); i < size; i++) { - if (suitable.get(i).getId().equals(mySavedActiveTargetId)) { - index = i; - break; - } - } - } - toNotify = - doSetActiveTarget(index >= 0 ? suitable.get(index) : ContainerUtil.getFirstItem(suitable, DefaultExecutionTarget.INSTANCE)); - } - - if (toNotify != null) { - myProject.getMessageBus().syncPublisher(TOPIC).activeTargetChanged(toNotify); - } - } - - @Nullable - private ExecutionTarget doSetActiveTarget(@NotNull ExecutionTarget newTarget) { - mySavedActiveTargetId = null; - - ExecutionTarget prev = myActiveTarget; - myActiveTarget = newTarget; - if (prev != null && !prev.equals(myActiveTarget)) { - return myActiveTarget; - } - return null; - } - - @NotNull - @Override - public List getTargetsFor(@Nullable RunnerAndConfigurationSettings settings) { - ApplicationManager.getApplication().assertReadAccessAllowed(); - if (settings == null) return Collections.emptyList(); - - List result = new ArrayList(); - for (ExecutionTargetProvider eachTargetProvider : Extensions.getExtensions(ExecutionTargetProvider.EXTENSION_NAME)) { - for (ExecutionTarget eachTarget : eachTargetProvider.getTargets(myProject, settings)) { - if (canRun(settings, eachTarget)) result.add(eachTarget); - } - } - return Collections.unmodifiableList(result); - } - - @Override - public void update() { - ApplicationManager.getApplication().assertIsDispatchThread(); - updateActiveTarget(); - } -} +/* + * 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.execution; + +import com.intellij.execution.impl.RunManagerImpl; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.components.*; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.project.Project; +import com.intellij.util.containers.ContainerUtil; +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + + +@State(name = "ExecutionTargetManager", storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE, scheme = StorageScheme.DEFAULT)}) +public class ExecutionTargetManagerImpl extends ExecutionTargetManager implements ProjectComponent, PersistentStateComponent { + @NotNull private final Project myProject; + @NotNull private final Object myActiveTargetLock = new Object(); + @Nullable private ExecutionTarget myActiveTarget; + + @Nullable private String mySavedActiveTargetId; + + public ExecutionTargetManagerImpl(@NotNull Project project) { + myProject = project; + } + + @Override + public void projectOpened() { + } + + @Override + public void projectClosed() { + } + + @Override + public Element getState() { + synchronized (myActiveTargetLock) { + Element state = new Element("state"); + + String id = myActiveTarget == null ? mySavedActiveTargetId : myActiveTarget.getId(); + if (id != null) state.setAttribute("SELECTED_TARGET", id); + return state; + } + } + + @Override + public void loadState(Element state) { + synchronized (myActiveTargetLock) { + if (myActiveTarget == null && mySavedActiveTargetId == null) { + mySavedActiveTargetId = state.getAttributeValue("SELECTED_TARGET"); + } + } + } + + @Override + public void initComponent() { + RunManagerImpl.getInstanceImpl(myProject).addRunManagerListener(new RunManagerAdapter() { + @Override + public void runConfigurationChanged(@NotNull RunnerAndConfigurationSettings settings) { + if (settings == RunManager.getInstance(myProject).getSelectedConfiguration()) { + updateActiveTarget(settings); + } + } + + @Override + public void runConfigurationSelected() { + updateActiveTarget(); + } + }); + } + + @Override + public void disposeComponent() { + } + + @NotNull + @Override + public String getComponentName() { + return ExecutionTargetManager.class.getName(); + } + + @NotNull + @Override + public ExecutionTarget getActiveTarget() { + ApplicationManager.getApplication().assertReadAccessAllowed(); + synchronized (myActiveTargetLock) { + if (myActiveTarget == null) { + updateActiveTarget(); + } + return myActiveTarget; + } + } + + @Override + public void setActiveTarget(@NotNull ExecutionTarget target) { + ApplicationManager.getApplication().assertIsDispatchThread(); + synchronized (myActiveTargetLock) { + updateActiveTarget(RunManager.getInstance(myProject).getSelectedConfiguration(), target); + } + } + + private void updateActiveTarget() { + updateActiveTarget(RunManager.getInstance(myProject).getSelectedConfiguration()); + } + + private void updateActiveTarget(@Nullable RunnerAndConfigurationSettings settings) { + updateActiveTarget(settings, null); + } + + private void updateActiveTarget(@Nullable RunnerAndConfigurationSettings settings, @Nullable ExecutionTarget toSelect) { + List suitable = settings == null ? Collections.singletonList(DefaultExecutionTarget.INSTANCE) + : getTargetsFor(settings); + ExecutionTarget toNotify = null; + synchronized (myActiveTargetLock) { + if (toSelect == null) toSelect = myActiveTarget; + + int index = -1; + if (toSelect != null) { + index = suitable.indexOf(toSelect); + } + else if (mySavedActiveTargetId != null) { + for (int i = 0, size = suitable.size(); i < size; i++) { + if (suitable.get(i).getId().equals(mySavedActiveTargetId)) { + index = i; + break; + } + } + } + toNotify = + doSetActiveTarget(index >= 0 ? suitable.get(index) : ContainerUtil.getFirstItem(suitable, DefaultExecutionTarget.INSTANCE)); + } + + if (toNotify != null) { + myProject.getMessageBus().syncPublisher(TOPIC).activeTargetChanged(toNotify); + } + } + + @Nullable + private ExecutionTarget doSetActiveTarget(@NotNull ExecutionTarget newTarget) { + mySavedActiveTargetId = null; + + ExecutionTarget prev = myActiveTarget; + myActiveTarget = newTarget; + if (prev != null && !prev.equals(myActiveTarget)) { + return myActiveTarget; + } + return null; + } + + @NotNull + @Override + public List getTargetsFor(@Nullable RunnerAndConfigurationSettings settings) { + ApplicationManager.getApplication().assertReadAccessAllowed(); + if (settings == null) return Collections.emptyList(); + + List result = new ArrayList(); + for (ExecutionTargetProvider eachTargetProvider : Extensions.getExtensions(ExecutionTargetProvider.EXTENSION_NAME)) { + for (ExecutionTarget eachTarget : eachTargetProvider.getTargets(myProject, settings)) { + if (canRun(settings, eachTarget)) result.add(eachTarget); + } + } + return Collections.unmodifiableList(result); + } + + @Override + public void update() { + ApplicationManager.getApplication().assertIsDispatchThread(); + updateActiveTarget(); + } +} diff --git a/platform/lang-impl/src/com/intellij/execution/ProgramRunnerUtil.java b/platform/lang-impl/src/com/intellij/execution/ProgramRunnerUtil.java index 84ce05a61d5e..64229d5dca41 100644 --- a/platform/lang-impl/src/com/intellij/execution/ProgramRunnerUtil.java +++ b/platform/lang-impl/src/com/intellij/execution/ProgramRunnerUtil.java @@ -1,140 +1,140 @@ -/* - * 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.execution; - -import com.intellij.execution.configurations.ConfigurationType; -import com.intellij.execution.configurations.RunConfiguration; -import com.intellij.execution.impl.RunDialog; -import com.intellij.execution.impl.RunManagerImpl; -import com.intellij.execution.runners.ExecutionEnvironment; -import com.intellij.execution.runners.ExecutionUtil; -import com.intellij.execution.runners.ProgramRunner; -import com.intellij.execution.ui.RunContentDescriptor; -import com.intellij.icons.AllIcons; -import com.intellij.internal.statistic.UsageTrigger; -import com.intellij.internal.statistic.beans.ConvertUsagesUtil; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.util.IconLoader; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.ui.LayeredIcon; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; - -/** - * @author spleaner - */ -public class ProgramRunnerUtil { - private static final Logger LOG = Logger.getInstance("#com.intellij.execution.ProgramRunnerUtil"); - - private ProgramRunnerUtil() { - } - - @Nullable - public static ProgramRunner getRunner(final String executorId, final RunnerAndConfigurationSettings configuration) { - return RunnerRegistry.getInstance().getRunner(executorId, configuration.getConfiguration()); - } - - public static void executeConfiguration(@NotNull final Project project, - @NotNull final RunnerAndConfigurationSettings configuration, - @NotNull final Executor executor, - @NotNull final ExecutionTarget target, - @Nullable RunContentDescriptor contentToReuse, - final boolean showSettings) { - ProgramRunner runner = getRunner(executor.getId(), configuration); - if (runner == null) { - LOG.error("Runner MUST not be null! Cannot find runner for " + executor.getId() + " and " + configuration.getConfiguration().getFactory().getName()); - return; - } - if (ExecutorRegistry.getInstance().isStarting(project, executor.getId(), runner.getRunnerId())){ - return; - } - - if (!ExecutionTargetManager.canRun(configuration, target)) { - ExecutionUtil.handleExecutionError( - project, executor.getToolWindowId(), configuration.getConfiguration(), - new ExecutionException(StringUtil.escapeXml("Cannot run '" + configuration.getName() + "' on '" + target.getDisplayName() + "'"))); - return; - } - - if (!RunManagerImpl.canRunConfiguration(configuration, executor) || (showSettings && configuration.isEditBeforeRun())) { - if (!RunDialog.editConfiguration(project, configuration, "Edit configuration", executor)) { - return; - } - - while (!RunManagerImpl.canRunConfiguration(configuration, executor)) { - if (0 == Messages.showYesNoDialog(project, "Configuration is still incorrect. Do you want to edit it again?", "Change Configuration Settings", - "Edit", "Continue Anyway", Messages.getErrorIcon())) { - if (!RunDialog.editConfiguration(project, configuration, "Edit configuration", executor)) { - return; - } - } else { - break; - } - } - } - - final ConfigurationType configurationType = configuration.getType(); - if (configurationType != null) { - UsageTrigger.trigger("execute." + ConvertUsagesUtil.ensureProperKey(configurationType.getId()) + "." + executor.getId()); - } - - try { - runner.execute(executor, new ExecutionEnvironment(runner, target, configuration, contentToReuse, project)); - } - catch (ExecutionException e) { - ExecutionUtil.handleExecutionError(project, executor.getToolWindowId(), configuration.getConfiguration(), e); - } - } - - - public static void executeConfiguration(@NotNull Project project, - @NotNull RunnerAndConfigurationSettings configuration, - @NotNull Executor executor) { - executeConfiguration(project, configuration, executor, ExecutionTargetManager.getActiveTarget(project), null, true); - } - - public static Icon getConfigurationIcon(final Project project, final RunnerAndConfigurationSettings settings, final boolean invalid) { - final RunManager runManager = RunManager.getInstance(project); - return getConfigurationIcon(settings, invalid, runManager.isTemporary(settings.getConfiguration())); - } - - public static Icon getConfigurationIcon(final RunnerAndConfigurationSettings settings, - final boolean invalid, - boolean isTemporary) { - RunConfiguration configuration = settings.getConfiguration(); - final Icon icon = settings.getFactory().getIcon(configuration); - LOG.assertTrue(icon != null, "Icon should not be null!"); - - final Icon configurationIcon = isTemporary ? IconLoader.getTransparentIcon(icon, 0.3f) : icon; - if (invalid) { - return LayeredIcon.create(configurationIcon, AllIcons.RunConfigurations.InvalidConfigurationLayer); - } - - return configurationIcon; - } - - public static String shortenName(final String name, final int toBeAdded) { - if (name == null) return ""; - final int symbols = Math.max(10, 20 - toBeAdded); - if (name.length() < symbols) return name; - else return name.substring(0, symbols) + "..."; - } -} +/* + * 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.execution; + +import com.intellij.execution.configurations.ConfigurationType; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.execution.impl.RunDialog; +import com.intellij.execution.impl.RunManagerImpl; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.runners.ExecutionUtil; +import com.intellij.execution.runners.ProgramRunner; +import com.intellij.execution.ui.RunContentDescriptor; +import com.intellij.icons.AllIcons; +import com.intellij.internal.statistic.UsageTrigger; +import com.intellij.internal.statistic.beans.ConvertUsagesUtil; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.IconLoader; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.LayeredIcon; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +/** + * @author spleaner + */ +public class ProgramRunnerUtil { + private static final Logger LOG = Logger.getInstance("#com.intellij.execution.ProgramRunnerUtil"); + + private ProgramRunnerUtil() { + } + + @Nullable + public static ProgramRunner getRunner(final String executorId, final RunnerAndConfigurationSettings configuration) { + return RunnerRegistry.getInstance().getRunner(executorId, configuration.getConfiguration()); + } + + public static void executeConfiguration(@NotNull final Project project, + @NotNull final RunnerAndConfigurationSettings configuration, + @NotNull final Executor executor, + @NotNull final ExecutionTarget target, + @Nullable RunContentDescriptor contentToReuse, + final boolean showSettings) { + ProgramRunner runner = getRunner(executor.getId(), configuration); + if (runner == null) { + LOG.error("Runner MUST not be null! Cannot find runner for " + executor.getId() + " and " + configuration.getConfiguration().getFactory().getName()); + return; + } + if (ExecutorRegistry.getInstance().isStarting(project, executor.getId(), runner.getRunnerId())){ + return; + } + + if (!ExecutionTargetManager.canRun(configuration, target)) { + ExecutionUtil.handleExecutionError( + project, executor.getToolWindowId(), configuration.getConfiguration(), + new ExecutionException(StringUtil.escapeXml("Cannot run '" + configuration.getName() + "' on '" + target.getDisplayName() + "'"))); + return; + } + + if (!RunManagerImpl.canRunConfiguration(configuration, executor) || (showSettings && configuration.isEditBeforeRun())) { + if (!RunDialog.editConfiguration(project, configuration, "Edit configuration", executor)) { + return; + } + + while (!RunManagerImpl.canRunConfiguration(configuration, executor)) { + if (0 == Messages.showYesNoDialog(project, "Configuration is still incorrect. Do you want to edit it again?", "Change Configuration Settings", + "Edit", "Continue Anyway", Messages.getErrorIcon())) { + if (!RunDialog.editConfiguration(project, configuration, "Edit configuration", executor)) { + return; + } + } else { + break; + } + } + } + + final ConfigurationType configurationType = configuration.getType(); + if (configurationType != null) { + UsageTrigger.trigger("execute." + ConvertUsagesUtil.ensureProperKey(configurationType.getId()) + "." + executor.getId()); + } + + try { + runner.execute(executor, new ExecutionEnvironment(runner, target, configuration, contentToReuse, project)); + } + catch (ExecutionException e) { + ExecutionUtil.handleExecutionError(project, executor.getToolWindowId(), configuration.getConfiguration(), e); + } + } + + + public static void executeConfiguration(@NotNull Project project, + @NotNull RunnerAndConfigurationSettings configuration, + @NotNull Executor executor) { + executeConfiguration(project, configuration, executor, ExecutionTargetManager.getActiveTarget(project), null, true); + } + + public static Icon getConfigurationIcon(final Project project, final RunnerAndConfigurationSettings settings, final boolean invalid) { + final RunManager runManager = RunManager.getInstance(project); + return getConfigurationIcon(settings, invalid, runManager.isTemporary(settings.getConfiguration())); + } + + public static Icon getConfigurationIcon(final RunnerAndConfigurationSettings settings, + final boolean invalid, + boolean isTemporary) { + RunConfiguration configuration = settings.getConfiguration(); + final Icon icon = settings.getFactory().getIcon(configuration); + LOG.assertTrue(icon != null, "Icon should not be null!"); + + final Icon configurationIcon = isTemporary ? IconLoader.getTransparentIcon(icon, 0.3f) : icon; + if (invalid) { + return LayeredIcon.create(configurationIcon, AllIcons.RunConfigurations.InvalidConfigurationLayer); + } + + return configurationIcon; + } + + public static String shortenName(final String name, final int toBeAdded) { + if (name == null) return ""; + final int symbols = Math.max(10, 20 - toBeAdded); + if (name.length() < symbols) return name; + else return name.substring(0, symbols) + "..."; + } +} diff --git a/platform/lang-impl/src/com/intellij/execution/actions/ChooseDebugConfigurationPopupAction.java b/platform/lang-impl/src/com/intellij/execution/actions/ChooseDebugConfigurationPopupAction.java index c841275c1470..aad9d71c2b9d 100644 --- a/platform/lang-impl/src/com/intellij/execution/actions/ChooseDebugConfigurationPopupAction.java +++ b/platform/lang-impl/src/com/intellij/execution/actions/ChooseDebugConfigurationPopupAction.java @@ -1,36 +1,36 @@ -/* - * 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.execution.actions; - -import com.intellij.execution.Executor; - -public class ChooseDebugConfigurationPopupAction extends ChooseRunConfigurationPopupAction { - @Override - protected Executor getDefaultExecutor() { - return super.getAlternativeExecutor(); - } - - @Override - protected Executor getAlternativeExecutor() { - return super.getDefaultExecutor(); - } - - @Override - protected String getAdKey() { - return "debug.configuration.alternate.action.ad"; - } -} +/* + * 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.execution.actions; + +import com.intellij.execution.Executor; + +public class ChooseDebugConfigurationPopupAction extends ChooseRunConfigurationPopupAction { + @Override + protected Executor getDefaultExecutor() { + return super.getAlternativeExecutor(); + } + + @Override + protected Executor getAlternativeExecutor() { + return super.getDefaultExecutor(); + } + + @Override + protected String getAdKey() { + return "debug.configuration.alternate.action.ad"; + } +} diff --git a/platform/lang-impl/src/com/intellij/execution/actions/ChooseRunConfigurationPopupAction.java b/platform/lang-impl/src/com/intellij/execution/actions/ChooseRunConfigurationPopupAction.java index cc835e728872..94f78ff48301 100644 --- a/platform/lang-impl/src/com/intellij/execution/actions/ChooseRunConfigurationPopupAction.java +++ b/platform/lang-impl/src/com/intellij/execution/actions/ChooseRunConfigurationPopupAction.java @@ -1,74 +1,74 @@ -/* - * 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.execution.actions; - -import com.intellij.execution.Executor; -import com.intellij.execution.ExecutorRegistry; -import com.intellij.execution.executors.DefaultRunExecutor; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.PlatformDataKeys; -import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.wm.ToolWindowId; - -public class ChooseRunConfigurationPopupAction extends AnAction { - @Override - public void actionPerformed(AnActionEvent e) { - final Project project = e.getData(PlatformDataKeys.PROJECT); - assert project != null; - - new ChooseRunConfigurationPopup(project, - getAdKey(), - getDefaultExecutor(), - getAlternativeExecutor()).show(); - } - - protected Executor getDefaultExecutor() { - return DefaultRunExecutor.getRunExecutorInstance(); - } - - protected Executor getAlternativeExecutor() { - return ExecutorRegistry.getInstance().getExecutorById(ToolWindowId.DEBUG); - } - - protected String getAdKey() { - return "run.configuration.alternate.action.ad"; - } - - @Override - public void update(AnActionEvent e) { - final Presentation presentation = e.getPresentation(); - final Project project = e.getData(PlatformDataKeys.PROJECT); - - presentation.setEnabled(true); - if (project == null || project.isDisposed()) { - presentation.setEnabled(false); - presentation.setVisible(false); - return; - } - - if (null == getDefaultExecutor()) { - presentation.setEnabled(false); - presentation.setVisible(false); - return; - } - - presentation.setEnabled(true); - presentation.setVisible(true); - } -} +/* + * 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.execution.actions; + +import com.intellij.execution.Executor; +import com.intellij.execution.ExecutorRegistry; +import com.intellij.execution.executors.DefaultRunExecutor; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.wm.ToolWindowId; + +public class ChooseRunConfigurationPopupAction extends AnAction { + @Override + public void actionPerformed(AnActionEvent e) { + final Project project = e.getData(PlatformDataKeys.PROJECT); + assert project != null; + + new ChooseRunConfigurationPopup(project, + getAdKey(), + getDefaultExecutor(), + getAlternativeExecutor()).show(); + } + + protected Executor getDefaultExecutor() { + return DefaultRunExecutor.getRunExecutorInstance(); + } + + protected Executor getAlternativeExecutor() { + return ExecutorRegistry.getInstance().getExecutorById(ToolWindowId.DEBUG); + } + + protected String getAdKey() { + return "run.configuration.alternate.action.ad"; + } + + @Override + public void update(AnActionEvent e) { + final Presentation presentation = e.getPresentation(); + final Project project = e.getData(PlatformDataKeys.PROJECT); + + presentation.setEnabled(true); + if (project == null || project.isDisposed()) { + presentation.setEnabled(false); + presentation.setVisible(false); + return; + } + + if (null == getDefaultExecutor()) { + presentation.setEnabled(false); + presentation.setVisible(false); + return; + } + + presentation.setEnabled(true); + presentation.setVisible(true); + } +} 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 520576d5c72f..0314099250f9 100644 --- a/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationsComboBoxAction.java +++ b/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationsComboBoxAction.java @@ -1,328 +1,328 @@ -/* - * 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.execution.actions; - -import com.intellij.execution.*; -import com.intellij.execution.configurations.ConfigurationType; -import com.intellij.execution.configurations.RunConfiguration; -import com.intellij.icons.AllIcons; -import com.intellij.ide.DataManager; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.actionSystem.ex.ComboBoxAction; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.DumbService; -import com.intellij.openapi.project.IndexNotReadyException; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.wm.IdeFrame; -import com.intellij.util.ui.UIUtil; -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 RunConfigurationsComboBoxAction extends ComboBoxAction implements DumbAware { - private static final Logger LOG = Logger.getInstance("#com.intellij.execution.actions.RunConfigurationAction"); - private static final Key BUTTON_KEY = Key.create("COMBOBOX_BUTTON"); - - public void actionPerformed(final AnActionEvent e) { - final IdeFrame ideFrame = findFrame(e.getData(PlatformDataKeys.CONTEXT_COMPONENT)); - final ComboBoxButton button = (ComboBoxButton)ideFrame.getComponent().getRootPane().getClientProperty(BUTTON_KEY); - if (button == null || !button.isShowing()) return; - button.showPopup(); - } - - private static IdeFrame findFrame(final Component component) { - return UIUtil.getParentOfType(IdeFrame.class, component); - } - - public void update(final AnActionEvent e) { - final Presentation presentation = e.getPresentation(); - final Project project = e.getData(PlatformDataKeys.PROJECT); - if (ActionPlaces.MAIN_MENU.equals(e.getPlace())) { - presentation.setDescription(ExecutionBundle.message("choose.run.configuration.action.description")); - presentation.setEnabled(findFrame(e.getData(PlatformDataKeys.CONTEXT_COMPONENT)) != null); - return; - } - - try { - if (project == null || project.isDisposed() || !project.isInitialized()) { - //if (ProjectManager.getInstance().getOpenProjects().length > 0) { - // // do nothing if frame is not active - // return; - //} - - updateButton(null, null, null, presentation); - presentation.setEnabled(false); - } - else { - if (DumbService.getInstance(project).isDumb()) { - presentation.setEnabled(false); - presentation.setText(""); - presentation.setIcon(null); - } - else { - updateButton(ExecutionTargetManager.getActiveTarget(project), - RunManagerEx.getInstanceEx(project).getSelectedConfiguration(), - project, - presentation); - presentation.setEnabled(true); - } - } - } - catch (IndexNotReadyException e1) { - presentation.setEnabled(false); - } - } - - private static void updateButton(@Nullable ExecutionTarget target, - final @Nullable RunnerAndConfigurationSettings settings, - final @Nullable Project project, - final @NotNull Presentation presentation) { - if (project != null && target != null && settings != null) { - String name = settings.getName(); - if (target != DefaultExecutionTarget.INSTANCE) { - name += " | " + target.getDisplayName(); - } else { - if (!settings.canRunOn(target)) { - name += " | Nothing to run on"; - } - } - presentation.setText(name, false); - setConfigurationIcon(presentation, settings, project); - } - else { - presentation.setText(""); // IDEA-21657 - presentation.setIcon(null); - } - } - - private static void setConfigurationIcon(final Presentation presentation, - final RunnerAndConfigurationSettings settings, - final Project project) { - try { - presentation.setIcon(RunManagerEx.getInstanceEx(project).getConfigurationIcon(settings)); - } - catch (IndexNotReadyException ignored) { - } - } - - public JComponent createCustomComponent(final Presentation presentation) { - final ComboBoxButton comboBoxButton = new ComboBoxButton(presentation) { - public void addNotify() { - super.addNotify(); //To change body of overriden methods use Options | File Templates.; - final IdeFrame frame = findFrame(this); - LOG.assertTrue(frame != null); - frame.getComponent().getRootPane().putClientProperty(BUTTON_KEY, this); - } - - @Override - public void removeNotify() { - final IdeFrame frame = findFrame(this); - LOG.assertTrue(frame != null); - frame.getComponent().getRootPane().putClientProperty(BUTTON_KEY, null); - super.removeNotify(); - } - }; - - final JPanel panel = new JPanel(new BorderLayout()); - panel.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2)); - panel.add(comboBoxButton); - panel.setOpaque(false); - return panel; - } - - - @NotNull - protected DefaultActionGroup createPopupActionGroup(final JComponent button) { - final DefaultActionGroup allActionsGroup = new DefaultActionGroup(); - final Project project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(button)); - if (project != null) { - final RunManagerEx runManager = RunManagerEx.getInstanceEx(project); - - allActionsGroup.add(ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_RUN_CONFIGURATIONS)); - allActionsGroup.add(new SaveTemporaryAction()); - allActionsGroup.addSeparator(); - - RunnerAndConfigurationSettings selected = RunManager.getInstance(project).getSelectedConfiguration(); - if (selected != null) { - ExecutionTarget activeTarget = ExecutionTargetManager.getActiveTarget(project); - for (ExecutionTarget eachTarget : ExecutionTargetManager.getTargetsToChooseFor(project, selected)) { - allActionsGroup.add(new SelectTargetAction(project, eachTarget, eachTarget.equals(activeTarget))); - } - allActionsGroup.addSeparator(); - } - - final ConfigurationType[] types = runManager.getConfigurationFactories(); - for (ConfigurationType type : types) { - final DefaultActionGroup actionGroup = new DefaultActionGroup(); - Map> structure = runManager.getStructure(type); - for (Map.Entry> entry : structure.entrySet()) { - DefaultActionGroup group = entry.getKey() != null ? new DefaultActionGroup(entry.getKey(), true) : actionGroup; - group.getTemplatePresentation().setIcon(AllIcons.Nodes.Folder); - for (RunnerAndConfigurationSettings settings : entry.getValue()) { - group.add(new SelectConfigAction(settings, project)); - } - if (group != actionGroup) { - actionGroup.add(group); - } - } - - //final RunnerAndConfigurationSettings[] configurations = runManager.getConfigurationSettings(type); - //ArrayList configurationSettingsList = new ArrayList(); - //int i = 0; - //for (RunnerAndConfigurationSettings configuration : configurations) { - // if (configuration.isTemporary()) { - // configurationSettingsList.add(configuration); - // } - // else { - // configurationSettingsList.add(i++, configuration); - // } - //} - //for (final RunnerAndConfigurationSettings configuration : configurationSettingsList) { - // //if (runManager.canRunConfiguration(configuration)) { - // final SelectConfigAction action = new SelectConfigAction(configuration, project); - // - // actionGroup.add(action); - // //} - //} - - allActionsGroup.add(actionGroup); - allActionsGroup.addSeparator(); - } - } - return allActionsGroup; - } - - private static class SaveTemporaryAction extends AnAction { - - public SaveTemporaryAction() { - Presentation presentation = getTemplatePresentation(); - presentation.setIcon(AllIcons.Actions.Menu_saveall); - } - - public void actionPerformed(final AnActionEvent e) { - final Project project = e.getData(PlatformDataKeys.PROJECT); - RunConfiguration configuration = chooseTempConfiguration(project); - if (project != null && configuration != null) { - final RunManager runManager = RunManager.getInstance(project); - runManager.makeStable(configuration); - } - } - - public void update(final AnActionEvent e) { - final Presentation presentation = e.getPresentation(); - final Project project = e.getData(PlatformDataKeys.PROJECT); - if (project == null) { - disable(presentation); - return; - } - RunConfiguration configuration = chooseTempConfiguration(project); - if (configuration == null) { - disable(presentation); - } - else { - presentation.setText(ExecutionBundle.message("save.temporary.run.configuration.action.name", configuration.getName())); - presentation.setDescription(presentation.getText()); - presentation.setVisible(true); - presentation.setEnabled(true); - } - } - - private static void disable(final Presentation presentation) { - presentation.setEnabled(false); - presentation.setVisible(false); - } - - @Nullable - private static RunConfiguration chooseTempConfiguration(Project project) { - final RunConfiguration[] tempConfigurations = RunManager.getInstance(project).getTempConfigurations(); - if (tempConfigurations.length > 0) { - RunnerAndConfigurationSettings selectedConfiguration = RunManager.getInstance(project).getSelectedConfiguration(); - if (selectedConfiguration == null || !selectedConfiguration.isTemporary()) { - return tempConfigurations[0]; - } - return selectedConfiguration.getConfiguration(); - } - return null; - } - } - - private static class SelectTargetAction extends AnAction { - private final Project myProject; - private final ExecutionTarget myTarget; - - public SelectTargetAction(final Project project, final ExecutionTarget target, boolean selected) { - myProject = project; - myTarget = target; - - String name = target.getDisplayName(); - Presentation presentation = getTemplatePresentation(); - presentation.setText(name, false); - presentation.setDescription("Select " + name); - if (selected) { - presentation.setIcon(AllIcons.Actions.Checked); - presentation.setSelectedIcon(AllIcons.Actions.Checked_selected); - } - } - - @Override - public void actionPerformed(AnActionEvent e) { - ExecutionTargetManager.setActiveTarget(myProject, myTarget); - updateButton(ExecutionTargetManager.getActiveTarget(myProject), - RunManagerEx.getInstanceEx(myProject).getSelectedConfiguration(), - myProject, - e.getPresentation()); - } - } - - private static class SelectConfigAction extends AnAction { - private final RunnerAndConfigurationSettings myConfiguration; - private final Project myProject; - - public SelectConfigAction(final RunnerAndConfigurationSettings configuration, final Project project) { - myConfiguration = configuration; - myProject = project; - String name = configuration.getName(); - if (name == null || name.length() == 0) { - name = " "; - } - final Presentation presentation = getTemplatePresentation(); - presentation.setText(name, false); - presentation.setDescription("Select " + configuration.getType().getConfigurationTypeDescription() + " '" + name + "'"); - updateIcon(presentation); - } - - private void updateIcon(final Presentation presentation) { - setConfigurationIcon(presentation, myConfiguration, myProject); - } - - public void actionPerformed(final AnActionEvent e) { - RunManagerEx.getInstanceEx(myProject).setActiveConfiguration(myConfiguration); - updateButton(ExecutionTargetManager.getActiveTarget(myProject), myConfiguration, myProject, e.getPresentation()); - } - - public void update(final AnActionEvent e) { - super.update(e); - updateIcon(e.getPresentation()); - } - } -} +/* + * 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.execution.actions; + +import com.intellij.execution.*; +import com.intellij.execution.configurations.ConfigurationType; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.icons.AllIcons; +import com.intellij.ide.DataManager; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ex.ComboBoxAction; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.project.IndexNotReadyException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.wm.IdeFrame; +import com.intellij.util.ui.UIUtil; +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 RunConfigurationsComboBoxAction extends ComboBoxAction implements DumbAware { + private static final Logger LOG = Logger.getInstance("#com.intellij.execution.actions.RunConfigurationAction"); + private static final Key BUTTON_KEY = Key.create("COMBOBOX_BUTTON"); + + public void actionPerformed(final AnActionEvent e) { + final IdeFrame ideFrame = findFrame(e.getData(PlatformDataKeys.CONTEXT_COMPONENT)); + final ComboBoxButton button = (ComboBoxButton)ideFrame.getComponent().getRootPane().getClientProperty(BUTTON_KEY); + if (button == null || !button.isShowing()) return; + button.showPopup(); + } + + private static IdeFrame findFrame(final Component component) { + return UIUtil.getParentOfType(IdeFrame.class, component); + } + + public void update(final AnActionEvent e) { + final Presentation presentation = e.getPresentation(); + final Project project = e.getData(PlatformDataKeys.PROJECT); + if (ActionPlaces.MAIN_MENU.equals(e.getPlace())) { + presentation.setDescription(ExecutionBundle.message("choose.run.configuration.action.description")); + presentation.setEnabled(findFrame(e.getData(PlatformDataKeys.CONTEXT_COMPONENT)) != null); + return; + } + + try { + if (project == null || project.isDisposed() || !project.isInitialized()) { + //if (ProjectManager.getInstance().getOpenProjects().length > 0) { + // // do nothing if frame is not active + // return; + //} + + updateButton(null, null, null, presentation); + presentation.setEnabled(false); + } + else { + if (DumbService.getInstance(project).isDumb()) { + presentation.setEnabled(false); + presentation.setText(""); + presentation.setIcon(null); + } + else { + updateButton(ExecutionTargetManager.getActiveTarget(project), + RunManagerEx.getInstanceEx(project).getSelectedConfiguration(), + project, + presentation); + presentation.setEnabled(true); + } + } + } + catch (IndexNotReadyException e1) { + presentation.setEnabled(false); + } + } + + private static void updateButton(@Nullable ExecutionTarget target, + final @Nullable RunnerAndConfigurationSettings settings, + final @Nullable Project project, + final @NotNull Presentation presentation) { + if (project != null && target != null && settings != null) { + String name = settings.getName(); + if (target != DefaultExecutionTarget.INSTANCE) { + name += " | " + target.getDisplayName(); + } else { + if (!settings.canRunOn(target)) { + name += " | Nothing to run on"; + } + } + presentation.setText(name, false); + setConfigurationIcon(presentation, settings, project); + } + else { + presentation.setText(""); // IDEA-21657 + presentation.setIcon(null); + } + } + + private static void setConfigurationIcon(final Presentation presentation, + final RunnerAndConfigurationSettings settings, + final Project project) { + try { + presentation.setIcon(RunManagerEx.getInstanceEx(project).getConfigurationIcon(settings)); + } + catch (IndexNotReadyException ignored) { + } + } + + public JComponent createCustomComponent(final Presentation presentation) { + final ComboBoxButton comboBoxButton = new ComboBoxButton(presentation) { + public void addNotify() { + super.addNotify(); //To change body of overriden methods use Options | File Templates.; + final IdeFrame frame = findFrame(this); + LOG.assertTrue(frame != null); + frame.getComponent().getRootPane().putClientProperty(BUTTON_KEY, this); + } + + @Override + public void removeNotify() { + final IdeFrame frame = findFrame(this); + LOG.assertTrue(frame != null); + frame.getComponent().getRootPane().putClientProperty(BUTTON_KEY, null); + super.removeNotify(); + } + }; + + final JPanel panel = new JPanel(new BorderLayout()); + panel.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2)); + panel.add(comboBoxButton); + panel.setOpaque(false); + return panel; + } + + + @NotNull + protected DefaultActionGroup createPopupActionGroup(final JComponent button) { + final DefaultActionGroup allActionsGroup = new DefaultActionGroup(); + final Project project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(button)); + if (project != null) { + final RunManagerEx runManager = RunManagerEx.getInstanceEx(project); + + allActionsGroup.add(ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_RUN_CONFIGURATIONS)); + allActionsGroup.add(new SaveTemporaryAction()); + allActionsGroup.addSeparator(); + + RunnerAndConfigurationSettings selected = RunManager.getInstance(project).getSelectedConfiguration(); + if (selected != null) { + ExecutionTarget activeTarget = ExecutionTargetManager.getActiveTarget(project); + for (ExecutionTarget eachTarget : ExecutionTargetManager.getTargetsToChooseFor(project, selected)) { + allActionsGroup.add(new SelectTargetAction(project, eachTarget, eachTarget.equals(activeTarget))); + } + allActionsGroup.addSeparator(); + } + + final ConfigurationType[] types = runManager.getConfigurationFactories(); + for (ConfigurationType type : types) { + final DefaultActionGroup actionGroup = new DefaultActionGroup(); + Map> structure = runManager.getStructure(type); + for (Map.Entry> entry : structure.entrySet()) { + DefaultActionGroup group = entry.getKey() != null ? new DefaultActionGroup(entry.getKey(), true) : actionGroup; + group.getTemplatePresentation().setIcon(AllIcons.Nodes.Folder); + for (RunnerAndConfigurationSettings settings : entry.getValue()) { + group.add(new SelectConfigAction(settings, project)); + } + if (group != actionGroup) { + actionGroup.add(group); + } + } + + //final RunnerAndConfigurationSettings[] configurations = runManager.getConfigurationSettings(type); + //ArrayList configurationSettingsList = new ArrayList(); + //int i = 0; + //for (RunnerAndConfigurationSettings configuration : configurations) { + // if (configuration.isTemporary()) { + // configurationSettingsList.add(configuration); + // } + // else { + // configurationSettingsList.add(i++, configuration); + // } + //} + //for (final RunnerAndConfigurationSettings configuration : configurationSettingsList) { + // //if (runManager.canRunConfiguration(configuration)) { + // final SelectConfigAction action = new SelectConfigAction(configuration, project); + // + // actionGroup.add(action); + // //} + //} + + allActionsGroup.add(actionGroup); + allActionsGroup.addSeparator(); + } + } + return allActionsGroup; + } + + private static class SaveTemporaryAction extends AnAction { + + public SaveTemporaryAction() { + Presentation presentation = getTemplatePresentation(); + presentation.setIcon(AllIcons.Actions.Menu_saveall); + } + + public void actionPerformed(final AnActionEvent e) { + final Project project = e.getData(PlatformDataKeys.PROJECT); + RunConfiguration configuration = chooseTempConfiguration(project); + if (project != null && configuration != null) { + final RunManager runManager = RunManager.getInstance(project); + runManager.makeStable(configuration); + } + } + + public void update(final AnActionEvent e) { + final Presentation presentation = e.getPresentation(); + final Project project = e.getData(PlatformDataKeys.PROJECT); + if (project == null) { + disable(presentation); + return; + } + RunConfiguration configuration = chooseTempConfiguration(project); + if (configuration == null) { + disable(presentation); + } + else { + presentation.setText(ExecutionBundle.message("save.temporary.run.configuration.action.name", configuration.getName())); + presentation.setDescription(presentation.getText()); + presentation.setVisible(true); + presentation.setEnabled(true); + } + } + + private static void disable(final Presentation presentation) { + presentation.setEnabled(false); + presentation.setVisible(false); + } + + @Nullable + private static RunConfiguration chooseTempConfiguration(Project project) { + final RunConfiguration[] tempConfigurations = RunManager.getInstance(project).getTempConfigurations(); + if (tempConfigurations.length > 0) { + RunnerAndConfigurationSettings selectedConfiguration = RunManager.getInstance(project).getSelectedConfiguration(); + if (selectedConfiguration == null || !selectedConfiguration.isTemporary()) { + return tempConfigurations[0]; + } + return selectedConfiguration.getConfiguration(); + } + return null; + } + } + + private static class SelectTargetAction extends AnAction { + private final Project myProject; + private final ExecutionTarget myTarget; + + public SelectTargetAction(final Project project, final ExecutionTarget target, boolean selected) { + myProject = project; + myTarget = target; + + String name = target.getDisplayName(); + Presentation presentation = getTemplatePresentation(); + presentation.setText(name, false); + presentation.setDescription("Select " + name); + if (selected) { + presentation.setIcon(AllIcons.Actions.Checked); + presentation.setSelectedIcon(AllIcons.Actions.Checked_selected); + } + } + + @Override + public void actionPerformed(AnActionEvent e) { + ExecutionTargetManager.setActiveTarget(myProject, myTarget); + updateButton(ExecutionTargetManager.getActiveTarget(myProject), + RunManagerEx.getInstanceEx(myProject).getSelectedConfiguration(), + myProject, + e.getPresentation()); + } + } + + private static class SelectConfigAction extends AnAction { + private final RunnerAndConfigurationSettings myConfiguration; + private final Project myProject; + + public SelectConfigAction(final RunnerAndConfigurationSettings configuration, final Project project) { + myConfiguration = configuration; + myProject = project; + String name = configuration.getName(); + if (name == null || name.length() == 0) { + name = " "; + } + final Presentation presentation = getTemplatePresentation(); + presentation.setText(name, false); + presentation.setDescription("Select " + configuration.getType().getConfigurationTypeDescription() + " '" + name + "'"); + updateIcon(presentation); + } + + private void updateIcon(final Presentation presentation) { + setConfigurationIcon(presentation, myConfiguration, myProject); + } + + public void actionPerformed(final AnActionEvent e) { + RunManagerEx.getInstanceEx(myProject).setActiveConfiguration(myConfiguration); + updateButton(ExecutionTargetManager.getActiveTarget(myProject), myConfiguration, myProject, e.getPresentation()); + } + + public void update(final AnActionEvent e) { + super.update(e); + updateIcon(e.getPresentation()); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationBeforeRunProvider.java b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationBeforeRunProvider.java index 3402d75309c9..9ac0b1877c0c 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationBeforeRunProvider.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationBeforeRunProvider.java @@ -1,382 +1,382 @@ -/* - * 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.execution.impl; - -import com.intellij.execution.*; -import com.intellij.execution.configurations.ConfigurationType; -import com.intellij.execution.configurations.RunConfiguration; -import com.intellij.execution.executors.DefaultRunExecutor; -import com.intellij.execution.process.ProcessAdapter; -import com.intellij.execution.process.ProcessEvent; -import com.intellij.execution.process.ProcessHandler; -import com.intellij.execution.runners.ExecutionEnvironment; -import com.intellij.execution.runners.ProgramRunner; -import com.intellij.execution.ui.RunContentDescriptor; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.util.Key; -import com.intellij.ui.ColoredListCellRenderer; -import com.intellij.ui.SimpleTextAttributes; -import com.intellij.ui.components.JBList; -import com.intellij.ui.components.JBScrollPane; -import com.intellij.util.concurrency.Semaphore; -import org.jdom.Attribute; -import org.jdom.Element; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import java.awt.*; -import java.util.*; -import java.util.List; - -/** - * @author Vassiliy Kudryashov - */ -public class RunConfigurationBeforeRunProvider -extends BeforeRunTaskProvider { - - public static final Key ID = Key.create("RunConfigurationTask"); - - private static final Logger LOG = Logger.getInstance("#com.intellij.execution.impl.RunConfigurationBeforeRunProvider"); - - private final Project myProject; - - public RunConfigurationBeforeRunProvider(Project project) { - myProject = project; - } - - @Override - public Key getId() { - return ID; - } - - @Override - public Icon getIcon() { - return AllIcons.Actions.Execute; - } - - @Override - public Icon getTaskIcon(RunConfigurableBeforeRunTask task) { - if (task.getSettings() == null) - return null; - return ProgramRunnerUtil.getConfigurationIcon(myProject, task.getSettings(), false); - } - - @Override - public String getName() { - return ExecutionBundle.message("before.launch.run.another.configuration"); - } - - @Override - public String getDescription(RunConfigurableBeforeRunTask task) { - if (task.getSettings() == null) { - return ExecutionBundle.message("before.launch.run.another.configuration"); - } - else { - return ExecutionBundle.message("before.launch.run.certain.configuration", task.getSettings().getName()); - } - } - - @Override - public boolean isConfigurable() { - return true; - } - - @Override - @Nullable - public RunConfigurableBeforeRunTask createTask(RunConfiguration runConfiguration) { - if (runConfiguration.getProject().isInitialized()) { - Collection configurations = - RunManagerImpl.getInstanceImpl(runConfiguration.getProject()).getSortedConfigurations(); - if (configurations.isEmpty() - || (configurations.size() == 1 && configurations.iterator().next().getConfiguration() == runConfiguration)) { - return null; - } - } - return new RunConfigurableBeforeRunTask(); - } - - @Override - public boolean configureTask(RunConfiguration runConfiguration, RunConfigurableBeforeRunTask task) { - SelectionDialog dialog = - new SelectionDialog(task.getSettings(), getAvailableConfigurations(runConfiguration)); - dialog.show(); - RunnerAndConfigurationSettings settings = dialog.getSelectedSettings(); - if (settings != null) { - task.setSettings(settings); - return true; - } - else { - return false; - } - } - - @NotNull - private List getAvailableConfigurations(RunConfiguration runConfiguration) { - Project project = runConfiguration.getProject(); - if (project == null || !project.isInitialized()) - return Collections.emptyList(); - final RunManagerImpl runManager = RunManagerImpl.getInstanceImpl(project); - - final ArrayList configurations - = new ArrayList(runManager.getSortedConfigurations()); - String executorId = DefaultRunExecutor.getRunExecutorInstance().getId(); - for (Iterator iterator = configurations.iterator(); iterator.hasNext();) { - RunnerAndConfigurationSettings settings = iterator.next(); - final ProgramRunner runner = ProgramRunnerUtil.getRunner(executorId, settings); - if (runner == null || settings.getConfiguration() == runConfiguration) - iterator.remove(); - } - return configurations; - } - - @Override - public boolean canExecuteTask(RunConfiguration configuration, - RunConfigurableBeforeRunTask task) { - RunnerAndConfigurationSettings settings = task.getSettings(); - if (settings == null) { - return false; - } - String executorId = DefaultRunExecutor.getRunExecutorInstance().getId(); - final ProgramRunner runner = ProgramRunnerUtil.getRunner(executorId, settings); - if (runner == null) - return false; - return runner.canRun(executorId, settings.getConfiguration()); - } - - @Override - public boolean executeTask(final DataContext dataContext, - RunConfiguration configuration, - final ExecutionEnvironment env, - RunConfigurableBeforeRunTask task) { - RunnerAndConfigurationSettings settings = task.getSettings(); - if (settings == null) { - return false; - } - final Executor executor = DefaultRunExecutor.getRunExecutorInstance(); - String executorId = executor.getId(); - final ProgramRunner runner = ProgramRunnerUtil.getRunner(executorId, settings); - if (runner == null) - return false; - final ExecutionEnvironment environment = new ExecutionEnvironment(runner, settings, myProject); - environment.putUserData(RunContentDescriptor.REUSE_CONTENT_PROHIBITED, env.getUserData(RunContentDescriptor.REUSE_CONTENT_PROHIBITED)); - if (!ExecutionTargetManager.canRun(settings, env.getExecutionTarget())) { - return false; - } - - if (!runner.canRun(executorId, environment.getRunProfile())) { - return false; - } - - else { - final Semaphore targetDone = new Semaphore(); - final boolean[] result = new boolean[1]; - try { - ApplicationManager.getApplication().invokeAndWait(new Runnable() { - - public void run() { - targetDone.down(); - try { - runner.execute(executor, environment, new ProgramRunner.Callback() { - @Override - public void processStarted(RunContentDescriptor descriptor) { - ProcessHandler processHandler = descriptor != null ? descriptor.getProcessHandler() : null; - if (processHandler != null) { - processHandler.addProcessListener(new ProcessAdapter() { - @Override - public void processTerminated(ProcessEvent event) { - result[0] = event.getExitCode() == 0; - targetDone.up(); - } - }); - } - } - }); - } - catch (ExecutionException e) { - LOG.error(e); - } - } - }, ModalityState.NON_MODAL); - } - catch (Exception e) { - LOG.error(e); - return false; - } - targetDone.waitFor(); - return result[0]; - } - } - - class RunConfigurableBeforeRunTask extends BeforeRunTask { - private String myConfigurationName; - private String myConfigurationType; - private boolean myInitialized = false; - - private RunnerAndConfigurationSettings mySettings; - - RunConfigurableBeforeRunTask() { - super(ID); - } - - @Override - public void writeExternal(Element element) { - super.writeExternal(element); - if (myConfigurationName != null && myConfigurationType != null) { - element.setAttribute("run_configuration_name", myConfigurationName); - element.setAttribute("run_configuration_type", myConfigurationType); - } - else if (mySettings != null) { - element.setAttribute("run_configuration_name", mySettings.getName()); - element.setAttribute("run_configuration_type", mySettings.getType().getId()); - } - } - - @Override - public void readExternal(Element element) { - super.readExternal(element); - Attribute configurationNameAttr = element.getAttribute("run_configuration_name"); - Attribute configurationTypeAttr = element.getAttribute("run_configuration_type"); - myConfigurationName = configurationNameAttr != null ? configurationNameAttr.getValue() : null; - myConfigurationType = configurationTypeAttr != null ? configurationTypeAttr.getValue() : null; - } - - void init() { - if (myInitialized) { - return; - } - if (myConfigurationName != null && myConfigurationType != null) { - Collection configurations = RunManagerImpl.getInstanceImpl(myProject).getSortedConfigurations(); - for (RunnerAndConfigurationSettings runConfiguration : configurations) { - ConfigurationType type = runConfiguration.getType(); - if (myConfigurationName.equals(runConfiguration.getName()) - && type != null - && myConfigurationType.equals(type.getId())) { - setSettings(runConfiguration); - return; - } - } - } - } - - void setSettings(RunnerAndConfigurationSettings settings) { - mySettings = settings; - myInitialized = true; - } - - RunnerAndConfigurationSettings getSettings() { - init(); - return mySettings; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - - RunConfigurableBeforeRunTask that = (RunConfigurableBeforeRunTask)o; - - if (myConfigurationName != null ? !myConfigurationName.equals(that.myConfigurationName) : that.myConfigurationName != null) return false; - if (myConfigurationType != null ? !myConfigurationType.equals(that.myConfigurationType) : that.myConfigurationType != null) return false; - - return true; - } - - @Override - public int hashCode() { - int result = super.hashCode(); - result = 31 * result + (myConfigurationName != null ? myConfigurationName.hashCode() : 0); - result = 31 * result + (myConfigurationType != null ? myConfigurationType.hashCode() : 0); - return result; - } - } - - private class SelectionDialog extends DialogWrapper { - private RunnerAndConfigurationSettings mySelectedSettings; - @NotNull private final List mySettings; - private JBList myJBList; - - private SelectionDialog(RunnerAndConfigurationSettings selectedSettings, @NotNull List settings) { - super(myProject); - setTitle(ExecutionBundle.message("before.launch.run.another.configuration.choose")); - mySelectedSettings = selectedSettings; - mySettings = settings; - init(); - myJBList.setSelectedValue(mySelectedSettings, true); - FontMetrics fontMetrics = myJBList.getFontMetrics(myJBList.getFont()); - int maxWidth = fontMetrics.stringWidth("m") * 30; - for (RunnerAndConfigurationSettings setting : settings) { - maxWidth = Math.max(fontMetrics.stringWidth(setting.getConfiguration().getName()), maxWidth); - } - maxWidth += 24;//icon and gap - myJBList.setMinimumSize(new Dimension(maxWidth, myJBList.getPreferredSize().height)); - } - - @Nullable - @Override - protected String getDimensionServiceKey() { - return "com.intellij.execution.impl.RunConfigurationBeforeRunProvider.dimensionServiceKey;"; - } - - @Override - protected JComponent createCenterPanel() { - myJBList = new JBList(mySettings); - myJBList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - myJBList.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - Object selectedValue = myJBList.getSelectedValue(); - if (selectedValue instanceof RunnerAndConfigurationSettings) { - mySelectedSettings = (RunnerAndConfigurationSettings)selectedValue; - } - else { - mySelectedSettings = null; - } - setOKActionEnabled(mySelectedSettings != null); - } - }); - myJBList.setCellRenderer(new ColoredListCellRenderer() { - @Override - protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) { - if (value instanceof RunnerAndConfigurationSettings) { - RunnerAndConfigurationSettings settings = (RunnerAndConfigurationSettings)value; - RunManagerEx runManager = RunManagerEx.getInstanceEx(myProject); - setIcon(runManager.getConfigurationIcon(settings)); - RunConfiguration configuration = settings.getConfiguration(); - append(configuration.getName(), runManager.isTemporary(configuration) - ? SimpleTextAttributes.GRAY_ATTRIBUTES - : SimpleTextAttributes.REGULAR_ATTRIBUTES); - } - } - }); - return new JBScrollPane(myJBList); - } - - @Nullable - RunnerAndConfigurationSettings getSelectedSettings() { - return isOK() ? mySelectedSettings : null; - } - } -} +/* + * 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.execution.impl; + +import com.intellij.execution.*; +import com.intellij.execution.configurations.ConfigurationType; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.execution.executors.DefaultRunExecutor; +import com.intellij.execution.process.ProcessAdapter; +import com.intellij.execution.process.ProcessEvent; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.runners.ProgramRunner; +import com.intellij.execution.ui.RunContentDescriptor; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.Key; +import com.intellij.ui.ColoredListCellRenderer; +import com.intellij.ui.SimpleTextAttributes; +import com.intellij.ui.components.JBList; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.util.concurrency.Semaphore; +import org.jdom.Attribute; +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import java.awt.*; +import java.util.*; +import java.util.List; + +/** + * @author Vassiliy Kudryashov + */ +public class RunConfigurationBeforeRunProvider +extends BeforeRunTaskProvider { + + public static final Key ID = Key.create("RunConfigurationTask"); + + private static final Logger LOG = Logger.getInstance("#com.intellij.execution.impl.RunConfigurationBeforeRunProvider"); + + private final Project myProject; + + public RunConfigurationBeforeRunProvider(Project project) { + myProject = project; + } + + @Override + public Key getId() { + return ID; + } + + @Override + public Icon getIcon() { + return AllIcons.Actions.Execute; + } + + @Override + public Icon getTaskIcon(RunConfigurableBeforeRunTask task) { + if (task.getSettings() == null) + return null; + return ProgramRunnerUtil.getConfigurationIcon(myProject, task.getSettings(), false); + } + + @Override + public String getName() { + return ExecutionBundle.message("before.launch.run.another.configuration"); + } + + @Override + public String getDescription(RunConfigurableBeforeRunTask task) { + if (task.getSettings() == null) { + return ExecutionBundle.message("before.launch.run.another.configuration"); + } + else { + return ExecutionBundle.message("before.launch.run.certain.configuration", task.getSettings().getName()); + } + } + + @Override + public boolean isConfigurable() { + return true; + } + + @Override + @Nullable + public RunConfigurableBeforeRunTask createTask(RunConfiguration runConfiguration) { + if (runConfiguration.getProject().isInitialized()) { + Collection configurations = + RunManagerImpl.getInstanceImpl(runConfiguration.getProject()).getSortedConfigurations(); + if (configurations.isEmpty() + || (configurations.size() == 1 && configurations.iterator().next().getConfiguration() == runConfiguration)) { + return null; + } + } + return new RunConfigurableBeforeRunTask(); + } + + @Override + public boolean configureTask(RunConfiguration runConfiguration, RunConfigurableBeforeRunTask task) { + SelectionDialog dialog = + new SelectionDialog(task.getSettings(), getAvailableConfigurations(runConfiguration)); + dialog.show(); + RunnerAndConfigurationSettings settings = dialog.getSelectedSettings(); + if (settings != null) { + task.setSettings(settings); + return true; + } + else { + return false; + } + } + + @NotNull + private List getAvailableConfigurations(RunConfiguration runConfiguration) { + Project project = runConfiguration.getProject(); + if (project == null || !project.isInitialized()) + return Collections.emptyList(); + final RunManagerImpl runManager = RunManagerImpl.getInstanceImpl(project); + + final ArrayList configurations + = new ArrayList(runManager.getSortedConfigurations()); + String executorId = DefaultRunExecutor.getRunExecutorInstance().getId(); + for (Iterator iterator = configurations.iterator(); iterator.hasNext();) { + RunnerAndConfigurationSettings settings = iterator.next(); + final ProgramRunner runner = ProgramRunnerUtil.getRunner(executorId, settings); + if (runner == null || settings.getConfiguration() == runConfiguration) + iterator.remove(); + } + return configurations; + } + + @Override + public boolean canExecuteTask(RunConfiguration configuration, + RunConfigurableBeforeRunTask task) { + RunnerAndConfigurationSettings settings = task.getSettings(); + if (settings == null) { + return false; + } + String executorId = DefaultRunExecutor.getRunExecutorInstance().getId(); + final ProgramRunner runner = ProgramRunnerUtil.getRunner(executorId, settings); + if (runner == null) + return false; + return runner.canRun(executorId, settings.getConfiguration()); + } + + @Override + public boolean executeTask(final DataContext dataContext, + RunConfiguration configuration, + final ExecutionEnvironment env, + RunConfigurableBeforeRunTask task) { + RunnerAndConfigurationSettings settings = task.getSettings(); + if (settings == null) { + return false; + } + final Executor executor = DefaultRunExecutor.getRunExecutorInstance(); + String executorId = executor.getId(); + final ProgramRunner runner = ProgramRunnerUtil.getRunner(executorId, settings); + if (runner == null) + return false; + final ExecutionEnvironment environment = new ExecutionEnvironment(runner, settings, myProject); + environment.putUserData(RunContentDescriptor.REUSE_CONTENT_PROHIBITED, env.getUserData(RunContentDescriptor.REUSE_CONTENT_PROHIBITED)); + if (!ExecutionTargetManager.canRun(settings, env.getExecutionTarget())) { + return false; + } + + if (!runner.canRun(executorId, environment.getRunProfile())) { + return false; + } + + else { + final Semaphore targetDone = new Semaphore(); + final boolean[] result = new boolean[1]; + try { + ApplicationManager.getApplication().invokeAndWait(new Runnable() { + + public void run() { + targetDone.down(); + try { + runner.execute(executor, environment, new ProgramRunner.Callback() { + @Override + public void processStarted(RunContentDescriptor descriptor) { + ProcessHandler processHandler = descriptor != null ? descriptor.getProcessHandler() : null; + if (processHandler != null) { + processHandler.addProcessListener(new ProcessAdapter() { + @Override + public void processTerminated(ProcessEvent event) { + result[0] = event.getExitCode() == 0; + targetDone.up(); + } + }); + } + } + }); + } + catch (ExecutionException e) { + LOG.error(e); + } + } + }, ModalityState.NON_MODAL); + } + catch (Exception e) { + LOG.error(e); + return false; + } + targetDone.waitFor(); + return result[0]; + } + } + + class RunConfigurableBeforeRunTask extends BeforeRunTask { + private String myConfigurationName; + private String myConfigurationType; + private boolean myInitialized = false; + + private RunnerAndConfigurationSettings mySettings; + + RunConfigurableBeforeRunTask() { + super(ID); + } + + @Override + public void writeExternal(Element element) { + super.writeExternal(element); + if (myConfigurationName != null && myConfigurationType != null) { + element.setAttribute("run_configuration_name", myConfigurationName); + element.setAttribute("run_configuration_type", myConfigurationType); + } + else if (mySettings != null) { + element.setAttribute("run_configuration_name", mySettings.getName()); + element.setAttribute("run_configuration_type", mySettings.getType().getId()); + } + } + + @Override + public void readExternal(Element element) { + super.readExternal(element); + Attribute configurationNameAttr = element.getAttribute("run_configuration_name"); + Attribute configurationTypeAttr = element.getAttribute("run_configuration_type"); + myConfigurationName = configurationNameAttr != null ? configurationNameAttr.getValue() : null; + myConfigurationType = configurationTypeAttr != null ? configurationTypeAttr.getValue() : null; + } + + void init() { + if (myInitialized) { + return; + } + if (myConfigurationName != null && myConfigurationType != null) { + Collection configurations = RunManagerImpl.getInstanceImpl(myProject).getSortedConfigurations(); + for (RunnerAndConfigurationSettings runConfiguration : configurations) { + ConfigurationType type = runConfiguration.getType(); + if (myConfigurationName.equals(runConfiguration.getName()) + && type != null + && myConfigurationType.equals(type.getId())) { + setSettings(runConfiguration); + return; + } + } + } + } + + void setSettings(RunnerAndConfigurationSettings settings) { + mySettings = settings; + myInitialized = true; + } + + RunnerAndConfigurationSettings getSettings() { + init(); + return mySettings; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + + RunConfigurableBeforeRunTask that = (RunConfigurableBeforeRunTask)o; + + if (myConfigurationName != null ? !myConfigurationName.equals(that.myConfigurationName) : that.myConfigurationName != null) return false; + if (myConfigurationType != null ? !myConfigurationType.equals(that.myConfigurationType) : that.myConfigurationType != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (myConfigurationName != null ? myConfigurationName.hashCode() : 0); + result = 31 * result + (myConfigurationType != null ? myConfigurationType.hashCode() : 0); + return result; + } + } + + private class SelectionDialog extends DialogWrapper { + private RunnerAndConfigurationSettings mySelectedSettings; + @NotNull private final List mySettings; + private JBList myJBList; + + private SelectionDialog(RunnerAndConfigurationSettings selectedSettings, @NotNull List settings) { + super(myProject); + setTitle(ExecutionBundle.message("before.launch.run.another.configuration.choose")); + mySelectedSettings = selectedSettings; + mySettings = settings; + init(); + myJBList.setSelectedValue(mySelectedSettings, true); + FontMetrics fontMetrics = myJBList.getFontMetrics(myJBList.getFont()); + int maxWidth = fontMetrics.stringWidth("m") * 30; + for (RunnerAndConfigurationSettings setting : settings) { + maxWidth = Math.max(fontMetrics.stringWidth(setting.getConfiguration().getName()), maxWidth); + } + maxWidth += 24;//icon and gap + myJBList.setMinimumSize(new Dimension(maxWidth, myJBList.getPreferredSize().height)); + } + + @Nullable + @Override + protected String getDimensionServiceKey() { + return "com.intellij.execution.impl.RunConfigurationBeforeRunProvider.dimensionServiceKey;"; + } + + @Override + protected JComponent createCenterPanel() { + myJBList = new JBList(mySettings); + myJBList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + myJBList.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + Object selectedValue = myJBList.getSelectedValue(); + if (selectedValue instanceof RunnerAndConfigurationSettings) { + mySelectedSettings = (RunnerAndConfigurationSettings)selectedValue; + } + else { + mySelectedSettings = null; + } + setOKActionEnabled(mySelectedSettings != null); + } + }); + myJBList.setCellRenderer(new ColoredListCellRenderer() { + @Override + protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) { + if (value instanceof RunnerAndConfigurationSettings) { + RunnerAndConfigurationSettings settings = (RunnerAndConfigurationSettings)value; + RunManagerEx runManager = RunManagerEx.getInstanceEx(myProject); + setIcon(runManager.getConfigurationIcon(settings)); + RunConfiguration configuration = settings.getConfiguration(); + append(configuration.getName(), runManager.isTemporary(configuration) + ? SimpleTextAttributes.GRAY_ATTRIBUTES + : SimpleTextAttributes.REGULAR_ATTRIBUTES); + } + } + }); + return new JBScrollPane(myJBList); + } + + @Nullable + RunnerAndConfigurationSettings getSelectedSettings() { + return isOK() ? mySelectedSettings : null; + } + } +} diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunnerAndConfigurationSettingsImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/RunnerAndConfigurationSettingsImpl.java index 2522de239c5b..33534ff601e1 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunnerAndConfigurationSettingsImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunnerAndConfigurationSettingsImpl.java @@ -1,448 +1,448 @@ -/* - * 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.execution.impl; - -import com.intellij.execution.*; -import com.intellij.execution.configurations.*; -import com.intellij.execution.runners.ProgramRunner; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Factory; -import com.intellij.openapi.util.InvalidDataException; -import com.intellij.openapi.util.JDOMExternalizable; -import com.intellij.openapi.util.WriteExternalException; -import org.jdom.Element; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -/** - * @author dyoma - */ -public class RunnerAndConfigurationSettingsImpl implements JDOMExternalizable, Cloneable, RunnerAndConfigurationSettings, Comparable { - private static final Logger LOG = Logger.getInstance("#com.intellij.execution.impl.RunnerAndConfigurationSettings"); - - @NonNls - private static final String RUNNER_ELEMENT = "RunnerSettings"; - @NonNls - private static final String CONFIGURATION_ELEMENT = "ConfigurationWrapper"; - @NonNls - private static final String RUNNER_ID = "RunnerId"; - @NonNls - private static final String CONFIGURATION_TYPE_ATTRIBUTE = "type"; - @NonNls - private static final String FACTORY_NAME_ATTRIBUTE = "factoryName"; - @NonNls - private static final String FOLDER_NAME = "folderName"; - @NonNls - private static final String TEMPLATE_FLAG_ATTRIBUTE = "default"; - @NonNls - public static final String NAME_ATTR = "name"; - @NonNls - protected static final String DUMMY_ELEMENT_NANE = "dummy"; - @NonNls - private static final String TEMPORARY_ATTRIBUTE = "temporary"; - @NonNls - private static final String EDIT_BEFORE_RUN = "editBeforeRun"; - @NonNls - private static final String SINGLETON = "singleton"; - - - /** for compatibility */ - @NonNls - private static final String TEMP_CONFIGURATION = "tempConfiguration"; - - private final RunManagerImpl myManager; - private RunConfiguration myConfiguration; - private boolean myIsTemplate; - - private final Map myRunnerSettings = new HashMap(); - private List myUnloadedRunnerSettings = null; - - private final Map myConfigurationPerRunnerSettings = new HashMap(); - private List myUnloadedConfigurationPerRunnerSettings = null; - - private boolean myTemporary; - private boolean myEditBeforeRun; - private boolean mySingleton; - private String myFolderName; - - public RunnerAndConfigurationSettingsImpl(RunManagerImpl manager) { - myManager = manager; - } - - public RunnerAndConfigurationSettingsImpl(RunManagerImpl manager, RunConfiguration configuration, boolean isTemplate) { - myManager = manager; - myConfiguration = configuration; - myIsTemplate = isTemplate; - } - - @Nullable - public ConfigurationFactory getFactory() { - return myConfiguration == null ? null : myConfiguration.getFactory(); - } - - public boolean isTemplate() { - return myIsTemplate; - } - - public boolean isTemporary() { - return myTemporary; - } - - public void setTemporary(boolean temporary) { - myTemporary = temporary; - } - - public RunConfiguration getConfiguration() { - return myConfiguration; - } - - public Factory createFactory() { - return new Factory() { - public RunnerAndConfigurationSettings create() { - RunConfiguration configuration = myConfiguration.getFactory().createConfiguration(ExecutionBundle.message("default.run.configuration.name"), myConfiguration); - return new RunnerAndConfigurationSettingsImpl(myManager, configuration, false); - } - }; - } - - public void setName(String name) { - myConfiguration.setName(name); - } - - public String getName() { - return myConfiguration.getName(); - } - - @Override - public void setEditBeforeRun(boolean b) { - myEditBeforeRun = b; - } - - @Override - public boolean isEditBeforeRun() { - return myEditBeforeRun; - } - - @Override - public void setSingleton(boolean singleton) { - mySingleton = singleton; - } - - @Override - public boolean isSingleton() { - return mySingleton; - } - - @Override - public void setFolderName(@Nullable String folderName) { - myFolderName = folderName; - } - - @Nullable - @Override - public String getFolderName() { - return myFolderName; - } - - @Nullable - private ConfigurationFactory getFactory(final Element element) { - final String typeName = element.getAttributeValue(CONFIGURATION_TYPE_ATTRIBUTE); - String factoryName = element.getAttributeValue(FACTORY_NAME_ATTRIBUTE); - return myManager.getFactory(typeName, factoryName); - } - - public void readExternal(Element element) throws InvalidDataException { - myIsTemplate = Boolean.valueOf(element.getAttributeValue(TEMPLATE_FLAG_ATTRIBUTE)).booleanValue(); - myTemporary = Boolean.valueOf(element.getAttributeValue(TEMPORARY_ATTRIBUTE)).booleanValue() || TEMP_CONFIGURATION.equals(element.getName()); - myEditBeforeRun = Boolean.valueOf(element.getAttributeValue(EDIT_BEFORE_RUN)).booleanValue(); - myFolderName = element.getAttributeValue(FOLDER_NAME); - // singleton is not configurable by user for template - if (!myIsTemplate) { - mySingleton = Boolean.valueOf(element.getAttributeValue(SINGLETON)).booleanValue(); - } - - final ConfigurationFactory factory = getFactory(element); - if (factory == null) return; - - if (myIsTemplate) { - mySingleton = factory.isConfigurationSingletonByDefault(); - myConfiguration = myManager.getConfigurationTemplate(factory).getConfiguration(); - } else { - final String name = element.getAttributeValue(NAME_ATTR); - // shouldn't call createConfiguration since it calls StepBeforeRunProviders that - // may not be loaded yet. This creates initialization order issue. - myConfiguration = myManager.doCreateConfiguration(name, factory, false); - } - - myConfiguration.readExternal(element); - List runners = element.getChildren(RUNNER_ELEMENT); - myUnloadedRunnerSettings = null; - for (final Object runner1 : runners) { - Element runnerElement = (Element) runner1; - String id = runnerElement.getAttributeValue(RUNNER_ID); - ProgramRunner runner = RunnerRegistry.getInstance().findRunnerById(id); - if (runner != null) { - RunnerSettings settings = createRunnerSettings(runner); - settings.readExternal(runnerElement); - myRunnerSettings.put(runner, settings); - } else { - if (myUnloadedRunnerSettings == null) myUnloadedRunnerSettings = new ArrayList(1); - myUnloadedRunnerSettings.add(runnerElement); - } - } - - List configurations = element.getChildren(CONFIGURATION_ELEMENT); - myUnloadedConfigurationPerRunnerSettings = null; - for (final Object configuration : configurations) { - Element configurationElement = (Element) configuration; - String id = configurationElement.getAttributeValue(RUNNER_ID); - ProgramRunner runner = RunnerRegistry.getInstance().findRunnerById(id); - if (runner != null) { - ConfigurationPerRunnerSettings settings = - new ConfigurationPerRunnerSettings(id, myConfiguration.createRunnerSettings(new InfoProvider(runner))); - settings.readExternal(configurationElement); - myConfigurationPerRunnerSettings.put(runner, settings); - } else { - if (myUnloadedConfigurationPerRunnerSettings == null) - myUnloadedConfigurationPerRunnerSettings = new ArrayList(1); - myUnloadedConfigurationPerRunnerSettings.add(configurationElement); - } - } - } - - public void writeExternal(final Element element) throws WriteExternalException { - final ConfigurationFactory factory = myConfiguration.getFactory(); - - if (!(myConfiguration instanceof UnknownRunConfiguration)) { - element.setAttribute(TEMPLATE_FLAG_ATTRIBUTE, String.valueOf(myIsTemplate)); - if (!myIsTemplate) { - element.setAttribute(NAME_ATTR, myConfiguration.getName()); - } - element.setAttribute(CONFIGURATION_TYPE_ATTRIBUTE, factory.getType().getId()); - element.setAttribute(FACTORY_NAME_ATTRIBUTE, factory.getName()); - if (myFolderName != null) { - element.setAttribute(FOLDER_NAME, myFolderName); - } - - if (isEditBeforeRun()) element.setAttribute(EDIT_BEFORE_RUN, String.valueOf(true)); - if (isSingleton()) element.setAttribute(SINGLETON, String.valueOf(true)); - if (myTemporary) { - element.setAttribute(TEMPORARY_ATTRIBUTE, Boolean.toString(myTemporary)); - } - } - - myConfiguration.writeExternal(element); - - if (!(myConfiguration instanceof UnknownRunConfiguration)) { - final Comparator runnerComparator = createRunnerComparator(); - writeRunnerSettings(runnerComparator, element); - writeConfigurationPerRunnerSettings(runnerComparator, element); - } - } - - private void writeConfigurationPerRunnerSettings(final Comparator runnerComparator, final Element element) - throws WriteExternalException { - final ArrayList configurationPerRunnerSettings = new ArrayList(); - for (ProgramRunner runner : myConfigurationPerRunnerSettings.keySet()) { - ConfigurationPerRunnerSettings settings = myConfigurationPerRunnerSettings.get(runner); - Element runnerElement = new Element(CONFIGURATION_ELEMENT); - settings.writeExternal(runnerElement); - runnerElement.setAttribute(RUNNER_ID, runner.getRunnerId()); - configurationPerRunnerSettings.add(runnerElement); - } - if (myUnloadedConfigurationPerRunnerSettings != null) { - for (Element unloadedCRunnerSetting : myUnloadedConfigurationPerRunnerSettings) { - configurationPerRunnerSettings.add((Element) unloadedCRunnerSetting.clone()); - } - } - Collections.sort(configurationPerRunnerSettings, runnerComparator); - for (Element runnerConfigurationSetting : configurationPerRunnerSettings) { - element.addContent(runnerConfigurationSetting); - } - } - - private void writeRunnerSettings(final Comparator runnerComparator, final Element element) throws WriteExternalException { - final ArrayList runnerSettings = new ArrayList(); - for (ProgramRunner runner : myRunnerSettings.keySet()) { - RunnerSettings settings = myRunnerSettings.get(runner); - Element runnerElement = new Element(RUNNER_ELEMENT); - settings.writeExternal(runnerElement); - runnerElement.setAttribute(RUNNER_ID, runner.getRunnerId()); - runnerSettings.add(runnerElement); - } - if (myUnloadedRunnerSettings != null) { - for (Element unloadedRunnerSetting : myUnloadedRunnerSettings) { - runnerSettings.add((Element) unloadedRunnerSetting.clone()); - } - } - Collections.sort(runnerSettings, runnerComparator); - for (Element runnerSetting : runnerSettings) { - element.addContent(runnerSetting); - } - } - - public void checkSettings() throws RuntimeConfigurationException { - checkSettings(null); - } - - public void checkSettings(@Nullable Executor executor) throws RuntimeConfigurationException { - myConfiguration.checkConfiguration(); - if (myConfiguration instanceof RunConfigurationBase) { - final RunConfigurationBase runConfigurationBase = (RunConfigurationBase) myConfiguration; - Set runners = new HashSet(); - runners.addAll(myRunnerSettings.keySet()); - runners.addAll(myConfigurationPerRunnerSettings.keySet()); - for (ProgramRunner runner : runners) { - if (executor == null || runner.canRun(executor.getId(), myConfiguration)) { - runConfigurationBase.checkRunnerSettings(runner, myRunnerSettings.get(runner), myConfigurationPerRunnerSettings.get(runner)); - } - } - if (executor != null) { - runConfigurationBase.checkSettingsBeforeRun(); - } - } - } - - @Override - public boolean canRunOn(@NotNull ExecutionTarget target) { - if (myConfiguration instanceof TargetAwareRunProfile) { - return ((TargetAwareRunProfile)myConfiguration).canRunOn(target); - } - return true; - } - - private static Comparator createRunnerComparator() { - return new Comparator() { - public int compare(final Element o1, final Element o2) { - final String attributeValue1 = o1.getAttributeValue(RUNNER_ID); - if (attributeValue1 == null) { - return 1; - - } - final String attributeValue2 = o2.getAttributeValue(RUNNER_ID); - if (attributeValue2 == null) { - return -1; - } - return attributeValue1.compareTo(attributeValue2); - } - }; - } - - @NotNull - public RunnerSettings getRunnerSettings(@NotNull ProgramRunner runner) { - RunnerSettings settings = myRunnerSettings.get(runner); - if (settings == null) { - settings = createRunnerSettings(runner); - myRunnerSettings.put(runner, settings); - } - return settings; - } - - @NotNull - public ConfigurationPerRunnerSettings getConfigurationSettings(@NotNull ProgramRunner runner) { - ConfigurationPerRunnerSettings settings = myConfigurationPerRunnerSettings.get(runner); - if (settings == null) { - settings = new ConfigurationPerRunnerSettings(runner.getRunnerId(), myConfiguration.createRunnerSettings(new InfoProvider(runner))); - myConfigurationPerRunnerSettings.put(runner, settings); - } - return settings; - } - - @Nullable - public ConfigurationType getType() { - return myConfiguration == null ? null : myConfiguration.getType(); - } - - public RunnerAndConfigurationSettings clone() { - RunnerAndConfigurationSettingsImpl copy = new RunnerAndConfigurationSettingsImpl(myManager, myConfiguration.clone(), false); - copy.importRunnerAndConfigurationSettings(this); - return copy; - } - - public void importRunnerAndConfigurationSettings(RunnerAndConfigurationSettingsImpl template) { - try { - for (ProgramRunner runner : template.myRunnerSettings.keySet()) { - RunnerSettings data = createRunnerSettings(runner); - myRunnerSettings.put(runner, data); - Element temp = new Element(DUMMY_ELEMENT_NANE); - template.myRunnerSettings.get(runner).writeExternal(temp); - data.readExternal(temp); - } - - for (ProgramRunner runner : template.myConfigurationPerRunnerSettings.keySet()) { - ConfigurationPerRunnerSettings data = - new ConfigurationPerRunnerSettings(runner.getRunnerId(), myConfiguration.createRunnerSettings(new InfoProvider(runner))); - myConfigurationPerRunnerSettings.put(runner, data); - Element temp = new Element(DUMMY_ELEMENT_NANE); - template.myConfigurationPerRunnerSettings.get(runner).writeExternal(temp); - data.readExternal(temp); - } - setSingleton(template.isSingleton()); - setEditBeforeRun(template.isEditBeforeRun()); - } - catch (WriteExternalException e) { - LOG.error(e); - } - catch (InvalidDataException e) { - LOG.error(e); - } - } - - private RunnerSettings createRunnerSettings(final ProgramRunner runner) { - return new RunnerSettings(runner.createConfigurationData(new InfoProvider(runner)), myConfiguration); - } - - public int compareTo(final Object o) { - if (o instanceof RunnerAndConfigurationSettings) { - return getName().compareTo(((RunnerAndConfigurationSettings) o).getName()); - } - return 0; - } - - @Override - public String toString() { - ConfigurationType type = getType(); - return (type != null ? type.getDisplayName() + ": " : "") + (isTemplate() ? "