From ba691da22654c3747e4b6fcac503fd12e0d446be Mon Sep 17 00:00:00 2001 From: nik Date: Wed, 28 Jul 2010 10:17:42 +0400 Subject: [PATCH 01/17] create valid manifest.mf file in artifact editor --- .../impl/elements/ManifestFileUtil.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/elements/ManifestFileUtil.java b/java/compiler/impl/src/com/intellij/packaging/impl/elements/ManifestFileUtil.java index f326e2f1e831..21433a5e74e3 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/elements/ManifestFileUtil.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/elements/ManifestFileUtil.java @@ -249,13 +249,19 @@ public class ManifestFileUtil { VirtualFile dir = files[0]; try { if (!dir.getName().equals(MANIFEST_DIR_NAME)) { - VirtualFile newDir = dir.findChild(MANIFEST_DIR_NAME); - if (newDir == null) { - newDir = dir.createChildDirectory(this, MANIFEST_DIR_NAME); - } - dir = newDir; + dir = VfsUtil.createDirectoryIfMissing(dir, MANIFEST_DIR_NAME); } - result.setResult(dir.createChildData(this, MANIFEST_FILE_NAME)); + final VirtualFile file = dir.createChildData(this, MANIFEST_FILE_NAME); + final OutputStream output = file.getOutputStream(this); + try { + final Manifest manifest = new Manifest(); + ManifestBuilder.setVersionAttribute(manifest.getMainAttributes()); + manifest.write(output); + } + finally { + output.close(); + } + result.setResult(file); } catch (IOException e) { exc.set(e); From 8bb207d4d1104dfcff46f131e85fd204f7c133c3 Mon Sep 17 00:00:00 2001 From: nik Date: Wed, 28 Jul 2010 10:32:17 +0400 Subject: [PATCH 02/17] publish artifacts as soon as they build --- build/scripts/dist.gant | 12 +++++++++--- build/scripts/utils.gant | 8 ++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/build/scripts/dist.gant b/build/scripts/dist.gant index 07e8849d3af9..2921df30192a 100644 --- a/build/scripts/dist.gant +++ b/build/scripts/dist.gant @@ -136,10 +136,12 @@ private def layoutWin(Map args, String home, Paths paths) { patchPropertiesFile(paths.distWin) ant.echo(file: "$paths.distWin/bin/idea.exe.vmoptions", message: args.vmoptions.replace(' ', '\n')) - ant.zip(zipfile: "$paths.artifacts/idea${args.buildNumber}.win.zip") { + def winZipPath = "$paths.artifacts/idea${args.buildNumber}.win.zip" + ant.zip(zipfile: winZipPath) { fileset(dir: paths.distAll) fileset(dir: paths.distWin) } + notifyArtifactBuilt(winZipPath) } private def layoutMac(Map args, String home, Paths paths) { @@ -170,7 +172,8 @@ private def layoutMac(Map args, String home, Paths paths) { def root = isEap() ? "${version}-${args.buildNumber}.app" : "IntelliJ IDEA ${version} CE.app" - ant.zip(zipfile: "$paths.artifacts/idea${args.buildNumber}.mac.zip") { + def macZipPath = "$paths.artifacts/idea${args.buildNumber}.mac.zip" + ant.zip(zipfile: macZipPath) { [paths.distAll, paths.distMac].each { tarfileset(dir: it, prefix: root) { exclude(name: "bin/*.sh") @@ -183,6 +186,7 @@ private def layoutMac(Map args, String home, Paths paths) { include(name: "Contents/MacOS/idea") } } + notifyArtifactBuilt(macZipPath) } def layoutLinux(Map args, String home, Paths paths) { @@ -216,7 +220,9 @@ def layoutLinux(Map args, String home, Paths paths) { } } - ant.gzip(src: tarPath, zipfile: "${tarPath}.gz") + def gzPath = "${tarPath}.gz" + ant.gzip(src: tarPath, zipfile: gzPath) ant.delete(file: tarPath) + notifyArtifactBuilt(gzPath) } diff --git a/build/scripts/utils.gant b/build/scripts/utils.gant index 8be15353d412..5f46552722dc 100644 --- a/build/scripts/utils.gant +++ b/build/scripts/utils.gant @@ -88,3 +88,11 @@ binding.setVariable("loadProject", { requireProperty("home", guessHome()) project.builder.buildInfoPrinter = new org.jetbrains.jps.teamcity.TeamcityBuildInfoPrinter() + +binding.setVariable("notifyArtifactBuilt", { String artifactPath -> + if (!artifactPath.startsWith(home)) { + project.error("Artifact path $artifactPath should start with $home") + } + def relativePath = artifactPath.substring(home.length()) + project.info("##teamcity[publishArtifacts '$relativePath']") +}) \ No newline at end of file From 60be87e12e6fe312fe7143def32990b2ddab7b3f Mon Sep 17 00:00:00 2001 From: Denis Zhdanov Date: Wed, 28 Jul 2010 11:09:21 +0400 Subject: [PATCH 03/17] IDEA-56409 Soft wrap, editing: AIOOBE at EditorImpl$EditorSizeContainer.changedUpdate() on removing a code that doesn't fit editor's width and height Added additional check for the situation when complete document is emptied --- .../src/com/intellij/openapi/editor/impl/EditorImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index 4e0f3a5e789c..6b743f8f0687 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -4649,7 +4649,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi public synchronized void update(int startLine, int newEndLine, int oldEndLine) { final int lineWidthSize = myLineWidths.size(); - if (lineWidthSize == 0) { + if (lineWidthSize == 0 || myDocument.getTextLength() <= 0) { reset(); } else { From 77d68210d82d3de0968bbf0b2d35d84dac7b3314 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 26 Jul 2010 15:52:45 +0400 Subject: [PATCH 04/17] New Java parser (work in progress) --- .../lang/java/parser/DeclarationParser.java | 122 ++++++++++++++++-- .../lang/java/parser/JavaParserUtil.java | 119 ++++++++++++++++- .../lang/java/parser/StatementParser.java | 30 +++++ .../psi/impl/source/tree/JavaElementType.java | 2 +- .../declarations/EmptyBody0.txt | 4 + .../declarations/EmptyBody1.txt | 5 + .../parser-partial/declarations/EnumBody0.txt | 6 + .../parser-partial/declarations/EnumBody1.txt | 28 ++++ .../parser-partial/declarations/EnumBody2.txt | 27 ++++ .../parser-partial/declarations/EnumBody3.txt | 28 ++++ .../parser-partial/declarations/EnumBody4.txt | 37 ++++++ .../parser-partial/declarations/EnumBody5.txt | 22 ++++ .../parser/partial/DeclarationParserTest.java | 45 +++++++ 13 files changed, 459 insertions(+), 16 deletions(-) create mode 100644 java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/EmptyBody0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/EmptyBody1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/EnumBody0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/EnumBody1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/EnumBody2.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/EnumBody3.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/EnumBody4.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/EnumBody5.txt create mode 100644 java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java diff --git a/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java b/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java index 268e9c2fd5ac..183accdbf72b 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java @@ -18,6 +18,7 @@ package com.intellij.lang.java.parser; import com.intellij.codeInsight.daemon.JavaErrorMessages; import com.intellij.lang.LighterASTNode; import com.intellij.lang.PsiBuilder; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.JavaTokenType; import com.intellij.psi.impl.source.tree.ElementType; import com.intellij.psi.impl.source.tree.JavaElementType; @@ -36,6 +37,8 @@ public class DeclarationParser { FILE, CLASS, CODE_BLOCK, ANNOTATION_INTERFACE } + private static final Logger LOG = Logger.getInstance("#com.intellij.lang.java.parser.DeclarationParser"); + private static final TokenSet AFTER_END_DECLARATION_SET = TokenSet.create(JavaElementType.FIELD, JavaElementType.METHOD); private DeclarationParser() { } @@ -48,10 +51,11 @@ public class DeclarationParser { marker.drop(); builder.advanceLexer(); + final PsiBuilder builderWrapper = braceMatchingBuilder(builder); if (isEnum) { - parseEnumConstants(builder); + parseEnumConstants(builderWrapper); } - parseClassBodyDeclarations(builder, isAnnotation); + parseClassBodyDeclarations(builderWrapper, isAnnotation); expectOrError(builder, JavaTokenType.RBRACE, JavaErrorMessages.message("expected.rbrace")); @@ -189,7 +193,7 @@ public class DeclarationParser { final PsiBuilder.Marker modList = parseModifierList(builder); if (expect(builder, JavaTokenType.AT)) { - if (tokenType == JavaTokenType.INTERFACE_KEYWORD) { + if (builder.getTokenType() == JavaTokenType.INTERFACE_KEYWORD) { return parseClassFromKeyword(builder, declaration, true); } else { @@ -197,9 +201,8 @@ public class DeclarationParser { return null; } } - else if (ElementType.CLASS_KEYWORD_BIT_SET.contains(tokenType)) { + else if (ElementType.CLASS_KEYWORD_BIT_SET.contains(builder.getTokenType())) { final PsiBuilder.Marker root = parseClassFromKeyword(builder, declaration, false); - if (context == Context.FILE) { // todo: append following declarations to root boolean declarationsAfterEnd = false; @@ -233,18 +236,100 @@ public class DeclarationParser { } if (context == Context.FILE) { - if (typeParams == null) { - error(builder, JavaErrorMessages.message("expected.class.or.interface")); - } - else { - typeParams.precede().errorBefore(JavaErrorMessages.message("expected.class.or.interface"), typeParams); - } + error(builder, JavaErrorMessages.message("expected.class.or.interface"), typeParams); declaration.drop(); return modList; } - // todo: implement - throw new UnsupportedOperationException(builder.toString() + context); + PsiBuilder.Marker type; + if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(builder.getTokenType())) { + type = parseTypeNotNull(builder); + } + else if (builder.getTokenType() == JavaTokenType.IDENTIFIER) { + final PsiBuilder.Marker idPos = builder.mark(); + type = parseTypeNotNull(builder); + if (builder.getTokenType() == JavaTokenType.LPARENTH) { // constructor + if (context == Context.CODE_BLOCK) { + declaration.rollbackTo(); + return null; + } + idPos.rollbackTo(); + if (typeParams == null) { + emptyElement(type, JavaElementType.TYPE_PARAMETER_LIST); + } + builder.advanceLexer(); + if (builder.getTokenType() != JavaTokenType.LPARENTH) { + declaration.drop(); + return null; + } + parseMethodFromLeftParenth(builder, declaration, false); + return declaration; + } + idPos.drop(); + } + else if (builder.getTokenType() == JavaTokenType.LBRACE) { + if (context == Context.CODE_BLOCK) { + error(builder, JavaErrorMessages.message("expected.identifier.or.type"), typeParams); + declaration.drop(); + return modList; + } + + final PsiBuilder.Marker codeBlock = StatementParser.parseCodeBlock(builder); + LOG.assertTrue(codeBlock != null); + + if (typeParams != null) { + final PsiBuilder.Marker error = typeParams.precede(); + error.errorBefore(JavaErrorMessages.message("unexpected.token"), codeBlock); + } + declaration.done(JavaElementType.CLASS_INITIALIZER); + return declaration; + } + else { + final PsiBuilder.Marker error; + if (typeParams != null) { + error = typeParams.precede(); + } + else { + error = builder.mark(); + } + error.error(JavaErrorMessages.message("expected.identifier.or.type")); + return modList; + } + + if (!expect(builder, JavaTokenType.IDENTIFIER)) { + if (context == Context.CODE_BLOCK /* todo: && modifierList.getFirstChildNode() == null */) { + declaration.rollbackTo(); + return null; + } + else { + if (typeParams != null) { + final PsiBuilder.Marker error = typeParams.precede(); + error.errorBefore(JavaErrorMessages.message("unexpected.token"), type); + } + builder.error(JavaErrorMessages.message("expected.identifier")); + declaration.drop(); + return modList; + } + } + + if (builder.getTokenType() == JavaTokenType.LPARENTH) { + if (context == Context.CLASS || context == Context.ANNOTATION_INTERFACE) { // method + if (typeParams == null) { + emptyElement(type, JavaElementType.TYPE_PARAMETER_LIST); + } + parseMethodFromLeftParenth(builder, declaration, (context == Context.ANNOTATION_INTERFACE)); + return declaration; + } + } + + return parseFieldOrLocalVariable(builder, declaration); + } + + @NotNull + private static PsiBuilder.Marker parseTypeNotNull(final PsiBuilder builder) { + final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseType(builder); + assert typeInfo != null : builder.getOriginalText(); + return typeInfo.marker; } @NotNull @@ -276,6 +361,17 @@ public class DeclarationParser { return modList; } + private static void parseMethodFromLeftParenth(final PsiBuilder builder, final PsiBuilder.Marker declaration, final boolean anno) { + // todo: implement + throw new UnsupportedOperationException(builder.toString() + declaration + anno); + } + + @Nullable + private static PsiBuilder.Marker parseFieldOrLocalVariable(final PsiBuilder builder, final PsiBuilder.Marker declaration) { + // todo: implement + throw new UnsupportedOperationException(builder.toString() + declaration); + } + @Nullable public static PsiBuilder.Marker parseAnnotations(final PsiBuilder builder) { PsiBuilder.Marker firstAnno = null; diff --git a/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java b/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java index 73937f311f81..89ed2e5c7fa5 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java @@ -15,12 +15,16 @@ */ package com.intellij.lang.java.parser; -import com.intellij.lang.PsiBuilder; -import com.intellij.lang.PsiBuilderUtil; +import com.intellij.lang.*; import com.intellij.openapi.util.Key; import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.JavaTokenType; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; +import com.intellij.util.diff.FlyweightCapableTreeStructure; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class JavaParserUtil { @@ -49,6 +53,15 @@ public class JavaParserUtil { builder.mark().error(message); } + public static void error(final PsiBuilder builder, final String message, @Nullable final PsiBuilder.Marker before) { + if (before == null) { + error(builder, message); + } + else { + before.precede().errorBefore(message, before); + } + } + public static boolean expectOrError(final PsiBuilder builder, final IElementType expectedType, final String errorMessage) { if (!PsiBuilderUtil.expect(builder, expectedType)) { error(builder, errorMessage); @@ -60,4 +73,106 @@ public class JavaParserUtil { public static void emptyElement(final PsiBuilder builder, final IElementType type) { builder.mark().done(type); } + + public static void emptyElement(final PsiBuilder.Marker before, final IElementType type) { + before.precede().done(type); + } + + public static PsiBuilder braceMatchingBuilder(final PsiBuilder builder) { + return new PsiBuilderAdapter(builder) { + private int braceCount = 1; + private int lastOffset = -1; + + @Override + public IElementType getTokenType() { + final IElementType tokenType = super.getTokenType(); + if (getCurrentOffset() != lastOffset) { + if (tokenType == JavaTokenType.LBRACE) { + braceCount++; + } + else if (tokenType == JavaTokenType.RBRACE) { + braceCount--; + } + lastOffset = getCurrentOffset(); + } + return (braceCount == 0 ? null : tokenType); + } + }; + } + + public static class PsiBuilderAdapter implements PsiBuilder { + protected final PsiBuilder myDelegate; + + public PsiBuilderAdapter(final PsiBuilder delegate) { + myDelegate = delegate; + } + + public CharSequence getOriginalText() { + return myDelegate.getOriginalText(); + } + + public void advanceLexer() { + myDelegate.advanceLexer(); + } + + @Nullable + public IElementType getTokenType() { + return myDelegate.getTokenType(); + } + + public void setTokenTypeRemapper(final ITokenTypeRemapper remapper) { + myDelegate.setTokenTypeRemapper(remapper); + } + + @Nullable @NonNls + public String getTokenText() { + return myDelegate.getTokenText(); + } + + public int getCurrentOffset() { + return myDelegate.getCurrentOffset(); + } + + public Marker mark() { + return myDelegate.mark(); + } + + public void error(final String messageText) { + myDelegate.error(messageText); + } + + public boolean eof() { + return myDelegate.eof(); + } + + public ASTNode getTreeBuilt() { + return myDelegate.getTreeBuilt(); + } + + public FlyweightCapableTreeStructure getLightTree() { + return myDelegate.getLightTree(); + } + + public void setDebugMode(final boolean dbgMode) { + myDelegate.setDebugMode(dbgMode); + } + + public void enforceCommentTokens(final TokenSet tokens) { + myDelegate.enforceCommentTokens(tokens); + } + + @Nullable + public LighterASTNode getLatestDoneMarker() { + return myDelegate.getLatestDoneMarker(); + } + + @Nullable + public T getUserData(@NotNull final Key key) { + return myDelegate.getUserData(key); + } + + public void putUserData(@NotNull final Key key, @Nullable final T value) { + myDelegate.putUserData(key, value); + } + } } diff --git a/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java b/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java new file mode 100644 index 000000000000..06d8532bd20d --- /dev/null +++ b/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java @@ -0,0 +1,30 @@ +/* + * 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.lang.java.parser; + +import com.intellij.lang.PsiBuilder; +import org.jetbrains.annotations.Nullable; + + +public class StatementParser { + private StatementParser() { } + + @Nullable + public static PsiBuilder.Marker parseCodeBlock(final PsiBuilder builder) { + // todo: implement + throw new UnsupportedOperationException(builder.toString()); + } +} diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java index b2968fa8dbef..c648d69da366 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java @@ -93,7 +93,7 @@ public interface JavaElementType { IElementType CLASS_OBJECT_ACCESS_EXPRESSION = new IJavaElementType("CLASS_OBJECT_ACCESS_EXPRESSION"); IElementType EMPTY_EXPRESSION = new IJavaElementType("EMPTY_EXPRESSION"); - IElementType EXPRESSION_LIST = new IJavaElementType("EXPRESSION_LIST"); + IElementType EXPRESSION_LIST = new IJavaElementType("EXPRESSION_LIST", true); IElementType EMPTY_STATEMENT = new IJavaElementType("EMPTY_STATEMENT"); IElementType BLOCK_STATEMENT = new IJavaElementType("BLOCK_STATEMENT"); diff --git a/java/java-tests/testData/psi/parser-partial/declarations/EmptyBody0.txt b/java/java-tests/testData/psi/parser-partial/declarations/EmptyBody0.txt new file mode 100644 index 000000000000..a83166937082 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/EmptyBody0.txt @@ -0,0 +1,4 @@ +PsiJavaFile:EmptyBody0.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/EmptyBody1.txt b/java/java-tests/testData/psi/parser-partial/declarations/EmptyBody1.txt new file mode 100644 index 000000000000..60988ad3eee2 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/EmptyBody1.txt @@ -0,0 +1,5 @@ +PsiJavaFile:EmptyBody1.java + PsiJavaToken:LBRACE('{') + PsiErrorElement:'}' expected + + PsiWhiteSpace(' ') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/EnumBody0.txt b/java/java-tests/testData/psi/parser-partial/declarations/EnumBody0.txt new file mode 100644 index 000000000000..a221d652117d --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/EnumBody0.txt @@ -0,0 +1,6 @@ +PsiJavaFile:EnumBody0.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/EnumBody1.txt b/java/java-tests/testData/psi/parser-partial/declarations/EnumBody1.txt new file mode 100644 index 000000000000..04b16bc1bcf1 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/EnumBody1.txt @@ -0,0 +1,28 @@ +PsiJavaFile:EnumBody1.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiEnumConstant:RED + PsiModifierList: + + PsiIdentifier:RED('RED') + PsiExpressionList + + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiEnumConstant:GREEN + PsiModifierList: + + PsiIdentifier:GREEN('GREEN') + PsiExpressionList + + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiEnumConstant:BLUE + PsiModifierList: + + PsiIdentifier:BLUE('BLUE') + PsiExpressionList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/EnumBody2.txt b/java/java-tests/testData/psi/parser-partial/declarations/EnumBody2.txt new file mode 100644 index 000000000000..0e6471320543 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/EnumBody2.txt @@ -0,0 +1,27 @@ +PsiJavaFile:EnumBody2.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiEnumConstant:RED + PsiModifierList: + + PsiIdentifier:RED('RED') + PsiExpressionList + + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiEnumConstant:GREEN + PsiModifierList: + + PsiIdentifier:GREEN('GREEN') + PsiExpressionList + + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiEnumConstant:BLUE + PsiModifierList: + + PsiIdentifier:BLUE('BLUE') + PsiExpressionList + + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/EnumBody3.txt b/java/java-tests/testData/psi/parser-partial/declarations/EnumBody3.txt new file mode 100644 index 000000000000..ea0d456d4d1b --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/EnumBody3.txt @@ -0,0 +1,28 @@ +PsiJavaFile:EnumBody3.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiEnumConstant:RED + PsiModifierList: + + PsiIdentifier:RED('RED') + PsiExpressionList + + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiEnumConstant:GREEN + PsiModifierList: + + PsiIdentifier:GREEN('GREEN') + PsiExpressionList + + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiEnumConstant:BLUE + PsiModifierList: + + PsiIdentifier:BLUE('BLUE') + PsiExpressionList + + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/EnumBody4.txt b/java/java-tests/testData/psi/parser-partial/declarations/EnumBody4.txt new file mode 100644 index 000000000000..f20ec90ba3f4 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/EnumBody4.txt @@ -0,0 +1,37 @@ +PsiJavaFile:EnumBody4.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiEnumConstant:RED + PsiModifierList: + + PsiIdentifier:RED('RED') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiLiteralExpression:0 + PsiJavaToken:INTEGER_LITERAL('0') + PsiJavaToken:RPARENTH(')') + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiEnumConstant:GREEN + PsiModifierList: + + PsiIdentifier:GREEN('GREEN') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiJavaToken:RPARENTH(')') + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiEnumConstant:BLUE + PsiModifierList: + + PsiIdentifier:BLUE('BLUE') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiLiteralExpression:2 + PsiJavaToken:INTEGER_LITERAL('2') + PsiJavaToken:RPARENTH(')') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/EnumBody5.txt b/java/java-tests/testData/psi/parser-partial/declarations/EnumBody5.txt new file mode 100644 index 000000000000..573f3471c668 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/EnumBody5.txt @@ -0,0 +1,22 @@ +PsiJavaFile:EnumBody5.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiEnumConstant:A + PsiModifierList:@ANNOTATION + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:ANNOTATION + PsiIdentifier:ANNOTATION('ANNOTATION') + PsiReferenceParameterList + + PsiAnnotationParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:A('A') + PsiExpressionList + PsiJavaToken:LPARENTH('(') + PsiLiteralExpression:10 + PsiJavaToken:INTEGER_LITERAL('10') + PsiJavaToken:RPARENTH(')') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java new file mode 100644 index 000000000000..2b5e8486967c --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java @@ -0,0 +1,45 @@ +/* + * 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.lang.java.parser.partial; + +import com.intellij.lang.PsiBuilder; +import com.intellij.lang.java.parser.DeclarationParser; +import com.intellij.lang.java.parser.JavaParsingTestCase; + + +public class DeclarationParserTest extends JavaParsingTestCase { + public DeclarationParserTest() { + super("parser-partial/declarations"); + } + + public void testEmptyBody0() { doParserTest("{ }", false, false); } + public void testEmptyBody1() { doParserTest("{ ", false, false); } + + public void testEnumBody0() { doParserTest("{ ; }", false, true); } + public void testEnumBody1() { doParserTest("{ RED, GREEN, BLUE; }", false, true); } + public void testEnumBody2() { doParserTest("{ RED, GREEN, BLUE }", false, true); } + public void testEnumBody3() { doParserTest("{ RED, GREEN, BLUE, }", false, true); } + public void testEnumBody4() { doParserTest("{ RED(0), GREEN(1), BLUE(2); }", false, true); } + public void testEnumBody5() { doParserTest("{ @ANNOTATION A(10) }", false, true); } + + private void doParserTest(final String text, final boolean isAnnotation, final boolean isEnum) { + doParserTest(text, new Parser() { + public void parse(final PsiBuilder builder) { + DeclarationParser.parseClassBodyWithBraces(builder, isAnnotation, isEnum); + } + }); + } +} From 72d3a0e47194d958c9f6519c6b24acd6a7d52960 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 26 Jul 2010 20:54:07 +0400 Subject: [PATCH 05/17] New Java parser (work in progress) --- .../lang/java/parser/DeclarationParser.java | 78 +++++++++++++++++-- .../declarations/FieldMulti.txt | 22 ++++++ .../declarations/FieldSimple.txt | 18 +++++ .../declarations/MissingInitializer.txt | 16 ++++ .../MissingInitializerExpression.txt | 16 ++++ .../declarations/MultiLineUnclosed.txt | 23 ++++++ .../declarations/UnclosedBracket.txt | 15 ++++ .../declarations/UnclosedComma.txt | 15 ++++ .../declarations/UnclosedSemicolon.txt | 14 ++++ .../parser/partial/DeclarationParserTest.java | 9 +++ 10 files changed, 220 insertions(+), 6 deletions(-) create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/FieldMulti.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/FieldSimple.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/MissingInitializer.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/MissingInitializerExpression.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/MultiLineUnclosed.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/UnclosedBracket.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/UnclosedComma.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/UnclosedSemicolon.txt diff --git a/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java b/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java index 183accdbf72b..0357b1e11cfe 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java @@ -303,8 +303,7 @@ public class DeclarationParser { } else { if (typeParams != null) { - final PsiBuilder.Marker error = typeParams.precede(); - error.errorBefore(JavaErrorMessages.message("unexpected.token"), type); + typeParams.precede().errorBefore(JavaErrorMessages.message("unexpected.token"), type); } builder.error(JavaErrorMessages.message("expected.identifier")); declaration.drop(); @@ -322,7 +321,10 @@ public class DeclarationParser { } } - return parseFieldOrLocalVariable(builder, declaration); + if (typeParams != null) { + typeParams.precede().errorBefore(JavaErrorMessages.message("unexpected.token"), type); + } + return parseFieldOrLocalVariable(builder, declaration, context); } @NotNull @@ -367,9 +369,73 @@ public class DeclarationParser { } @Nullable - private static PsiBuilder.Marker parseFieldOrLocalVariable(final PsiBuilder builder, final PsiBuilder.Marker declaration) { - // todo: implement - throw new UnsupportedOperationException(builder.toString() + declaration); + private static PsiBuilder.Marker parseFieldOrLocalVariable(final PsiBuilder builder, final PsiBuilder.Marker declaration, + final Context context) { + final IElementType varType; + if (context == Context.CLASS || context == Context.ANNOTATION_INTERFACE) { + varType = JavaElementType.FIELD; + } + else if (context == Context.CODE_BLOCK) { + varType = JavaElementType.LOCAL_VARIABLE; + } + else { + LOG.error("Unexpected context: " + context); + declaration.drop(); + return null; + } + + PsiBuilder.Marker variable = declaration; + boolean openMarker = true; + boolean eatSemicolon = true; + boolean expectSemicolon = true; + while (true) { + while (expect(builder, JavaTokenType.LBRACKET)) { + if (!expect(builder, JavaTokenType.RBRACKET)) { + error(builder, JavaErrorMessages.message("expected.rbracket")); + expectSemicolon = false; + break; + } + } + + if (expect(builder, JavaTokenType.EQ)) { + final PsiBuilder.Marker expr = ExpressionParser.parse(builder); + if (expr == null) { + error(builder, JavaErrorMessages.message("expected.expression")); + expectSemicolon = false; + break; + } + } + + if (builder.getTokenType() == JavaTokenType.COMMA) { + variable.done(varType); + builder.advanceLexer(); + variable = builder.mark(); + } + else { + break; + } + + if (!expect(builder, JavaTokenType.IDENTIFIER)) { + variable.drop(); + error(builder, JavaErrorMessages.message("expected.identifier")); + openMarker = false; + eatSemicolon = false; + break; + } + } + + if (eatSemicolon) { + if (!expect(builder, JavaTokenType.SEMICOLON) && expectSemicolon) { + error(builder, JavaErrorMessages.message("expected.semicolon")); + } + // todo: special treatment - see DeclarationParserTest.testMultiLineUnclosed() + } + + if (openMarker) { + variable.done(varType); + } + + return declaration; } @Nullable diff --git a/java/java-tests/testData/psi/parser-partial/declarations/FieldMulti.txt b/java/java-tests/testData/psi/parser-partial/declarations/FieldMulti.txt new file mode 100644 index 000000000000..22138d62d7bf --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/FieldMulti.txt @@ -0,0 +1,22 @@ +PsiJavaFile:FieldMulti.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiField:field1 + PsiModifierList: + + PsiTypeElement:int + PsiKeyword:int('int') + PsiWhiteSpace(' ') + PsiIdentifier:field1('field1') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:0 + PsiJavaToken:INTEGER_LITERAL('0') + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiField:field2 + PsiIdentifier:field2('field2') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/FieldSimple.txt b/java/java-tests/testData/psi/parser-partial/declarations/FieldSimple.txt new file mode 100644 index 000000000000..59dc28ffe43c --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/FieldSimple.txt @@ -0,0 +1,18 @@ +PsiJavaFile:FieldSimple.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiField:field + PsiModifierList: + + PsiTypeElement:int + PsiKeyword:int('int') + PsiWhiteSpace(' ') + PsiIdentifier:field('field') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:0 + PsiJavaToken:INTEGER_LITERAL('0') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/MissingInitializer.txt b/java/java-tests/testData/psi/parser-partial/declarations/MissingInitializer.txt new file mode 100644 index 000000000000..ad9b3b26e18c --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/MissingInitializer.txt @@ -0,0 +1,16 @@ +PsiJavaFile:MissingInitializer.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiField:field + PsiModifierList: + + PsiTypeElement:int + PsiKeyword:int('int') + PsiWhiteSpace(' ') + PsiIdentifier:field('field') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiErrorElement:Expression expected + + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/MissingInitializerExpression.txt b/java/java-tests/testData/psi/parser-partial/declarations/MissingInitializerExpression.txt new file mode 100644 index 000000000000..e7dac65bea9c --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/MissingInitializerExpression.txt @@ -0,0 +1,16 @@ +PsiJavaFile:MissingInitializerExpression.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiField:field + PsiModifierList: + + PsiTypeElement:int + PsiKeyword:int('int') + PsiWhiteSpace(' ') + PsiIdentifier:field('field') + PsiJavaToken:EQ('=') + PsiErrorElement:Expression expected + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/MultiLineUnclosed.txt b/java/java-tests/testData/psi/parser-partial/declarations/MultiLineUnclosed.txt new file mode 100644 index 000000000000..d44d8913422d --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/MultiLineUnclosed.txt @@ -0,0 +1,23 @@ +PsiJavaFile:MultiLineUnclosed.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiModifierList: + + PsiTypeElement:int + PsiKeyword:int('int') + PsiErrorElement:Identifier expected + + PsiWhiteSpace(' \n ') + PsiField:o + PsiModifierList: + + PsiTypeElement:Object + PsiJavaCodeReferenceElement:Object + PsiIdentifier:Object('Object') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:o('o') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/UnclosedBracket.txt b/java/java-tests/testData/psi/parser-partial/declarations/UnclosedBracket.txt new file mode 100644 index 000000000000..e17119cb9b42 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/UnclosedBracket.txt @@ -0,0 +1,15 @@ +PsiJavaFile:UnclosedBracket.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiField:field + PsiModifierList: + + PsiTypeElement:int + PsiKeyword:int('int') + PsiWhiteSpace(' ') + PsiIdentifier:field('field') + PsiJavaToken:LBRACKET('[') + PsiErrorElement:']' expected + + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/UnclosedComma.txt b/java/java-tests/testData/psi/parser-partial/declarations/UnclosedComma.txt new file mode 100644 index 000000000000..83f9e32e72d9 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/UnclosedComma.txt @@ -0,0 +1,15 @@ +PsiJavaFile:UnclosedComma.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiField:field + PsiModifierList: + + PsiTypeElement:int + PsiKeyword:int('int') + PsiWhiteSpace(' ') + PsiIdentifier:field('field') + PsiJavaToken:COMMA(',') + PsiErrorElement:Identifier expected + + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/UnclosedSemicolon.txt b/java/java-tests/testData/psi/parser-partial/declarations/UnclosedSemicolon.txt new file mode 100644 index 000000000000..f185e9852b30 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/UnclosedSemicolon.txt @@ -0,0 +1,14 @@ +PsiJavaFile:UnclosedSemicolon.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiField:field + PsiModifierList: + + PsiTypeElement:int + PsiKeyword:int('int') + PsiWhiteSpace(' ') + PsiIdentifier:field('field') + PsiErrorElement:';' expected + + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java index 2b5e8486967c..7d516c955c89 100644 --- a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java @@ -35,6 +35,15 @@ public class DeclarationParserTest extends JavaParsingTestCase { public void testEnumBody4() { doParserTest("{ RED(0), GREEN(1), BLUE(2); }", false, true); } public void testEnumBody5() { doParserTest("{ @ANNOTATION A(10) }", false, true); } + public void testFieldSimple() { doParserTest("{ int field = 0; }", false, false); } + public void testFieldMulti() { doParserTest("{ int field1 = 0, field2; }", false, false); } + public void testUnclosedBracket() { doParserTest("{ int field[ }", false, false); } + public void testMissingInitializer() { doParserTest("{ int field = }", false, false); } + public void testUnclosedComma() { doParserTest("{ int field, }", false, false); } + public void testUnclosedSemicolon() { doParserTest("{ int field }", false, false); } + public void testMissingInitializerExpression() { doParserTest("{ int field=; }", false, false); } + //public void testMultiLineUnclosed() { doParserTest("{ int \n Object o; }", false, false); } // todo: implement + private void doParserTest(final String text, final boolean isAnnotation, final boolean isEnum) { doParserTest(text, new Parser() { public void parse(final PsiBuilder builder) { From c2cb3deb5519889ed7dc314233e190925858b9f4 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 27 Jul 2010 12:57:26 +0400 Subject: [PATCH 06/17] New Java parser (work in progress) --- .../lang/java/parser/ReferenceParser.java | 15 +++++++++++++++ .../psi/parser-partial/references/Type5.txt | 11 +++++++++++ .../java/parser/partial/ReferenceParserTest.java | 3 ++- 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/psi/parser-partial/references/Type5.txt diff --git a/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java b/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java index 8831468fabe3..62fa6078d640 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java @@ -53,6 +53,21 @@ public class ReferenceParser { return typeInfo != null ? typeInfo.marker : null; } + @Nullable + public static PsiBuilder.Marker parseTypeWithEllipsis(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard) { + final TypeInfo typeInfo = parseTypeWithInfo(builder, eatLastDot, wildcard); + if (typeInfo == null) return null; + + PsiBuilder.Marker type = typeInfo.marker; + if (builder.getTokenType() == JavaTokenType.ELLIPSIS) { + type = typeInfo.marker.precede(); + builder.advanceLexer(); + type.done(JavaElementType.TYPE); + } + + return type; + } + @Nullable private static TypeInfo parseTypeWithInfo(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard) { if (builder.getTokenType() == null) return null; diff --git a/java/java-tests/testData/psi/parser-partial/references/Type5.txt b/java/java-tests/testData/psi/parser-partial/references/Type5.txt new file mode 100644 index 000000000000..74a43fc43766 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/references/Type5.txt @@ -0,0 +1,11 @@ +PsiJavaFile:Type5.java + PsiTypeElement:Object[]... + PsiTypeElement:Object[] + PsiTypeElement:Object + PsiJavaCodeReferenceElement:Object + PsiIdentifier:Object('Object') + PsiReferenceParameterList + + PsiJavaToken:LBRACKET('[') + PsiJavaToken:RBRACKET(']') + PsiJavaToken:ELLIPSIS('...') \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ReferenceParserTest.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ReferenceParserTest.java index da5651bf4eb9..77e1e8cb3f1e 100644 --- a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ReferenceParserTest.java +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ReferenceParserTest.java @@ -34,6 +34,7 @@ public class ReferenceParserTest extends JavaParsingTestCase { public void testType2() { doTypeParserTest("int[]", false); } public void testType3() { doTypeParserTest("int[][", false); } public void testType4() { doTypeParserTest("Map>", false); } + public void testType5() { doTypeParserTest("Object[]...", false); } public void testTypeParams0() { doTypeParamsParserTest(""); } public void testTypeParams1() { doTypeParamsParserTest(""); } @@ -55,7 +56,7 @@ public class ReferenceParserTest extends JavaParsingTestCase { private void doTypeParserTest(final String text, final boolean incomplete) { doParserTest(text, new Parser() { public void parse(final PsiBuilder builder) { - ReferenceParser.parseType(builder, incomplete, false); + ReferenceParser.parseTypeWithEllipsis(builder, incomplete, false); } }); } From 46dad645d85704a8dd865b51a4ea74e37e2c4d02 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 27 Jul 2010 13:11:59 +0400 Subject: [PATCH 07/17] Parser message bundled --- .../intellij/psi/impl/source/parsing/DeclarationParsing.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/psi/impl/source/parsing/DeclarationParsing.java b/java/java-impl/src/com/intellij/psi/impl/source/parsing/DeclarationParsing.java index 95219c560609..8061c0d256e3 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/parsing/DeclarationParsing.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/parsing/DeclarationParsing.java @@ -1086,7 +1086,7 @@ public class DeclarationParsing extends Parsing { if (type == null) { type = ASTFactory.composite(JavaElementType.TYPE); - param.rawAddChildren(Factory.createErrorElement("Parameter type missing")); + param.rawAddChildren(Factory.createErrorElement(JavaErrorMessages.message("expected.type"))); } param.rawAddChildren(type); From fb03ab9d6d883402fea17f4bc92765b77f60fe4d Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 27 Jul 2010 15:18:22 +0400 Subject: [PATCH 08/17] Cleanup --- .../psi/impl/source/parsing/StatementParsing.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/impl/source/parsing/StatementParsing.java b/java/java-impl/src/com/intellij/psi/impl/source/parsing/StatementParsing.java index 89c35b07456f..c706eb3d1bb8 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/parsing/StatementParsing.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/parsing/StatementParsing.java @@ -111,6 +111,7 @@ public class StatementParsing extends Parsing { return dummyRoot.getFirstChildNode(); } + @Nullable public TreeElement parseCodeBlock(Lexer lexer, boolean deep) { if (lexer.getTokenType() != JavaTokenType.LBRACE) return null; Lexer badLexer = lexer instanceof StoppableLexerAdapter ? ((StoppableLexerAdapter)lexer).getDelegate() : lexer; @@ -151,11 +152,10 @@ public class StatementParsing extends Parsing { List list = new SmartList(); while (true) { final IElementType type = lexer.getTokenType(); - if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(type) || type == JavaTokenType.IDENTIFIER || ElementType.MODIFIER_BIT_SET.contains(type) || - type == JavaTokenType.LT || type == JavaTokenType.GT || type == JavaTokenType.GTGT || type == JavaTokenType.GTGTGT || type == - JavaTokenType.COMMA || type == - JavaTokenType.DOT || - type == JavaTokenType.EXTENDS_KEYWORD || type == JavaTokenType.IMPLEMENTS_KEYWORD) { + if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(type) || ElementType.MODIFIER_BIT_SET.contains(type) || + type == JavaTokenType.IDENTIFIER || type == JavaTokenType.LT || type == JavaTokenType.GT || + type == JavaTokenType.GTGT || type == JavaTokenType.GTGTGT || type == JavaTokenType.COMMA || + type == JavaTokenType.DOT || type == JavaTokenType.EXTENDS_KEYWORD || type == JavaTokenType.IMPLEMENTS_KEYWORD) { list.add(type); lexer.advance(); } else { From c654288e18b5d5fb677717682bf5e6c0e5806d3a Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 27 Jul 2010 17:38:06 +0400 Subject: [PATCH 09/17] New Java parser (work in progress) --- .../lang/java/parser/DeclarationParser.java | 186 ++++++++++++++++-- .../lang/java/parser/JavaParserUtil.java | 4 +- .../lang/java/parser/ReferenceParser.java | 26 ++- .../lang/java/parser/StatementParser.java | 14 ++ .../declarations/CompletionHack0.txt | 33 ++++ .../declarations/CompletionHack1.txt | 31 +++ .../parser-partial/declarations/Errors.txt | 45 +++++ .../declarations/GenericMethod.txt | 91 +++++++++ .../declarations/GenericMethodErrors.txt | 43 ++++ .../declarations/MethodNormal0.txt | 24 +++ .../declarations/MethodNormal1.txt | 20 ++ .../parser-partial/declarations/Unclosed0.txt | 21 ++ .../parser-partial/declarations/Unclosed1.txt | 22 +++ .../parser-partial/declarations/Unclosed2.txt | 37 ++++ .../parser-partial/declarations/Unclosed3.txt | 29 +++ .../parser-partial/declarations/Unclosed4.txt | 33 ++++ .../parser-partial/declarations/Unclosed5.txt | 30 +++ .../declarations/WildcardParsing.txt | 55 ++++++ .../parser-partial/references/TypeParams5.txt | 4 +- .../parser-partial/references/TypeParams7.txt | 4 +- .../parser/partial/DeclarationParserTest.java | 17 ++ 21 files changed, 730 insertions(+), 39 deletions(-) create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/CompletionHack0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/CompletionHack1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/Errors.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/GenericMethod.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/GenericMethodErrors.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/MethodNormal0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/MethodNormal1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/Unclosed0.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/Unclosed1.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/Unclosed2.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/Unclosed3.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/Unclosed4.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/Unclosed5.txt create mode 100644 java/java-tests/testData/psi/parser-partial/declarations/WildcardParsing.txt diff --git a/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java b/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java index 0357b1e11cfe..63908d4e6e4c 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.daemon.JavaErrorMessages; import com.intellij.lang.LighterASTNode; import com.intellij.lang.PsiBuilder; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Pair; import com.intellij.psi.JavaTokenType; import com.intellij.psi.impl.source.tree.ElementType; import com.intellij.psi.impl.source.tree.JavaElementType; @@ -190,7 +191,8 @@ public class DeclarationParser { final PsiBuilder.Marker declaration = builder.mark(); - final PsiBuilder.Marker modList = parseModifierList(builder); + final Pair modListInfo = parseModifierList(builder); + final PsiBuilder.Marker modList = modListInfo.first; if (expect(builder, JavaTokenType.AT)) { if (builder.getTokenType() == JavaTokenType.INTERFACE_KEYWORD) { @@ -255,15 +257,14 @@ public class DeclarationParser { } idPos.rollbackTo(); if (typeParams == null) { - emptyElement(type, JavaElementType.TYPE_PARAMETER_LIST); + emptyElement(builder, JavaElementType.TYPE_PARAMETER_LIST); } builder.advanceLexer(); if (builder.getTokenType() != JavaTokenType.LPARENTH) { - declaration.drop(); + declaration.rollbackTo(); return null; } - parseMethodFromLeftParenth(builder, declaration, false); - return declaration; + return parseMethodFromLeftParenth(builder, declaration, false); } idPos.drop(); } @@ -297,7 +298,7 @@ public class DeclarationParser { } if (!expect(builder, JavaTokenType.IDENTIFIER)) { - if (context == Context.CODE_BLOCK /* todo: && modifierList.getFirstChildNode() == null */) { + if (context == Context.CODE_BLOCK && modListInfo.second) { declaration.rollbackTo(); return null; } @@ -316,8 +317,7 @@ public class DeclarationParser { if (typeParams == null) { emptyElement(type, JavaElementType.TYPE_PARAMETER_LIST); } - parseMethodFromLeftParenth(builder, declaration, (context == Context.ANNOTATION_INTERFACE)); - return declaration; + return parseMethodFromLeftParenth(builder, declaration, (context == Context.ANNOTATION_INTERFACE)); } } @@ -335,14 +335,16 @@ public class DeclarationParser { } @NotNull - private static PsiBuilder.Marker parseModifierList(final PsiBuilder builder) { + private static Pair parseModifierList(final PsiBuilder builder) { final PsiBuilder.Marker modList = builder.mark(); + boolean isEmpty = true; while (true) { final IElementType tokenType = builder.getTokenType(); if (tokenType == null) break; if (ElementType.MODIFIER_BIT_SET.contains(tokenType)) { builder.advanceLexer(); + isEmpty = false; } else if (tokenType == JavaTokenType.AT) { final PsiBuilder.Marker pos = builder.mark(); @@ -353,6 +355,7 @@ public class DeclarationParser { break; } parseAnnotation(builder); + isEmpty = false; } else { break; @@ -360,12 +363,149 @@ public class DeclarationParser { } modList.done(JavaElementType.MODIFIER_LIST); - return modList; + return Pair.create(modList, isEmpty); } - private static void parseMethodFromLeftParenth(final PsiBuilder builder, final PsiBuilder.Marker declaration, final boolean anno) { - // todo: implement - throw new UnsupportedOperationException(builder.toString() + declaration + anno); + private static PsiBuilder.Marker parseMethodFromLeftParenth(final PsiBuilder builder, final PsiBuilder.Marker declaration, + final boolean anno) { + parseParameterList(builder); + + eatBrackets(builder); + + if (areTypeAnnotationsSupported(builder)) { + final PsiBuilder.Marker receiver = builder.mark(); + final PsiBuilder.Marker annotations = parseAnnotations(builder); + if (annotations != null) { + receiver.done(JavaElementType.METHOD_RECEIVER); + } + else { + receiver.drop(); + } + } + + ReferenceParser.parseReferenceList(builder, JavaTokenType.THROWS_KEYWORD, JavaElementType.THROWS_LIST, JavaTokenType.COMMA); + + if (anno && expect(builder, JavaTokenType.DEFAULT_KEYWORD)) { + parseAnnotationValue(builder); + } + + final IElementType tokenType = builder.getTokenType(); + if (tokenType == JavaTokenType.SEMICOLON) { + builder.advanceLexer(); + } + else if (tokenType == JavaTokenType.LBRACE) { + StatementParser.parseCodeBlock(builder); + } + else { + error(builder, JavaErrorMessages.message("expected.lbrace.or.semicolon")); + // todo: special treatment - like in fields (DeclarationParserTest.testMultiLineUnclosed()) + } + + declaration.done(anno ? JavaElementType.ANNOTATION_METHOD : JavaElementType.METHOD); + return declaration; + } + + @NotNull + private static PsiBuilder.Marker parseParameterList(final PsiBuilder builder) { + assert builder.getTokenType() == JavaTokenType.LPARENTH : builder.getTokenType(); + final PsiBuilder.Marker paramList = builder.mark(); + builder.advanceLexer(); + + PsiBuilder.Marker invalidElements = null; + boolean commaExpected = false; + int paramCount = 0; + while (true) { + final IElementType tokenType = builder.getTokenType(); + if (tokenType == null || tokenType == JavaTokenType.RPARENTH) { + boolean noLastParam = !commaExpected && paramCount > 0; + if (noLastParam) { + error(builder, JavaErrorMessages.message("expected.identifier.or.type")); + } + if (!expect(builder, JavaTokenType.RPARENTH)) { + if (!noLastParam) { + error(builder, JavaErrorMessages.message("expected.rparen")); + } + } + break; + } + + if (commaExpected) { + if (builder.getTokenType() == JavaTokenType.COMMA) { + commaExpected = false; + if (invalidElements != null) { + invalidElements.error(JavaErrorMessages.message("expected.parameter")); + invalidElements = null; + } + builder.advanceLexer(); + continue; + } + } + else { + final PsiBuilder.Marker param = parseParameter(builder, true); + if (param != null) { + commaExpected = true; + if (invalidElements != null) { + invalidElements.errorBefore(JavaErrorMessages.message("expected.comma"), param); + invalidElements = null; + } + paramCount++; + continue; + } + } + + if (invalidElements == null) { + if (builder.getTokenType() == JavaTokenType.COMMA) { + error(builder, JavaErrorMessages.message("expected.parameter")); + builder.advanceLexer(); + continue; + } + else { + invalidElements = builder.mark(); + } + } + + // adding a reference, not simple tokens allows "Browse .." to work well + final PsiBuilder.Marker ref = ReferenceParser.parseJavaCodeReference(builder, true, true, false); + if (ref == null && builder.getTokenType() != null) { + builder.advanceLexer(); + } + } + + if (invalidElements != null) { + invalidElements.error(commaExpected ? JavaErrorMessages.message("expected.comma") : JavaErrorMessages.message("expected.parameter")); + } + + paramList.done(JavaElementType.PARAMETER_LIST); + return paramList; + } + + @Nullable + private static PsiBuilder.Marker parseParameter(final PsiBuilder builder, final boolean ellipsis) { + final PsiBuilder.Marker param = builder.mark(); + + final Pair modListInfo = parseModifierList(builder); + final PsiBuilder.Marker type = ellipsis ? ReferenceParser.parseTypeWithEllipsis(builder, true, true) : + ReferenceParser.parseType(builder, true, true); + + if (type == null && modListInfo.second) { + param.rollbackTo(); + return null; + } + + if (type == null) { + error(builder, JavaErrorMessages.message("expected.type")); + emptyElement(builder, JavaElementType.TYPE); + } + + if (expect(builder, JavaTokenType.IDENTIFIER)) { + eatBrackets(builder); + } + else { + error(builder, JavaErrorMessages.message("expected.identifier")); + } + + param.done(JavaElementType.PARAMETER); + return param; } @Nullable @@ -389,12 +529,8 @@ public class DeclarationParser { boolean eatSemicolon = true; boolean expectSemicolon = true; while (true) { - while (expect(builder, JavaTokenType.LBRACKET)) { - if (!expect(builder, JavaTokenType.RBRACKET)) { - error(builder, JavaErrorMessages.message("expected.rbracket")); - expectSemicolon = false; - break; - } + if (!eatBrackets(builder)) { + expectSemicolon = false; } if (expect(builder, JavaTokenType.EQ)) { @@ -438,6 +574,16 @@ public class DeclarationParser { return declaration; } + private static boolean eatBrackets(final PsiBuilder builder) { + while (expect(builder, JavaTokenType.LBRACKET)) { + if (!expect(builder, JavaTokenType.RBRACKET)) { + error(builder, JavaErrorMessages.message("expected.rbracket")); + return false; + } + } + return true; + } + @Nullable public static PsiBuilder.Marker parseAnnotations(final PsiBuilder builder) { PsiBuilder.Marker firstAnno = null; @@ -452,6 +598,7 @@ public class DeclarationParser { @NotNull private static PsiBuilder.Marker parseAnnotation(final PsiBuilder builder) { + assert builder.getTokenType() == JavaTokenType.AT : builder.getTokenType(); final PsiBuilder.Marker anno = builder.mark(); builder.advanceLexer(); @@ -570,6 +717,7 @@ public class DeclarationParser { @NotNull private static PsiBuilder.Marker parseAnnotationArrayInitializer(final PsiBuilder builder) { + assert builder.getTokenType() == JavaTokenType.LBRACE : builder.getTokenType(); final PsiBuilder.Marker annoArray = builder.mark(); builder.advanceLexer(); diff --git a/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java b/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java index 89ed2e5c7fa5..6a3597e5f897 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java @@ -44,7 +44,7 @@ public class JavaParserUtil { @NotNull private static LanguageLevel getLanguageLevel(final PsiBuilder builder) { final LanguageLevel level = builder.getUserData(LANG_LEVEL_KEY); - assert level != null; + assert level != null : builder; return level; } @@ -75,7 +75,7 @@ public class JavaParserUtil { } public static void emptyElement(final PsiBuilder.Marker before, final IElementType type) { - before.precede().done(type); + before.precede().doneBefore(type, before); } public static PsiBuilder braceMatchingBuilder(final PsiBuilder builder) { diff --git a/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java b/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java index 62fa6078d640..da8be88afb9e 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java @@ -278,28 +278,26 @@ public class ReferenceParser { return null; } - if (expect(builder, JavaTokenType.EXTENDS_KEYWORD)) { - parseReferenceList(builder, JavaElementType.EXTENDS_BOUND_LIST, JavaTokenType.AND); - } - else { - emptyElement(builder, JavaElementType.EXTENDS_BOUND_LIST); - } + parseReferenceList(builder, JavaTokenType.EXTENDS_KEYWORD, JavaElementType.EXTENDS_BOUND_LIST, JavaTokenType.AND); param.done(JavaElementType.TYPE_PARAMETER); return param; } @NotNull - private static PsiBuilder.Marker parseReferenceList(final PsiBuilder builder, final IElementType type, final IElementType delimiter) { + public static PsiBuilder.Marker parseReferenceList(final PsiBuilder builder, final IElementType start, + final IElementType type, final IElementType delimiter) { final PsiBuilder.Marker element = builder.mark(); - while (true) { - final PsiBuilder.Marker classReference = parseJavaCodeReference(builder, true, true, true); - if (classReference == null) { - error(builder, JavaErrorMessages.message("expected.identifier")); - } - if (!expect(builder, delimiter)) { - break; + if (expect(builder, start)) { + while (true) { + final PsiBuilder.Marker classReference = parseJavaCodeReference(builder, true, true, true); + if (classReference == null) { + error(builder, JavaErrorMessages.message("expected.identifier")); + } + if (!expect(builder, delimiter)) { + break; + } } } diff --git a/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java b/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java index 06d8532bd20d..d08d0ff88324 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java @@ -16,6 +16,8 @@ package com.intellij.lang.java.parser; import com.intellij.lang.PsiBuilder; +import com.intellij.psi.JavaTokenType; +import com.intellij.psi.impl.source.tree.JavaElementType; import org.jetbrains.annotations.Nullable; @@ -24,6 +26,18 @@ public class StatementParser { @Nullable public static PsiBuilder.Marker parseCodeBlock(final PsiBuilder builder) { + if (builder.getTokenType() != JavaTokenType.LBRACE) return null; + + final PsiBuilder.Marker codeBlock = builder.mark(); + builder.advanceLexer(); + + // temp + if (builder.getTokenType() == JavaTokenType.RBRACE) { + builder.advanceLexer(); + codeBlock.done(JavaElementType.CODE_BLOCK); + return codeBlock; + } + // todo: implement throw new UnsupportedOperationException(builder.toString()); } diff --git a/java/java-tests/testData/psi/parser-partial/declarations/CompletionHack0.txt b/java/java-tests/testData/psi/parser-partial/declarations/CompletionHack0.txt new file mode 100644 index 000000000000..7b9cfccf79de --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/CompletionHack0.txt @@ -0,0 +1,33 @@ +PsiJavaFile:CompletionHack0.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiField:s + PsiModifierList: + + PsiErrorElement:Unexpected token + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:X + PsiIdentifier:X('X') + PsiElement(EXTENDS_BOUND_LIST) + + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected identifier + PsiIdentifier:IntelliJIdeaRulezz('IntelliJIdeaRulezz') + PsiJavaToken:GT('>') + PsiWhiteSpace('\n ') + PsiTypeElement:String + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:s('s') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:"" + PsiJavaToken:STRING_LITERAL('""') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/CompletionHack1.txt b/java/java-tests/testData/psi/parser-partial/declarations/CompletionHack1.txt new file mode 100644 index 000000000000..127827743962 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/CompletionHack1.txt @@ -0,0 +1,31 @@ +PsiJavaFile:CompletionHack1.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiField:s + PsiModifierList: + + PsiErrorElement:Unexpected token + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:X + PsiIdentifier:X('X') + PsiElement(EXTENDS_BOUND_LIST) + + PsiErrorElement:'>' expected. + + PsiWhiteSpace('\n ') + PsiTypeElement:String + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:s('s') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:"" + PsiJavaToken:STRING_LITERAL('""') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/Errors.txt b/java/java-tests/testData/psi/parser-partial/declarations/Errors.txt new file mode 100644 index 000000000000..609379fee3fa --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/Errors.txt @@ -0,0 +1,45 @@ +PsiJavaFile:Errors.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiModifierList:public static + PsiKeyword:public('public') + PsiWhiteSpace(' ') + PsiKeyword:static('static') + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected token + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:error + PsiIdentifier:error('error') + PsiElement(EXTENDS_BOUND_LIST) + + PsiErrorElement:'>' expected. + + PsiWhiteSpace(' ') + PsiTypeElement:descr + PsiJavaCodeReferenceElement:descr + PsiIdentifier:descr('descr') + PsiReferenceParameterList + + PsiErrorElement:Identifier expected + + PsiErrorElement:Unexpected token + PsiJavaToken:EQ('=') + PsiJavaToken:STRING_LITERAL('"2"') + PsiJavaToken:GT('>') + PsiField:f1 + PsiModifierList:protected + PsiKeyword:protected('protected') + PsiWhiteSpace(' ') + PsiTypeElement:int + PsiKeyword:int('int') + PsiWhiteSpace(' ') + PsiIdentifier:f1('f1') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:0 + PsiJavaToken:INTEGER_LITERAL('0') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/GenericMethod.txt b/java/java-tests/testData/psi/parser-partial/declarations/GenericMethod.txt new file mode 100644 index 000000000000..7504f3612d97 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/GenericMethod.txt @@ -0,0 +1,91 @@ +PsiJavaFile:GenericMethod.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:test + PsiModifierList:public static + PsiKeyword:public('public') + PsiWhiteSpace(' ') + PsiKeyword:static('static') + PsiWhiteSpace(' ') + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:E + PsiIdentifier:E('E') + PsiElement(EXTENDS_BOUND_LIST) + + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiIdentifier:test('test') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace('\n ') + PsiMethod:test1 + PsiModifierList: + + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:E + PsiIdentifier:E('E') + PsiElement(EXTENDS_BOUND_LIST) + + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:test1('test1') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace('\n ') + PsiMethod:test2 + PsiModifierList: + + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:E1 + PsiIdentifier:E1('E1') + PsiWhiteSpace(' ') + PsiElement(EXTENDS_BOUND_LIST) + PsiKeyword:extends('extends') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:Integer + PsiIdentifier:Integer('Integer') + PsiReferenceParameterList + + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiTypeParameter:E2 + PsiIdentifier:E2('E2') + PsiWhiteSpace(' ') + PsiElement(EXTENDS_BOUND_LIST) + PsiKeyword:extends('extends') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:Runnable + PsiIdentifier:Runnable('Runnable') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiTypeElement:String + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:test2('test2') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/GenericMethodErrors.txt b/java/java-tests/testData/psi/parser-partial/declarations/GenericMethodErrors.txt new file mode 100644 index 000000000000..5be504737907 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/GenericMethodErrors.txt @@ -0,0 +1,43 @@ +PsiJavaFile:GenericMethodErrors.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiModifierList: + + PsiErrorElement:Unexpected token + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:Error + PsiIdentifier:Error('Error') + PsiElement(EXTENDS_BOUND_LIST) + + PsiErrorElement:'>' expected. + + PsiWhiteSpace(' ') + PsiTypeElement:sss + PsiJavaCodeReferenceElement:sss + PsiIdentifier:sss('sss') + PsiReferenceParameterList + + PsiErrorElement:Identifier expected + + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected token + PsiJavaToken:DIV('/') + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:test + PsiIdentifier:test('test') + PsiWhiteSpace(' ') + PsiReferenceParameterList + PsiJavaToken:LT('<') + PsiTypeElement:error + PsiJavaCodeReferenceElement:error + PsiIdentifier:error('error') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/MethodNormal0.txt b/java/java-tests/testData/psi/parser-partial/declarations/MethodNormal0.txt new file mode 100644 index 000000000000..f2383f5aaae4 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/MethodNormal0.txt @@ -0,0 +1,24 @@ +PsiJavaFile:MethodNormal0.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:f + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:f('f') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiWhiteSpace(' ') + PsiCodeBlock + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/MethodNormal1.txt b/java/java-tests/testData/psi/parser-partial/declarations/MethodNormal1.txt new file mode 100644 index 000000000000..b146b9b578d8 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/MethodNormal1.txt @@ -0,0 +1,20 @@ +PsiJavaFile:MethodNormal1.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:f + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:f('f') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/Unclosed0.txt b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed0.txt new file mode 100644 index 000000000000..9353f05c8052 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed0.txt @@ -0,0 +1,21 @@ +PsiJavaFile:Unclosed0.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:f + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:f('f') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiErrorElement:'{' or ';' expected + + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/Unclosed1.txt b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed1.txt new file mode 100644 index 000000000000..c7b4159c5357 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed1.txt @@ -0,0 +1,22 @@ +PsiJavaFile:Unclosed1.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:f + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:f('f') + PsiParameterList:( + PsiJavaToken:LPARENTH('(') + PsiErrorElement:')' expected + + PsiReferenceList + + PsiErrorElement:'{' or ';' expected + + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/Unclosed2.txt b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed2.txt new file mode 100644 index 000000000000..b2a0dfe174c4 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed2.txt @@ -0,0 +1,37 @@ +PsiJavaFile:Unclosed2.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:f + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:f('f') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiErrorElement:'{' or ';' expected + + PsiWhiteSpace('\n ') + PsiMethod:g + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:g('g') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/Unclosed3.txt b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed3.txt new file mode 100644 index 000000000000..82caa1cf199e --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed3.txt @@ -0,0 +1,29 @@ +PsiJavaFile:Unclosed3.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:f + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:f('f') + PsiParameterList:(int a + PsiJavaToken:LPARENTH('(') + PsiParameter:a + PsiModifierList: + + PsiTypeElement:int + PsiKeyword:int('int') + PsiWhiteSpace(' ') + PsiIdentifier:a('a') + PsiErrorElement:')' expected + + PsiReferenceList + + PsiErrorElement:'{' or ';' expected + + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/Unclosed4.txt b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed4.txt new file mode 100644 index 000000000000..d7ffeea84e44 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed4.txt @@ -0,0 +1,33 @@ +PsiJavaFile:Unclosed4.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:f + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:f('f') + PsiParameterList:(int a,, + PsiJavaToken:LPARENTH('(') + PsiParameter:a + PsiModifierList: + + PsiTypeElement:int + PsiKeyword:int('int') + PsiWhiteSpace(' ') + PsiIdentifier:a('a') + PsiJavaToken:COMMA(',') + PsiErrorElement:Parameter expected + + PsiJavaToken:COMMA(',') + PsiErrorElement:Identifier or type expected + + PsiReferenceList + + PsiErrorElement:'{' or ';' expected + + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/Unclosed5.txt b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed5.txt new file mode 100644 index 000000000000..a0166d829e10 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/Unclosed5.txt @@ -0,0 +1,30 @@ +PsiJavaFile:Unclosed5.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:f + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:f('f') + PsiParameterList:(int a,) + PsiJavaToken:LPARENTH('(') + PsiParameter:a + PsiModifierList: + + PsiTypeElement:int + PsiKeyword:int('int') + PsiWhiteSpace(' ') + PsiIdentifier:a('a') + PsiJavaToken:COMMA(',') + PsiErrorElement:Identifier or type expected + + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') diff --git a/java/java-tests/testData/psi/parser-partial/declarations/WildcardParsing.txt b/java/java-tests/testData/psi/parser-partial/declarations/WildcardParsing.txt new file mode 100644 index 000000000000..b433896f20bb --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/WildcardParsing.txt @@ -0,0 +1,55 @@ +PsiJavaFile:WildcardParsing.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiMethod:x + PsiModifierList: + + PsiTypeParameterList + + PsiTypeElement:List + PsiJavaCodeReferenceElement:List + PsiIdentifier:List('List') + PsiReferenceParameterList + PsiJavaToken:LT('<') + PsiTypeElement:? extends B + PsiJavaToken:QUEST('?') + PsiWhiteSpace(' ') + PsiKeyword:extends('extends') + PsiWhiteSpace(' ') + PsiTypeElement:B + PsiJavaCodeReferenceElement:B + PsiIdentifier:B('B') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiIdentifier:x('x') + PsiParameterList:(Collection x) + PsiJavaToken:LPARENTH('(') + PsiParameter:x + PsiModifierList: + + PsiTypeElement:Collection + PsiJavaCodeReferenceElement:Collection + PsiIdentifier:Collection('Collection') + PsiReferenceParameterList + PsiJavaToken:LT('<') + PsiTypeElement:? super B + PsiJavaToken:QUEST('?') + PsiWhiteSpace(' ') + PsiKeyword:super('super') + PsiWhiteSpace(' ') + PsiTypeElement:B + PsiJavaCodeReferenceElement:B + PsiIdentifier:B('B') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiIdentifier:x('x') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/references/TypeParams5.txt b/java/java-tests/testData/psi/parser-partial/references/TypeParams5.txt index 51d776e6a39e..a7329da61f08 100644 --- a/java/java-tests/testData/psi/parser-partial/references/TypeParams5.txt +++ b/java/java-tests/testData/psi/parser-partial/references/TypeParams5.txt @@ -4,9 +4,9 @@ PsiJavaFile:TypeParams5.java PsiTypeParameter:T PsiIdentifier:T('T') PsiWhiteSpace(' ') - PsiKeyword:extends('extends') - PsiWhiteSpace(' ') PsiElement(EXTENDS_BOUND_LIST) + PsiKeyword:extends('extends') + PsiWhiteSpace(' ') PsiJavaCodeReferenceElement:X PsiIdentifier:X('X') PsiReferenceParameterList diff --git a/java/java-tests/testData/psi/parser-partial/references/TypeParams7.txt b/java/java-tests/testData/psi/parser-partial/references/TypeParams7.txt index f3cf0196d19a..aaea7b8c3d5d 100644 --- a/java/java-tests/testData/psi/parser-partial/references/TypeParams7.txt +++ b/java/java-tests/testData/psi/parser-partial/references/TypeParams7.txt @@ -4,9 +4,9 @@ PsiJavaFile:TypeParams7.java PsiTypeParameter:T PsiIdentifier:T('T') PsiWhiteSpace(' ') - PsiKeyword:extends('extends') - PsiWhiteSpace(' ') PsiElement(EXTENDS_BOUND_LIST) + PsiKeyword:extends('extends') + PsiWhiteSpace(' ') PsiJavaCodeReferenceElement:X PsiIdentifier:X('X') PsiReferenceParameterList diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java index 7d516c955c89..577e74a93c53 100644 --- a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java @@ -44,6 +44,23 @@ public class DeclarationParserTest extends JavaParsingTestCase { public void testMissingInitializerExpression() { doParserTest("{ int field=; }", false, false); } //public void testMultiLineUnclosed() { doParserTest("{ int \n Object o; }", false, false); } // todo: implement + //public void testMethodNormal0() { doParserTest("{ void f() { } }", false, false); } // todo: parse code block correctly + public void testMethodNormal1() { doParserTest("{ void f(); }", false, false); } + public void testUnclosed0() { doParserTest("{ void f() }", false, false); } + public void testUnclosed1() { doParserTest("{ void f( }", false, false); } + public void testUnclosed2() { doParserTest("{ void f()\n void g(); }", false, false); } + public void testUnclosed3() { doParserTest("{ void f(int a }", false, false); } + public void testUnclosed4() { doParserTest("{ void f(int a,, }", false, false); } + public void testUnclosed5() { doParserTest("{ void f(int a,); }", false, false); } + public void testGenericMethod() { doParserTest("{ public static test();\n" + + " void test1();\n" + + " String test2(); }", false, false); } + public void testGenericMethodErrors() { doParserTest("{ test (); }", false, false); } + public void testErrors() { doParserTest("{ public static protected int f1 = 0; }", false, false); } + public void testCompletionHack0() { doParserTest("{ \n String s = \"\"; }", false, false); } + public void testCompletionHack1() { doParserTest("{ x(Collection x); }", false, false); } + private void doParserTest(final String text, final boolean isAnnotation, final boolean isEnum) { doParserTest(text, new Parser() { public void parse(final PsiBuilder builder) { From 9864bf56806814ff8d799ad30aa14558ea7e2ac6 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 27 Jul 2010 18:17:53 +0400 Subject: [PATCH 10/17] Cleanup --- .../intellij/psi/impl/source/parsing/DeclarationParsing.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/impl/source/parsing/DeclarationParsing.java b/java/java-impl/src/com/intellij/psi/impl/source/parsing/DeclarationParsing.java index 8061c0d256e3..4f8b677b1fc2 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/parsing/DeclarationParsing.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/parsing/DeclarationParsing.java @@ -705,8 +705,8 @@ public class DeclarationParsing extends Parsing { aClass.rawAddChildren(invalidElementsGroup); while (true) { IElementType tokenType = lexer.getTokenType(); - if (tokenType == JavaTokenType.IDENTIFIER || tokenType == JavaTokenType.COMMA || tokenType == JavaTokenType.EXTENDS_KEYWORD || tokenType == - JavaTokenType.IMPLEMENTS_KEYWORD) { + if (tokenType == JavaTokenType.IDENTIFIER || tokenType == JavaTokenType.COMMA || tokenType == JavaTokenType.EXTENDS_KEYWORD || + tokenType == JavaTokenType.IMPLEMENTS_KEYWORD) { invalidElementsGroup.rawAddChildren(ParseUtil.createTokenElement(lexer, myContext.getCharTable())); } else { From 42c9e53017f8b4dfd2e283aa5afa927c15c42e42 Mon Sep 17 00:00:00 2001 From: nik Date: Wed, 28 Jul 2010 12:14:45 +0400 Subject: [PATCH 11/17] added topic about starting/stopping run configurations --- .../intellij/execution/ExecutionAdapter.java | 45 ++++++ .../intellij/execution/ExecutionListener.java | 38 +++++ .../intellij/execution/ExecutionManager.java | 9 +- .../intellij/execution/RunProfileStarter.java | 33 +++++ .../runners/GenericProgramRunner.java | 44 ++---- .../execution/impl/ExecutionManagerImpl.java | 140 +++++++++++++----- 6 files changed, 237 insertions(+), 72 deletions(-) create mode 100644 platform/lang-api/src/com/intellij/execution/ExecutionAdapter.java create mode 100644 platform/lang-api/src/com/intellij/execution/ExecutionListener.java create mode 100644 platform/lang-api/src/com/intellij/execution/RunProfileStarter.java diff --git a/platform/lang-api/src/com/intellij/execution/ExecutionAdapter.java b/platform/lang-api/src/com/intellij/execution/ExecutionAdapter.java new file mode 100644 index 000000000000..85325b68aeb5 --- /dev/null +++ b/platform/lang-api/src/com/intellij/execution/ExecutionAdapter.java @@ -0,0 +1,45 @@ +/* + * 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.execution; + +import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.process.ProcessHandler; +import org.jetbrains.annotations.NotNull; + +/** + * @author nik + */ +public class ExecutionAdapter implements ExecutionListener { + @Override + public void processStarting(@NotNull RunProfile runProfile) { + } + + @Override + public void processNotStarted(@NotNull RunProfile runProfile) { + } + + @Override + public void processStarted(@NotNull RunProfile runProfile, @NotNull ProcessHandler handler) { + } + + @Override + public void processTerminating(@NotNull RunProfile runProfile, @NotNull ProcessHandler handler) { + } + + @Override + public void processTerminated(@NotNull RunProfile runProfile, @NotNull ProcessHandler handler) { + } +} diff --git a/platform/lang-api/src/com/intellij/execution/ExecutionListener.java b/platform/lang-api/src/com/intellij/execution/ExecutionListener.java new file mode 100644 index 000000000000..2e45ef7ac8d7 --- /dev/null +++ b/platform/lang-api/src/com/intellij/execution/ExecutionListener.java @@ -0,0 +1,38 @@ +/* + * 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.execution; + +import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.process.ProcessHandler; +import org.jetbrains.annotations.NotNull; + +import java.util.EventListener; + +/** + * @author nik + */ +public interface ExecutionListener extends EventListener { + + void processStarting(@NotNull RunProfile runProfile); + + void processNotStarted(@NotNull RunProfile runProfile); + + void processStarted(@NotNull RunProfile runProfile, @NotNull ProcessHandler handler); + + void processTerminating(@NotNull RunProfile runProfile, @NotNull ProcessHandler handler); + + void processTerminated(@NotNull RunProfile runProfile, @NotNull ProcessHandler handler); +} diff --git a/platform/lang-api/src/com/intellij/execution/ExecutionManager.java b/platform/lang-api/src/com/intellij/execution/ExecutionManager.java index 58e02af4f707..712d12c9f4a9 100644 --- a/platform/lang-api/src/com/intellij/execution/ExecutionManager.java +++ b/platform/lang-api/src/com/intellij/execution/ExecutionManager.java @@ -18,10 +18,16 @@ package com.intellij.execution; import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.configurations.RunProfileState; import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.ui.RunContentManager; import com.intellij.openapi.project.Project; +import com.intellij.util.messages.Topic; +import org.jetbrains.annotations.NotNull; public abstract class ExecutionManager { + public static final Topic EXECUTION_TOPIC = new Topic("configuration executed", ExecutionListener.class, + Topic.BroadcastDirection.TO_PARENT); + public static ExecutionManager getInstance(final Project project) { return project.getComponent(ExecutionManager.class); } @@ -32,5 +38,6 @@ public abstract class ExecutionManager { public abstract ProcessHandler[] getRunningProcesses(); - + public abstract void startRunProfile(@NotNull RunProfileStarter starter, @NotNull RunProfileState state, + @NotNull Project project, @NotNull Executor executor, @NotNull ExecutionEnvironment env); } diff --git a/platform/lang-api/src/com/intellij/execution/RunProfileStarter.java b/platform/lang-api/src/com/intellij/execution/RunProfileStarter.java new file mode 100644 index 000000000000..846b67b2f8a5 --- /dev/null +++ b/platform/lang-api/src/com/intellij/execution/RunProfileStarter.java @@ -0,0 +1,33 @@ +/* + * 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.execution; + +import com.intellij.execution.configurations.RunProfileState; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.ui.RunContentDescriptor; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author nik + */ +public abstract class RunProfileStarter { + @Nullable + public abstract RunContentDescriptor execute(@NotNull Project project, @NotNull Executor executor, @NotNull RunProfileState state, + @Nullable RunContentDescriptor contentToReuse, @NotNull ExecutionEnvironment env) throws ExecutionException; + +} diff --git a/platform/lang-api/src/com/intellij/execution/runners/GenericProgramRunner.java b/platform/lang-api/src/com/intellij/execution/runners/GenericProgramRunner.java index cfde4926a0b9..8d8550e664cc 100644 --- a/platform/lang-api/src/com/intellij/execution/runners/GenericProgramRunner.java +++ b/platform/lang-api/src/com/intellij/execution/runners/GenericProgramRunner.java @@ -18,12 +18,9 @@ package com.intellij.execution.runners; import com.intellij.execution.*; import com.intellij.execution.configurations.*; -import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.ui.RunContentDescriptor; -import com.intellij.history.LocalHistory; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.DataKey; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.JDOMExternalizable; @@ -67,51 +64,34 @@ public abstract class GenericProgramRunner public void execute(@NotNull final Executor executor, @NotNull final ExecutionEnvironment env, @Nullable final Callback callback) throws ExecutionException { - final RunProfile profile = env.getRunProfile(); final Project project = env.getProject(); if (project == null) { return; } - final RunContentDescriptor reuseContent = - ExecutionManager.getInstance(project).getContentManager().getReuseContent(executor, env.getContentToReuse()); final RunProfileState state = env.getState(executor); if (state == null) { return; } - Runnable startRunnable = new Runnable() { - public void run() { - try { - if (project.isDisposed()) return; - - final RunContentDescriptor descriptor = - doExecute(project, executor, state, reuseContent, env); - - if (callback != null) callback.processStarted(descriptor); - - if (descriptor != null) { - ExecutionManager.getInstance(project).getContentManager().showRunContent(executor, descriptor); - final ProcessHandler processHandler = descriptor.getProcessHandler(); - if (processHandler != null) processHandler.startNotify(); - } - } - catch (ExecutionException e) { - ExecutionUtil.handleExecutionError(project, executor.getToolWindowId(), profile, e); - } + ExecutionManager.getInstance(project).startRunProfile(new RunProfileStarter() { + @Override + public RunContentDescriptor execute(@NotNull Project project, + @NotNull Executor executor, + @NotNull RunProfileState state, + @Nullable RunContentDescriptor contentToReuse, + @NotNull ExecutionEnvironment env) throws ExecutionException { + final RunContentDescriptor descriptor = doExecute(project, executor, state, contentToReuse, env); + if (callback != null) callback.processStarted(descriptor); + return descriptor; } - }; - if (ApplicationManager.getApplication().isUnitTestMode()) { - startRunnable.run(); - } - else { - ExecutionManager.getInstance(project).compileAndRun(startRunnable, profile, state); - } + }, state, project, executor, env); } @Nullable protected abstract RunContentDescriptor doExecute(final Project project, final Executor executor, final RunProfileState state, final RunContentDescriptor contentToReuse, final ExecutionEnvironment env) throws ExecutionException; + } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java index 9a37209fc431..9f18f4a66c7a 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java @@ -16,14 +16,16 @@ package com.intellij.execution.impl; -import com.intellij.execution.BeforeRunTask; -import com.intellij.execution.BeforeRunTaskProvider; -import com.intellij.execution.ExecutionManager; +import com.intellij.execution.*; import com.intellij.execution.configurations.ConfigurationPerRunnerSettings; import com.intellij.execution.configurations.RunConfiguration; import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.configurations.RunProfileState; +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.ExecutionUtil; import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.execution.ui.RunContentManager; import com.intellij.execution.ui.RunContentManagerImpl; @@ -64,7 +66,8 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom public void projectClosed() { } - public void initComponent() { } + public void initComponent() { + } public void disposeComponent() { } @@ -94,53 +97,112 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom public void compileAndRun(final Runnable startRunnable, final RunProfile configuration, final RunProfileState state) { - final Runnable antAwareRunnable = new Runnable() { - public void run() { - if (configuration instanceof RunConfiguration) { - final RunConfiguration runConfiguration = (RunConfiguration)configuration; - final RunManagerImpl runManager = RunManagerImpl.getInstanceImpl(myProject); + if (configuration instanceof RunConfiguration) { + final RunConfiguration runConfiguration = (RunConfiguration)configuration; + final RunManagerImpl runManager = RunManagerImpl.getInstanceImpl(myProject); - final Map, BeforeRunTask> activeProviders = new LinkedHashMap, BeforeRunTask>(); - for (final BeforeRunTaskProvider provider : Extensions.getExtensions(BeforeRunTaskProvider.EXTENSION_POINT_NAME, myProject)) { - final BeforeRunTask task = runManager.getBeforeRunTask(runConfiguration, provider.getId()); - if (task != null && task.isEnabled()) { - activeProviders.put(provider, task); + final Map, BeforeRunTask> activeProviders = new LinkedHashMap, BeforeRunTask>(); + for (final BeforeRunTaskProvider provider : Extensions.getExtensions(BeforeRunTaskProvider.EXTENSION_POINT_NAME, myProject)) { + final BeforeRunTask task = runManager.getBeforeRunTask(runConfiguration, provider.getId()); + if (task != null && task.isEnabled()) { + activeProviders.put(provider, task); + } + } + + if (!activeProviders.isEmpty()) { + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + public void run() { + ConfigurationPerRunnerSettings configurationSettings = state.getConfigurationSettings(); + DataContext projectContext = SimpleDataContext.getProjectContext(myProject); + + final DataContext dataContext = configurationSettings != null ? SimpleDataContext + .getSimpleContext(BeforeRunTaskProvider.RUNNER_ID, configurationSettings.getRunnerId(), projectContext) : projectContext; + for (BeforeRunTaskProvider provider : activeProviders.keySet()) { + if(!provider.executeTask(dataContext, runConfiguration, activeProviders.get(provider))) { + return; + } + } + DumbService.getInstance(myProject).smartInvokeLater(startRunnable); + } + }); + } + else { + startRunnable.run(); + } + } + else { + startRunnable.run(); + } + } + + @Override + public void startRunProfile(@NotNull final RunProfileStarter starter, @NotNull final RunProfileState state, + @NotNull final Project project, @NotNull final Executor executor, @NotNull final ExecutionEnvironment env) { + final RunContentDescriptor reuseContent = ExecutionManager.getInstance(project).getContentManager().getReuseContent(executor, env.getContentToReuse()); + final RunProfile profile = env.getRunProfile(); + + Runnable startRunnable = new Runnable() { + public void run() { + boolean started = false; + try { + if (project.isDisposed()) return; + + project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processStarting(profile); + + final RunContentDescriptor descriptor = starter.execute(project, executor, state, reuseContent, env); + + if (descriptor != null) { + ExecutionManager.getInstance(project).getContentManager().showRunContent(executor, descriptor); + final ProcessHandler processHandler = descriptor.getProcessHandler(); + if (processHandler != null) { + processHandler.startNotify(); + project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processStarted(profile, processHandler); + started = true; + processHandler.addProcessListener(new ProcessExecutionListener(project, profile, processHandler)); } } - - if (!activeProviders.isEmpty()) { - ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - public void run() { - ConfigurationPerRunnerSettings configurationSettings = state.getConfigurationSettings(); - DataContext projectContext = SimpleDataContext.getProjectContext(myProject); - - final DataContext dataContext = configurationSettings != null ? SimpleDataContext - .getSimpleContext(BeforeRunTaskProvider.RUNNER_ID, configurationSettings.getRunnerId(), projectContext) : projectContext; - for (BeforeRunTaskProvider provider : activeProviders.keySet()) { - if(!provider.executeTask(dataContext, runConfiguration, activeProviders.get(provider))) { - return; - } - } - DumbService.getInstance(myProject).smartInvokeLater(startRunnable); - } - }); - } - else { - startRunnable.run(); - } } - else { - startRunnable.run(); + catch (ExecutionException e) { + ExecutionUtil.handleExecutionError(project, executor.getToolWindowId(), profile, e); + } + if (!started) { + project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processNotStarted(profile); } } }; - antAwareRunnable.run(); - //ApplicationManager.getApplication().invokeLater(antAwareRunnable); + if (ApplicationManager.getApplication().isUnitTestMode()) { + startRunnable.run(); + } + else { + compileAndRun(startRunnable, profile, state); + } } @NotNull public String getComponentName() { return "ExecutionManager"; } + + private static class ProcessExecutionListener extends ProcessAdapter { + private final Project myProject; + private final RunProfile myProfile; + private final ProcessHandler myProcessHandler; + + public ProcessExecutionListener(Project project, RunProfile profile, ProcessHandler processHandler) { + myProject = project; + myProfile = profile; + myProcessHandler = processHandler; + } + + @Override + public void processTerminated(ProcessEvent event) { + myProject.getMessageBus().syncPublisher(EXECUTION_TOPIC).processTerminated(myProfile, myProcessHandler); + } + + @Override + public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) { + myProject.getMessageBus().syncPublisher(EXECUTION_TOPIC).processTerminating(myProfile, myProcessHandler); + } + } } From 2ca4baf5164b8a5e30c57fd240236528653a163e Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 27 Jul 2010 21:35:02 +0400 Subject: [PATCH 12/17] eclipse: remember dependency scope for any library --- .../idea/eclipse/conversion/IdeaSpecificSettings.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/IdeaSpecificSettings.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/IdeaSpecificSettings.java index 07ccd9246166..a624a66d326e 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/IdeaSpecificSettings.java +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/IdeaSpecificSettings.java @@ -115,6 +115,11 @@ public class IdeaSpecificSettings { replaceModuleRelatedRoots(model.getProject(), modifiableModel, libElement, OrderRootType.CLASSES, RELATIVE_MODULE_CLS); replaceModuleRelatedRoots(model.getProject(), modifiableModel, libElement, JavadocOrderRootType.getInstance(), RELATIVE_MODULE_JAVADOC); modifiableModel.commit(); + } else { + final Library library = EclipseClasspathReader.findLibraryByName(model.getProject(), libName); + if (library != null) { + appendLibraryScope(model, libElement, library); + } } } overrideModulesScopes(root, model); From e7420456ab24a467192ebf444be4f8ca093f7652 Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 27 Jul 2010 22:21:52 +0400 Subject: [PATCH 13/17] introduce constant: detect write usages (IDEA-53654) --- .../introduceField/IntroduceConstantHandler.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantHandler.java index c2fee31d935a..8c9a56f658f1 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantHandler.java @@ -32,6 +32,7 @@ import com.intellij.refactoring.HelpID; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.ui.TypeSelectorManagerImpl; import com.intellij.refactoring.util.CommonRefactoringUtil; +import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.refactoring.util.classMembers.ClassMemberReferencesVisitor; import com.intellij.refactoring.util.occurences.ExpressionOccurenceManager; import com.intellij.refactoring.util.occurences.OccurenceManager; @@ -85,6 +86,15 @@ public class IntroduceConstantHandler extends BaseExpressionToFieldHandler { PsiExpression[] occurences, PsiElement anchorElement, PsiElement anchorElementIfAll) { + for (PsiExpression occurrence : occurences) { + if (RefactoringUtil.isAssignmentLHS(occurrence)) { + String message = + RefactoringBundle.getCannotRefactorMessage("Selected expression is used for write"); + CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, getHelpID()); + highlightError(project, editor, occurrence); + return null; + } + } PsiLocalVariable localVariable = null; if (expr instanceof PsiReferenceExpression) { PsiElement ref = ((PsiReferenceExpression)expr).resolve(); From ea83ef22a7f0d5d10083ca1ad1f88f4836d78cbd Mon Sep 17 00:00:00 2001 From: anna Date: Wed, 28 Jul 2010 12:14:45 +0400 Subject: [PATCH 14/17] action button presentation on disabled toolbar should behave appropriate (IDEA-56798) --- .../com/intellij/openapi/actionSystem/impl/ActionButton.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java index 1c9cd34c9350..13e615887cd6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionButton.java @@ -92,7 +92,7 @@ public class ActionButton extends JComponent implements ActionButtonComponent { } protected boolean isButtonEnabled() { - return myPresentation.isEnabled(); + return isEnabled() && myPresentation.isEnabled(); } private void onMousePresenceChanged(boolean setInfo) { From 72fedc5d1f88f6783f4b9da50e2ae89fc1956763 Mon Sep 17 00:00:00 2001 From: nik Date: Wed, 28 Jul 2010 12:53:23 +0400 Subject: [PATCH 15/17] new api for file processing compilers --- .../intellij/compiler/impl/CompileDriver.java | 13 +- .../compiler/impl/CompilerCacheManager.java | 22 ++ .../compiler/impl/NewCompilerRunner.java | 246 ++++++++++++++++++ .../compiler/impl/newApi/BuildTarget.java | 39 +++ .../compiler/impl/newApi/CompileItem.java | 31 +++ .../impl/newApi/CompilerInstance.java | 60 +++++ .../compiler/impl/newApi/NewCompiler.java | 62 +++++ .../impl/newApi/NewCompilerCache.java | 132 ++++++++++ .../newApi/NewCompilerPersistentData.java | 119 +++++++++ .../newApi/SingleTargetCompilerInstance.java | 48 ++++ .../impl/newApi/VirtualFileCompileItem.java | 55 ++++ .../newApi/VirtualFilePersistentState.java | 31 +++ .../newApi/VirtualFileStateExternalizer.java | 44 ++++ 13 files changed, 898 insertions(+), 4 deletions(-) create mode 100644 java/compiler/impl/src/com/intellij/compiler/impl/NewCompilerRunner.java create mode 100644 java/compiler/impl/src/com/intellij/compiler/impl/newApi/BuildTarget.java create mode 100644 java/compiler/impl/src/com/intellij/compiler/impl/newApi/CompileItem.java create mode 100644 java/compiler/impl/src/com/intellij/compiler/impl/newApi/CompilerInstance.java create mode 100644 java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompiler.java create mode 100644 java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerCache.java create mode 100644 java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerPersistentData.java create mode 100644 java/compiler/impl/src/com/intellij/compiler/impl/newApi/SingleTargetCompilerInstance.java create mode 100644 java/compiler/impl/src/com/intellij/compiler/impl/newApi/VirtualFileCompileItem.java create mode 100644 java/compiler/impl/src/com/intellij/compiler/impl/newApi/VirtualFilePersistentState.java create mode 100644 java/compiler/impl/src/com/intellij/compiler/impl/newApi/VirtualFileStateExternalizer.java 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 230c9e999ec9..5a29390a9e1d 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java @@ -24,6 +24,7 @@ package com.intellij.compiler.impl; import com.intellij.CommonBundle; import com.intellij.analysis.AnalysisScope; import com.intellij.compiler.*; +import com.intellij.compiler.impl.newApi.NewCompiler; import com.intellij.compiler.make.CacheCorruptedException; import com.intellij.compiler.make.CacheUtils; import com.intellij.compiler.make.DependencyCache; @@ -560,7 +561,7 @@ public class CompileDriver { return CompilerBundle.message("status.compilation.completed.successfully.with.warnings.and.errors", errorCount, warningCount); } - private static class ExitStatus { + static class ExitStatus { private final String myName; private ExitStatus(@NonNls String name) { @@ -577,10 +578,10 @@ public class CompileDriver { public static final ExitStatus UP_TO_DATE = new ExitStatus("UP_TO_DATE"); } - private static class ExitException extends Exception { + static class ExitException extends Exception { private final ExitStatus myStatus; - private ExitException(ExitStatus status) { + ExitException(ExitStatus status) { myStatus = status; } @@ -724,7 +725,7 @@ public class CompileDriver { boolean didSomething = false; final CompilerManager compilerManager = CompilerManager.getInstance(myProject); - + NewCompilerRunner runner = new NewCompilerRunner(context, compilerManager, forceCompile, onlyCheckStatus); try { didSomething |= generateSources(compilerManager, context, forceCompile, onlyCheckStatus); @@ -746,19 +747,23 @@ public class CompileDriver { didSomething |= invokeFileProcessingCompilers(compilerManager, context, ClassInstrumentingCompiler.class, FILE_PROCESSING_COMPILER_ADAPTER_FACTORY, isRebuild, false, onlyCheckStatus); + didSomething |= runner.invokeCompilers(NewCompiler.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(NewCompiler.CompileOrderPlace.CLASS_POST_PROCESSING); didSomething |= invokeFileProcessingCompilers(compilerManager, context, PackagingCompiler.class, FILE_PACKAGING_COMPILER_ADAPTER_FACTORY, isRebuild, false, onlyCheckStatus); + didSomething |= runner.invokeCompilers(NewCompiler.CompileOrderPlace.PACKAGING); didSomething |= invokeFileProcessingCompilers(compilerManager, context, Validator.class, FILE_PROCESSING_COMPILER_ADAPTER_FACTORY, forceCompile, true, onlyCheckStatus); + didSomething |= runner.invokeCompilers(NewCompiler.CompileOrderPlace.VALIDATING); } catch (ExitException e) { if (LOG.isDebugEnabled()) { diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompilerCacheManager.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompilerCacheManager.java index c99dc6f64924..76082f3fbce2 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompilerCacheManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompilerCacheManager.java @@ -15,6 +15,8 @@ */ package com.intellij.compiler.impl; +import com.intellij.compiler.impl.newApi.NewCompiler; +import com.intellij.compiler.impl.newApi.NewCompilerCache; import com.intellij.openapi.Disposable; import com.intellij.openapi.compiler.*; import com.intellij.openapi.compiler.Compiler; @@ -42,6 +44,7 @@ import java.util.Map; public class CompilerCacheManager implements ProjectComponent { private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.CompilerCacheManager"); private final Map myCompilerToCacheMap = new HashMap(); + private final Map, NewCompilerCache> myNewCachesMap = new HashMap, NewCompilerCache>(); private final List myCacheDisposables = new ArrayList(); private final File myCachesRoot; private final Runnable myShutdownTask = new Runnable() { @@ -49,8 +52,10 @@ public class CompilerCacheManager implements ProjectComponent { flushCaches(); } }; + private final Project myProject; public CompilerCacheManager(Project project) { + myProject = project; myCachesRoot = CompilerPaths.getCacheStoreDirectory(project); } @@ -85,6 +90,23 @@ public class CompilerCacheManager implements ProjectComponent { return dir; } + public synchronized NewCompilerCache getNewCompilerCache(NewCompiler compiler) throws IOException { + NewCompilerCache cache = myNewCachesMap.get(compiler); + if (cache == null) { + final NewCompilerCache newCache = new NewCompilerCache(compiler, NewCompilerRunner.getNewCompilerCacheDir(myProject, compiler)); + myNewCachesMap.put(compiler, newCache); + myCacheDisposables.add(new Disposable() { + @Override + public void dispose() { + newCache.close(); + } + }); + cache = newCache; + } + //noinspection unchecked + return (NewCompilerCache)cache; + } + public synchronized FileProcessingCompilerStateCache getFileProcessingCompilerCache(FileProcessingCompiler compiler) throws IOException { Object cache = myCompilerToCacheMap.get(compiler); if (cache == null) { diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/NewCompilerRunner.java b/java/compiler/impl/src/com/intellij/compiler/impl/NewCompilerRunner.java new file mode 100644 index 000000000000..a5dc5e2ffc24 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/impl/NewCompilerRunner.java @@ -0,0 +1,246 @@ +/* + * 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.compiler.impl; + +import com.intellij.compiler.impl.newApi.*; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.compiler.*; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Ref; +import com.intellij.util.CommonProcessors; +import com.intellij.util.Processor; +import com.intellij.util.io.KeyDescriptor; +import gnu.trove.THashSet; +import gnu.trove.TObjectHashingStrategy; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * @author nik + */ +public class NewCompilerRunner { + private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.NewCompilerRunner"); + private CompileContext myContext; + private final boolean myForceCompile; + private final boolean myOnlyCheckStatus; + private final NewCompiler[] myCompilers; + private final Project myProject; + + public NewCompilerRunner(CompileContext context, CompilerManager compilerManager, boolean forceCompile, boolean onlyCheckStatus) { + myContext = context; + myForceCompile = forceCompile; + myOnlyCheckStatus = onlyCheckStatus; + myCompilers = compilerManager.getCompilers(NewCompiler.class); + myProject = myContext.getProject(); + } + + public boolean invokeCompilers(NewCompiler.CompileOrderPlace place) throws CompileDriver.ExitException { + boolean didSomething = false; + try { + for (NewCompiler compiler : myCompilers) { + if (compiler.getOrderPlace().equals(place)) { + didSomething = invokeCompiler(compiler); + } + } + } + catch (IOException e) { + LOG.info(e); + myContext.requestRebuildNextTime(e.getMessage()); + throw new CompileDriver.ExitException(CompileDriver.ExitStatus.ERRORS); + } + catch (CompileDriver.ExitException e) { + throw e; + } + catch (ProcessCanceledException e) { + throw e; + } + catch (Exception e) { + LOG.info(e); + myContext.addMessage(CompilerMessageCategory.ERROR, CompilerBundle.message("compiler.error.exception", e.getMessage()), null, -1, -1); + } + return didSomething; + } + + private boolean invokeCompiler(NewCompiler compiler) throws IOException, CompileDriver.ExitException { + return invokeCompiler(compiler, compiler.createInstance(myContext)); + } + + private , Key, State> + boolean invokeCompiler(NewCompiler compiler, CompilerInstance instance) throws IOException, CompileDriver.ExitException { + NewCompilerCache cache = CompilerCacheManager.getInstance(myProject).getNewCompilerCache(compiler); + NewCompilerPersistentData data = new NewCompilerPersistentData(getNewCompilerCacheDir(myProject, compiler), compiler.getVersion()); + if (data.isVersionChanged()) { + LOG.info("Clearing cache for " + compiler.getDescription()); + cache.wipe(); + } + + Set targetsToRemove = new HashSet(data.getAllTargets()); + for (T target : instance.getAllTargets()) { + targetsToRemove.remove(target.getId()); + } + if (!myOnlyCheckStatus) { + for (String target : targetsToRemove) { + int id = data.removeId(target); + if (LOG.isDebugEnabled()) { + LOG.debug("Removing obsolete target '" + target + "' (id=" + id + ")"); + } + List keys = new ArrayList(); + cache.processSources(id, new CommonProcessors.CollectProcessor(keys)); + List> obsoleteSources = new ArrayList>(); + for (Key key : keys) { + final State state = cache.getState(id, key); + obsoleteSources.add(Pair.create(key, state)); + } + instance.processObsoleteTarget(target, obsoleteSources); + if (myContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) { + return true; + } + for (Key key : keys) { + cache.remove(id, key); + } + } + } + + boolean didSomething = false; + for (T target : instance.getSelectedTargets()) { + int id = data.getId(target.getId()); + didSomething |= processTarget(target, id, compiler, instance, cache); + } + + data.save(); + return didSomething; + } + + public static File getNewCompilerCacheDir(Project project, NewCompiler compiler) { + return new File(CompilerPaths.getCacheStoreDirectory(project), compiler.getId()); + } + + private , Key, State> + boolean processTarget(T target, final int targetId, final NewCompiler compiler, final CompilerInstance instance, + final NewCompilerCache cache) throws IOException, CompileDriver.ExitException { + if (LOG.isDebugEnabled()) { + LOG.debug("Processing target '" + target + "' (id=" + targetId + ")"); + } + final List items = instance.getItems(target); + if (myContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) return true; + + final List> toProcess = new ArrayList>(); + final THashSet keySet = new THashSet(new SourceItemHashingStrategy(compiler)); + final Ref exception = Ref.create(null); + DumbService.getInstance(myProject).waitForSmartMode(); + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + try { + for (Item item : items) { + final Key key = item.getKey(); + keySet.add(key); + State output = cache.getState(targetId, key); + if (myForceCompile || output == null || !item.isUpToDate(output)) { + toProcess.add(Pair.create(item, output)); + } + } + } + catch (IOException e) { + exception.set(e); + } + } + }); + if (!exception.isNull()) { + throw exception.get(); + } + + final List toRemove = new ArrayList(); + cache.processSources(targetId, new Processor() { + @Override + public boolean process(Key key) { + if (!keySet.contains(key)) { + toRemove.add(key); + } + return true; + } + }); + + if (LOG.isDebugEnabled()) { + LOG.debug(toProcess.size() + " items will be processed, " + toRemove.size() + " items will be removed"); + } + + if (toProcess.isEmpty() && toRemove.isEmpty()) { + return false; + } + + if (myOnlyCheckStatus) { + throw new CompileDriver.ExitException(CompileDriver.ExitStatus.CANCELLED); + } + + List> obsoleteItems = new ArrayList>(); + for (Key key : toRemove) { + obsoleteItems.add(Pair.create(key, cache.getState(targetId, key))); + } + + final List processedItems = new ArrayList(); + final List toRefresh = new ArrayList(); + instance.processItems(target, toProcess, obsoleteItems, new CompilerInstance.OutputConsumer() { + @Override + public void addFileToRefresh(@NotNull File file) { + toRefresh.add(file); + } + @Override + public void addProcessedItem(@NotNull Item sourceItem) { + processedItems.add(sourceItem); + } + }); + if (myContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) { + return true; + } + + for (Key key : toRemove) { + cache.remove(targetId, key); + } + CompilerUtil.refreshIOFiles(toRefresh); + for (Item item : processedItems) { + cache.putOutput(targetId, item.getKey(), item.computeState()); + } + + return true; + + } + + private class SourceItemHashingStrategy implements TObjectHashingStrategy { + private KeyDescriptor myKeyDescriptor; + + public SourceItemHashingStrategy(NewCompiler compiler) { + myKeyDescriptor = compiler.getItemKeyDescriptor(); + } + + @Override + public int computeHashCode(S object) { + return myKeyDescriptor.getHashCode(object); + } + + @Override + public boolean equals(S o1, S o2) { + return myKeyDescriptor.isEqual(o1, o2); + } + } +} diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/BuildTarget.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/BuildTarget.java new file mode 100644 index 000000000000..a53ffc1ff9c0 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/BuildTarget.java @@ -0,0 +1,39 @@ +/* + * 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.compiler.impl.newApi; + +import org.jetbrains.annotations.NotNull; + +/** + * @author nik + */ +public abstract class BuildTarget { + public static final BuildTarget DEFAULT = new BuildTarget() { + @NotNull + @Override + public String getId() { + return ""; + } + }; + + @NotNull + public abstract String getId(); + + @Override + public String toString() { + return "Build Target: " + getId(); + } +} diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/CompileItem.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/CompileItem.java new file mode 100644 index 000000000000..fb941ca3e4b2 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/CompileItem.java @@ -0,0 +1,31 @@ +/* + * 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.compiler.impl.newApi; + +import org.jetbrains.annotations.NotNull; + +/** + * @author nik + */ +public abstract class CompileItem { + @NotNull + public abstract Key getKey(); + + public abstract boolean isUpToDate(@NotNull State state); + + @NotNull + public abstract State computeState(); +} diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/CompilerInstance.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/CompilerInstance.java new file mode 100644 index 000000000000..2e9f9cf59593 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/CompilerInstance.java @@ -0,0 +1,60 @@ +/* + * 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.compiler.impl.newApi; + +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.List; + +/** + * @author nik + */ +public abstract class CompilerInstance, Key, State> { + protected final CompileContext myContext; + + protected CompilerInstance(CompileContext context) { + myContext = context; + } + + protected Project getProject() { + return myContext.getProject(); + } + + @NotNull + public abstract List getAllTargets(); + + @NotNull + public abstract List getSelectedTargets(); + + public abstract void processObsoleteTarget(@NotNull String targetId, @NotNull List> obsoleteItems); + + + @NotNull + public abstract List getItems(@NotNull T target); + + public abstract void processItems(@NotNull T target, @NotNull List> changedItems, @NotNull List> obsoleteItems, + @NotNull OutputConsumer consumer); + + public interface OutputConsumer> { + void addFileToRefresh(@NotNull File file); + + void addProcessedItem(@NotNull Item sourceItem); + } +} diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompiler.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompiler.java new file mode 100644 index 000000000000..b82b8bf9d84c --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompiler.java @@ -0,0 +1,62 @@ +/* + * 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.compiler.impl.newApi; + +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.Compiler; +import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.KeyDescriptor; +import org.jetbrains.annotations.NotNull; + +/** + * @author nik + */ +public abstract class NewCompiler implements Compiler { + private final String myId; + private final int myVersion; + private final CompileOrderPlace myOrderPlace; + + protected NewCompiler(@NotNull String id, int version, @NotNull CompileOrderPlace orderPlace) { + myId = id; + myVersion = version; + myOrderPlace = orderPlace; + } + + @NotNull + public abstract KeyDescriptor getItemKeyDescriptor(); + @NotNull + public abstract DataExternalizer getItemStateExternalizer(); + + @NotNull + public abstract CompilerInstance, Key, State> createInstance(@NotNull CompileContext context); + + public final String getId() { + return myId; + } + + public final int getVersion() { + return myVersion; + } + + public CompileOrderPlace getOrderPlace() { + return myOrderPlace; + } + + public static enum CompileOrderPlace { + CLASS_INSTRUMENTING, CLASS_POST_PROCESSING, PACKAGING, VALIDATING + } + +} diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerCache.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerCache.java new file mode 100644 index 000000000000..0b6ea2ecc3e0 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerCache.java @@ -0,0 +1,132 @@ +/* + * 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.compiler.impl.newApi; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.Processor; +import com.intellij.util.io.KeyDescriptor; +import com.intellij.util.io.PersistentHashMap; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.File; +import java.io.IOException; + +/** + * @author nik + */ +public class NewCompilerCache { + private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.newApi.NewCompilerCache"); + private PersistentHashMap, State> myPersistentMap; + private File myCacheFile; + private final NewCompiler myCompiler; + + public NewCompilerCache(NewCompiler compiler, final File compilerCacheDir) throws IOException { + myCompiler = compiler; + myCacheFile = new File(compilerCacheDir, "timestamps"); + createMap(); + } + + private void createMap() throws IOException { + myPersistentMap = new PersistentHashMap, State>(myCacheFile, new SourceItemDataDescriptor(myCompiler.getItemKeyDescriptor()), + myCompiler.getItemStateExternalizer()); + } + + private KeyAndTargetData getKeyAndTargetData(Key key, int target) { + KeyAndTargetData data = new KeyAndTargetData(); + data.myTarget = target; + data.myKey = key; + return data; + } + + public void wipe() throws IOException { + try { + myPersistentMap.close(); + } + catch (IOException ignored) { + } + PersistentHashMap.deleteFilesStartingWith(myCacheFile); + createMap(); + } + + public void close() { + try { + myPersistentMap.close(); + } + catch (IOException e) { + LOG.info(e); + } + } + + public void remove(int targetId, Key key) throws IOException { + myPersistentMap.remove(getKeyAndTargetData(key, targetId)); + } + + public State getState(int targetId, Key key) throws IOException { + return myPersistentMap.get(getKeyAndTargetData(key, targetId)); + } + + public void processSources(final int targetId, final Processor processor) throws IOException { + myPersistentMap.processKeys(new Processor>() { + @Override + public boolean process(KeyAndTargetData data) { + return targetId == data.myTarget ? processor.process(data.myKey) : true; + } + }); + } + + public void putOutput(int targetId, Key key, State outputItem) throws IOException { + myPersistentMap.put(getKeyAndTargetData(key, targetId), outputItem); + } + + + private static class KeyAndTargetData { + public int myTarget; + public Key myKey; + } + + private class SourceItemDataDescriptor implements KeyDescriptor> { + private final KeyDescriptor myKeyDescriptor; + + public SourceItemDataDescriptor(KeyDescriptor keyDescriptor) { + myKeyDescriptor = keyDescriptor; + } + + @Override + public boolean isEqual(KeyAndTargetData val1, KeyAndTargetData val2) { + return val1.myTarget == val2.myTarget; + } + + @Override + public int getHashCode(KeyAndTargetData value) { + return value.myTarget + 239 * myKeyDescriptor.getHashCode(value.myKey); + } + + @Override + public void save(DataOutput out, KeyAndTargetData value) throws IOException { + out.writeInt(value.myTarget); + myKeyDescriptor.save(out, value.myKey); + } + + + @Override + public KeyAndTargetData read(DataInput in) throws IOException { + int target = in.readInt(); + final Key item = myKeyDescriptor.read(in); + return getKeyAndTargetData(item, target); + } + } +} diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerPersistentData.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerPersistentData.java new file mode 100644 index 000000000000..1746c334cf77 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/NewCompilerPersistentData.java @@ -0,0 +1,119 @@ +/* + * 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.compiler.impl.newApi; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.io.IOUtil; +import gnu.trove.TIntHashSet; +import org.jetbrains.annotations.NotNull; + +import java.io.*; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * @author nik + */ +public class NewCompilerPersistentData { + private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.newApi.NewCompilerPersistentData"); + private static final int VERSION = 0; + private File myFile; + private Map myTarget2Id = new HashMap(); + private TIntHashSet myUsedIds = new TIntHashSet(); + private boolean myVersionChanged; + private final int myCompilerVersion; + + public NewCompilerPersistentData(File cacheStoreDirectory, int compilerVersion) throws IOException { + myCompilerVersion = compilerVersion; + myFile = new File(cacheStoreDirectory, "info"); + if (!myFile.exists()) { + LOG.info("Compiler info file doesn't exists: " + myFile.getAbsolutePath()); + myVersionChanged = true; + return; + } + + DataInputStream input = new DataInputStream(new FileInputStream(myFile)); + try { + final int dataVersion = input.readInt(); + if (dataVersion != VERSION) { + LOG.info("Version of compiler info file (" + myFile.getAbsolutePath() + ") changed: " + dataVersion + " -> " + VERSION); + myVersionChanged = true; + return; + } + + final int savedCompilerVersion = input.readInt(); + if (savedCompilerVersion != compilerVersion) { + LOG.info("Compiler caches version changed (" + myFile.getAbsolutePath() + "): " + savedCompilerVersion + " -> " + compilerVersion); + myVersionChanged = true; + return; + } + + int size = input.readInt(); + while (size-- > 0) { + final String target = IOUtil.readString(input); + final int id = input.readInt(); + myTarget2Id.put(target, id); + myUsedIds.add(id); + } + } + finally { + input.close(); + } + } + + public boolean isVersionChanged() { + return myVersionChanged; + } + + public void save() throws IOException { + final DataOutputStream output = new DataOutputStream(new FileOutputStream(myFile)); + try { + output.writeInt(VERSION); + output.writeInt(myCompilerVersion); + output.writeInt(myTarget2Id.size()); + + for (Map.Entry entry : myTarget2Id.entrySet()) { + IOUtil.writeString(entry.getKey(), output); + output.writeInt(entry.getValue()); + } + } + finally { + output.close(); + } + } + + public int getId(@NotNull String target) { + if (myTarget2Id.containsKey(target)) { + return myTarget2Id.get(target); + } + int id = 0; + while (myUsedIds.contains(id)) { + id++; + } + myTarget2Id.put(target, id); + myUsedIds.add(id); + return id; + } + + public Set getAllTargets() { + return myTarget2Id.keySet(); + } + + public int removeId(String target) { + return myTarget2Id.remove(target); + } +} diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/SingleTargetCompilerInstance.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/SingleTargetCompilerInstance.java new file mode 100644 index 000000000000..359366e70bb4 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/SingleTargetCompilerInstance.java @@ -0,0 +1,48 @@ +/* + * 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.compiler.impl.newApi; + +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.util.Pair; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * @author nik + */ +public abstract class SingleTargetCompilerInstance, S, O> extends CompilerInstance { + protected SingleTargetCompilerInstance(CompileContext context) { + super(context); + } + + @NotNull + @Override + public List getAllTargets() { + return Collections.singletonList(BuildTarget.DEFAULT); + } + + @NotNull + @Override + public List getSelectedTargets() { + return getAllTargets(); + } + + @Override + public void processObsoleteTarget(@NotNull String targetId, @NotNull List> obsoleteItems) { + } +} diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/VirtualFileCompileItem.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/VirtualFileCompileItem.java new file mode 100644 index 000000000000..a2c0b7055c9f --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/VirtualFileCompileItem.java @@ -0,0 +1,55 @@ +/* + * 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.compiler.impl.newApi; + +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.io.EnumeratorStringDescriptor; +import com.intellij.util.io.KeyDescriptor; +import org.jetbrains.annotations.NotNull; + +/** + * @author nik + */ +public abstract class VirtualFileCompileItem extends CompileItem { + public static final KeyDescriptor KEY_DESCRIPTOR = new EnumeratorStringDescriptor(); + protected final VirtualFile myFile; + + public VirtualFileCompileItem(@NotNull VirtualFile file) { + myFile = file; + } + + @NotNull + public VirtualFile getFile() { + return myFile; + } + + @Override + public final boolean isUpToDate(@NotNull State state) { + if (myFile.getTimeStamp() != state.getSourceTimestamp()) { + return false; + } + return isStateUpToDate(state); + } + + protected abstract boolean isStateUpToDate(State state); + + @NotNull + @Override + public String getKey() { + return myFile.getUrl(); + } + +} diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/VirtualFilePersistentState.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/VirtualFilePersistentState.java new file mode 100644 index 000000000000..9f30a9182e99 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/VirtualFilePersistentState.java @@ -0,0 +1,31 @@ +/* + * 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.compiler.impl.newApi; + +/** +* @author nik +*/ +public class VirtualFilePersistentState { + private final long mySourceTimestamp; + + public VirtualFilePersistentState(long sourceTimestamp) { + mySourceTimestamp = sourceTimestamp; + } + + public final long getSourceTimestamp() { + return mySourceTimestamp; + } +} diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/newApi/VirtualFileStateExternalizer.java b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/VirtualFileStateExternalizer.java new file mode 100644 index 000000000000..6ca460108979 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/impl/newApi/VirtualFileStateExternalizer.java @@ -0,0 +1,44 @@ +/* + * 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.compiler.impl.newApi; + +import com.intellij.util.io.DataExternalizer; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +/** +* @author nik +*/ +public abstract class VirtualFileStateExternalizer implements DataExternalizer { + protected abstract void doSave(DataOutput out, State value) throws IOException; + + protected abstract State doRead(DataInput in, long sourceTimestamp) throws IOException; + + @Override + public final void save(DataOutput out, State value) throws IOException { + out.writeLong(value.getSourceTimestamp()); + doSave(out, value); + } + + @Override + public final State read(DataInput in) throws IOException { + final long sourceTimestamp = in.readLong(); + return doRead(in, sourceTimestamp); + } + +} From 6fdc9a7e5752c43d11e6b3b20563dda7c87d4a7b Mon Sep 17 00:00:00 2001 From: nik Date: Wed, 28 Jul 2010 12:54:13 +0400 Subject: [PATCH 16/17] artifacts compiler migrated to new api --- .../compiler/CompilerManagerImpl.java | 2 - .../packagingCompiler/JarDestinationInfo.java | 10 +- ...rtifactAdditionalCompileScopeProvider.java | 2 +- .../impl/compiler/ArtifactBuildTarget.java | 41 ++ .../compiler/ArtifactCompilerCompileItem.java | 86 +++ .../ArtifactPackagingItemExternalizer.java | 54 ++ .../ArtifactPackagingItemOutputState.java | 32 + .../ArtifactPackagingItemValidityState.java | 102 --- .../ArtifactPackagingProcessingItem.java | 96 --- .../impl/compiler/ArtifactsCompiler.java | 88 +++ .../compiler/ArtifactsCompilerInstance.java | 389 ++++++++++++ ...rtifactsProcessingItemsBuilderContext.java | 26 +- .../CopyToDirectoryInstructionCreator.java | 3 +- .../IncrementalArtifactsCompiler.java | 583 ------------------ .../PackIntoArchiveInstructionCreator.java | 7 +- .../BuildArtifactsBeforeRunTaskProvider.java | 4 +- resources/src/META-INF/IdeaPlugin.xml | 1 + 17 files changed, 718 insertions(+), 808 deletions(-) create mode 100644 java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactBuildTarget.java create mode 100644 java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactCompilerCompileItem.java create mode 100644 java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemExternalizer.java create mode 100644 java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemOutputState.java delete mode 100644 java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemValidityState.java delete mode 100644 java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingProcessingItem.java create mode 100644 java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompiler.java create mode 100644 java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompilerInstance.java delete mode 100644 java/compiler/impl/src/com/intellij/packaging/impl/compiler/IncrementalArtifactsCompiler.java diff --git a/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java b/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java index 1f5fbdf98164..273514938618 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java @@ -29,7 +29,6 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.packaging.impl.compiler.IncrementalArtifactsCompiler; import com.intellij.util.ArrayUtil; import com.intellij.util.Chunk; import com.intellij.util.containers.ContainerUtil; @@ -68,7 +67,6 @@ public class CompilerManagerImpl extends CompilerManager { addTranslatingCompiler(new JavaCompiler(project), new HashSet(Arrays.asList(StdFileTypes.JAVA)), new HashSet(Arrays.asList(StdFileTypes.CLASS))); addCompiler(new ResourceCompiler(project, compilerConfiguration)); addCompiler(new RmicCompiler()); - addCompiler(new IncrementalArtifactsCompiler()); for(Compiler compiler: Extensions.getExtensions(Compiler.EP_NAME, myProject)) { addCompiler(compiler); diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/packagingCompiler/JarDestinationInfo.java b/java/compiler/impl/src/com/intellij/compiler/impl/packagingCompiler/JarDestinationInfo.java index 8e0e53a29ff9..5cc45c19278e 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/packagingCompiler/JarDestinationInfo.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/packagingCompiler/JarDestinationInfo.java @@ -16,9 +16,9 @@ package com.intellij.compiler.impl.packagingCompiler; -import com.intellij.openapi.deployment.DeploymentUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.JarFileSystem; /** * @author nik @@ -29,12 +29,18 @@ public class JarDestinationInfo extends DestinationInfo { private final JarInfo myJarInfo; public JarDestinationInfo(final String pathInJar, final JarInfo jarInfo, DestinationInfo jarDestination) { - super(DeploymentUtil.appendToPath(jarDestination.getOutputPath(), pathInJar), jarDestination.getOutputFile(), jarDestination.getOutputFilePath()); + super(appendPathInJar(jarDestination.getOutputPath(), pathInJar), jarDestination.getOutputFile(), jarDestination.getOutputFilePath()); LOG.assertTrue(!pathInJar.startsWith(".."), pathInJar); myPathInJar = StringUtil.startsWithChar(pathInJar, '/') ? pathInJar : "/" + pathInJar; myJarInfo = jarInfo; } + private static String appendPathInJar(String outputPath, String pathInJar) { + LOG.assertTrue(outputPath.length() > 0 && outputPath.charAt(outputPath.length() - 1) != '/'); + LOG.assertTrue(pathInJar.length() > 0 && pathInJar.charAt(0) != '/'); + return outputPath + JarFileSystem.JAR_SEPARATOR + pathInJar; + } + public String getPathInJar() { return myPathInJar; } diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactAdditionalCompileScopeProvider.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactAdditionalCompileScopeProvider.java index 6fdbb1d3f33d..78f9c1221117 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactAdditionalCompileScopeProvider.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactAdditionalCompileScopeProvider.java @@ -35,7 +35,7 @@ public class ArtifactAdditionalCompileScopeProvider extends AdditionalCompileSco if (ArtifactCompileScope.getArtifacts(baseScope) != null) { return null; } - final IncrementalArtifactsCompiler compiler = IncrementalArtifactsCompiler.getInstance(project); + final ArtifactsCompiler compiler = ArtifactsCompiler.getInstance(project); if (compiler == null || !filter.acceptCompiler(compiler)) { return null; } diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactBuildTarget.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactBuildTarget.java new file mode 100644 index 000000000000..41aeba8c8516 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactBuildTarget.java @@ -0,0 +1,41 @@ +/* + * 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.packaging.impl.compiler; + +import com.intellij.compiler.impl.newApi.BuildTarget; +import com.intellij.packaging.artifacts.Artifact; +import org.jetbrains.annotations.NotNull; + +/** + * @author nik + */ +public class ArtifactBuildTarget extends BuildTarget { + private Artifact myArtifact; + + public ArtifactBuildTarget(Artifact artifact) { + myArtifact = artifact; + } + + public Artifact getArtifact() { + return myArtifact; + } + + @NotNull + @Override + public String getId() { + return myArtifact.getName(); + } +} diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactCompilerCompileItem.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactCompilerCompileItem.java new file mode 100644 index 000000000000..517bef7e89d3 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactCompilerCompileItem.java @@ -0,0 +1,86 @@ +/* + * 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.packaging.impl.compiler; + +import com.intellij.compiler.impl.newApi.VirtualFileCompileItem; +import com.intellij.compiler.impl.packagingCompiler.DestinationInfo; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.SmartList; +import com.intellij.util.io.DataExternalizer; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author nik + */ +public class ArtifactCompilerCompileItem extends VirtualFileCompileItem { + public static final DataExternalizer OUTPUT_EXTERNALIZER = new ArtifactPackagingItemExternalizer(); + private final List myDestinations = new SmartList(); + + public ArtifactCompilerCompileItem(VirtualFile file) { + super(file); + } + + public void addDestination(DestinationInfo info) { + myDestinations.add(info); + } + + public List getDestinations() { + return myDestinations; + } + + @NotNull + @Override + public ArtifactPackagingItemOutputState computeState() { + final SmartList> pairs = new SmartList>(); + for (DestinationInfo destination : myDestinations) { + destination.update(); + final VirtualFile outputFile = destination.getOutputFile(); + long timestamp = outputFile != null ? outputFile.getTimeStamp() : -1; + pairs.add(Pair.create(destination.getOutputPath(), timestamp)); + } + return new ArtifactPackagingItemOutputState(myFile.getTimeStamp(), pairs); + } + + @Override + public boolean isStateUpToDate(ArtifactPackagingItemOutputState state) { + final SmartList> cachedDestinations = state.myDestinations; + if (cachedDestinations.size() != myDestinations.size()) { + return false; + } + + for (DestinationInfo info : myDestinations) { + final VirtualFile outputFile = info.getOutputFile(); + long timestamp = outputFile != null ? outputFile.getTimeStamp() : -1; + final String path = info.getOutputPath(); + boolean found = false; + //todo[nik] use map if list contains many items + for (Pair cachedDestination : cachedDestinations) { + if (cachedDestination.first.equals(path)) { + if (cachedDestination.second != timestamp) return false; + found = true; + break; + } + } + if (!found) return false; + } + + return true; + } + +} diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemExternalizer.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemExternalizer.java new file mode 100644 index 000000000000..f1adc4c406e1 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemExternalizer.java @@ -0,0 +1,54 @@ +/* + * 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.packaging.impl.compiler; + +import com.intellij.compiler.impl.newApi.VirtualFileStateExternalizer; +import com.intellij.openapi.util.Pair; +import com.intellij.util.SmartList; +import com.intellij.util.io.IOUtil; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +/** +* @author nik +*/ +public class ArtifactPackagingItemExternalizer + extends VirtualFileStateExternalizer { + private byte[] myBuffer = IOUtil.allocReadWriteUTFBuffer(); + + @Override + protected void doSave(DataOutput out, ArtifactPackagingItemOutputState value) throws IOException { + out.writeInt(value.myDestinations.size()); + for (Pair pair : value.myDestinations) { + IOUtil.writeUTFFast(myBuffer, out, pair.getFirst()); + out.writeLong(pair.getSecond()); + } + } + + @Override + protected ArtifactPackagingItemOutputState doRead(DataInput in, long sourceTimestamp) throws IOException { + int size = in.readInt(); + SmartList> destinations = new SmartList>(); + while (size-- > 0) { + String path = IOUtil.readUTFFast(myBuffer, in); + long outputTimestamp = in.readLong(); + destinations.add(Pair.create(path, outputTimestamp)); + } + return new ArtifactPackagingItemOutputState(sourceTimestamp, destinations); + } +} diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemOutputState.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemOutputState.java new file mode 100644 index 000000000000..e93390d6bc72 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemOutputState.java @@ -0,0 +1,32 @@ +/* + * 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.packaging.impl.compiler; + +import com.intellij.compiler.impl.newApi.VirtualFilePersistentState; +import com.intellij.openapi.util.Pair; +import com.intellij.util.SmartList; + +/** +* @author nik +*/ +public class ArtifactPackagingItemOutputState extends VirtualFilePersistentState { + public final SmartList> myDestinations; + + public ArtifactPackagingItemOutputState(long timestamp, SmartList> destinations) { + super(timestamp); + myDestinations = destinations; + } +} diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemValidityState.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemValidityState.java deleted file mode 100644 index 2dbf9cca5dea..000000000000 --- a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingItemValidityState.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.packaging.impl.compiler; - -import com.intellij.compiler.impl.packagingCompiler.DestinationInfo; -import com.intellij.openapi.compiler.ValidityState; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.SmartList; -import com.intellij.util.StringSetSpinAllocator; -import com.intellij.util.io.IOUtil; -import org.jetbrains.annotations.Nullable; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.util.List; -import java.util.Set; - -/** - * @author nik - */ -public class ArtifactPackagingItemValidityState implements ValidityState { - private final SmartList> myDestinations; - - public ArtifactPackagingItemValidityState(List destinationInfos, boolean sourceFileModified, - @Nullable ArtifactPackagingItemValidityState oldState) { - myDestinations = new SmartList>(); - final Set paths = StringSetSpinAllocator.alloc(); - try { - for (DestinationInfo info : destinationInfos) { - final VirtualFile outputFile = info.getOutputFile(); - long timestamp = outputFile != null ? outputFile.getTimeStamp() : -1; - final String path = info.getOutputPath(); - myDestinations.add(Pair.create(path, timestamp)); - paths.add(path); - } - - if (!sourceFileModified && oldState != null) { - for (Pair pair : oldState.myDestinations) { - if (!paths.contains(pair.getFirst())) { - myDestinations.add(pair); - } - } - } - } - finally { - StringSetSpinAllocator.dispose(paths); - } - } - - public ArtifactPackagingItemValidityState(DataInput input) throws IOException { - int size = input.readInt(); - myDestinations = new SmartList>(); - while (size-- > 0) { - String path = IOUtil.readString(input); - long timestamp = input.readLong(); - myDestinations.add(Pair.create(path, timestamp)); - } - } - - public boolean equalsTo(final ValidityState otherState) { - if (!(otherState instanceof ArtifactPackagingItemValidityState)) { - return false; - } - - final SmartList> otherDestinations = ((ArtifactPackagingItemValidityState)otherState).myDestinations; - if (otherDestinations.size() != myDestinations.size()) { - return false; - } - - if (myDestinations.size() == 1) { - return myDestinations.get(0).equals(otherDestinations.get(0)); - } - - return Comparing.haveEqualElements(myDestinations, otherDestinations); - } - - - public void save(final DataOutput output) throws IOException { - output.writeInt(myDestinations.size()); - for (Pair pair : myDestinations) { - IOUtil.writeString(pair.getFirst(), output); - output.writeLong(pair.getSecond()); - } - } -} \ No newline at end of file diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingProcessingItem.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingProcessingItem.java deleted file mode 100644 index 2054b9978af6..000000000000 --- a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactPackagingProcessingItem.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.packaging.impl.compiler; - -import com.intellij.compiler.impl.FileProcessingCompilerStateCache; -import com.intellij.compiler.impl.packagingCompiler.DestinationInfo; -import com.intellij.openapi.compiler.FileProcessingCompiler; -import com.intellij.openapi.compiler.ValidityState; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.SmartList; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.util.List; - -/** - * @author nik - */ -public class ArtifactPackagingProcessingItem implements FileProcessingCompiler.ProcessingItem { - private final VirtualFile mySourceFile; - private final List> myDestinations = new SmartList>(); - private List myEnabledDestinations; - private boolean mySourceFileModified; - private ArtifactPackagingItemValidityState myOldState; - - public ArtifactPackagingProcessingItem(final VirtualFile sourceFile) { - mySourceFile = sourceFile; - } - - @NotNull - public VirtualFile getFile() { - return mySourceFile; - } - - public void addDestination(DestinationInfo info, boolean enabled) { - for (int i = 0; i < myDestinations.size(); i++) { - Pair pair = myDestinations.get(i); - if (info.getOutputPath().equals(pair.getFirst().getOutputPath())) { - if (enabled && !pair.getSecond()) { - myDestinations.set(i, Pair.create(info, true)); - } - return; - } - } - myDestinations.add(Pair.create(info, enabled)); - } - - public List> getDestinations() { - return myDestinations; - } - - public void init(FileProcessingCompilerStateCache cache) throws IOException { - final String url = mySourceFile.getUrl(); - myOldState = (ArtifactPackagingItemValidityState)cache.getExtState(url); - mySourceFileModified = cache.getTimestamp(url) != mySourceFile.getTimeStamp(); - } - - public void setProcessed() { - for (DestinationInfo destination : myEnabledDestinations) { - destination.update(); - } - } - - public List getEnabledDestinations() { - if (myEnabledDestinations == null) { - myEnabledDestinations = new SmartList(); - for (Pair destination : myDestinations) { - if (destination.getSecond()) { - myEnabledDestinations.add(destination.getFirst()); - } - } - } - return myEnabledDestinations; - } - - @Nullable - public ValidityState getValidityState() { - return new ArtifactPackagingItemValidityState(getEnabledDestinations(), mySourceFileModified, myOldState); - } -} diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompiler.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompiler.java new file mode 100644 index 000000000000..b410fe456a78 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompiler.java @@ -0,0 +1,88 @@ +/* + * 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.packaging.impl.compiler; + +import com.intellij.compiler.impl.newApi.CompileItem; +import com.intellij.compiler.impl.newApi.CompilerInstance; +import com.intellij.compiler.impl.newApi.NewCompiler; +import com.intellij.compiler.impl.newApi.VirtualFileCompileItem; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompileScope; +import com.intellij.openapi.compiler.CompilerManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Key; +import com.intellij.packaging.artifacts.Artifact; +import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.KeyDescriptor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Set; + +/** + * @author nik + */ +public class ArtifactsCompiler extends NewCompiler { + static final Key> WRITTEN_PATHS_KEY = Key.create("artifacts_written_paths"); + static final Key> AFFECTED_ARTIFACTS = Key.create("affected_artifacts"); + + public ArtifactsCompiler() { + super("artifacts_compiler", 0, NewCompiler.CompileOrderPlace.PACKAGING); + } + + @Nullable + public static ArtifactsCompiler getInstance(@NotNull Project project) { + final ArtifactsCompiler[] compilers = CompilerManager.getInstance(project).getCompilers(ArtifactsCompiler.class); + return compilers.length == 1 ? compilers[0] : null; + } + + @NotNull + @Override + public KeyDescriptor getItemKeyDescriptor() { + return VirtualFileCompileItem.KEY_DESCRIPTOR; + } + + @NotNull + @Override + public DataExternalizer getItemStateExternalizer() { + return ArtifactCompilerCompileItem.OUTPUT_EXTERNALIZER; + } + + @NotNull + @Override + public CompilerInstance, String, ArtifactPackagingItemOutputState> createInstance( + @NotNull CompileContext context) { + return new ArtifactsCompilerInstance(context); + } + + public boolean validateConfiguration(final CompileScope scope) { + return true; + } + + @NotNull + public String getDescription() { + return "Artifacts Packaging Compiler"; + } + + public static Set getAffectedArtifacts(final CompileContext compileContext) { + return compileContext.getUserData(AFFECTED_ARTIFACTS); + } + + @Nullable + public static Set getWrittenPaths(@NotNull CompileContext context) { + return context.getUserData(WRITTEN_PATHS_KEY); + } +} diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompilerInstance.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompilerInstance.java new file mode 100644 index 000000000000..f2746de16b45 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompilerInstance.java @@ -0,0 +1,389 @@ +/* + * 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.packaging.impl.compiler; + +import com.intellij.compiler.CompilerManagerImpl; +import com.intellij.compiler.impl.CompilerUtil; +import com.intellij.compiler.impl.newApi.CompilerInstance; +import com.intellij.compiler.impl.packagingCompiler.*; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompilerBundle; +import com.intellij.openapi.compiler.CompilerMessageCategory; +import com.intellij.openapi.compiler.make.BuildParticipant; +import com.intellij.openapi.compiler.make.BuildParticipantProvider; +import com.intellij.openapi.deployment.DeploymentUtil; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.JarFileSystem; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.packaging.artifacts.Artifact; +import com.intellij.packaging.artifacts.ArtifactManager; +import com.intellij.packaging.artifacts.ArtifactProperties; +import com.intellij.packaging.artifacts.ArtifactPropertiesProvider; +import com.intellij.packaging.elements.CompositePackagingElement; +import com.intellij.packaging.elements.PackagingElementResolvingContext; +import com.intellij.packaging.impl.artifacts.ArtifactValidationUtil; +import com.intellij.util.ThrowableRunnable; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.text.CaseInsensitiveStringHashingStrategy; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.util.*; + +/** + * @author nik + */ +public class ArtifactsCompilerInstance extends CompilerInstance { + private static final Logger LOG = Logger.getInstance("#com.intellij.packaging.impl.compiler.ArtifactsCompilerInstance"); + private ArtifactsProcessingItemsBuilderContext myBuilderContext; + + public ArtifactsCompilerInstance(CompileContext context) { + super(context); + } + + @NotNull + @Override + public List getAllTargets() { + return getArtifactTargets(false); + } + + @NotNull + @Override + public List getSelectedTargets() { + return getArtifactTargets(true); + } + + private List getArtifactTargets(final boolean selectedOnly) { + final List targets = new ArrayList(); + new ReadAction() { + protected void run(final Result result) { + final Set artifacts; + if (selectedOnly) { + artifacts = ArtifactCompileScope.getArtifactsToBuild(getProject(), myContext.getCompileScope()); + } + else { + artifacts = new HashSet(Arrays.asList(ArtifactManager.getInstance(getProject()).getArtifacts())); + } + List additionalArtifacts = new ArrayList(); + for (BuildParticipantProvider provider : BuildParticipantProvider.EXTENSION_POINT_NAME.getExtensions()) { + for (Module module : ModuleManager.getInstance(getProject()).getModules()) { + final Collection participants = provider.getParticipants(module); + for (BuildParticipant participant : participants) { + ContainerUtil.addIfNotNull(participant.createArtifact(myContext), additionalArtifacts); + } + } + } + if (LOG.isDebugEnabled() && !additionalArtifacts.isEmpty()) { + LOG.debug("additional artifacts to build: " + additionalArtifacts); + } + artifacts.addAll(additionalArtifacts); + + for (Artifact artifact : artifacts) { + targets.add(new ArtifactBuildTarget(artifact)); + } + if (selectedOnly) { + myContext.putUserData(ArtifactsCompiler.AFFECTED_ARTIFACTS, artifacts); + } + } + }.execute(); + return targets; + } + + @Override + public void processObsoleteTarget(@NotNull String targetId, @NotNull List> obsoleteItems) { + deleteFiles(obsoleteItems, Collections.>emptyList()); + } + + @NotNull + @Override + public List getItems(@NotNull ArtifactBuildTarget target) { + myBuilderContext = new ArtifactsProcessingItemsBuilderContext(myContext); + final Artifact artifact = target.getArtifact(); + + final Set selfIncludingArtifacts = new ReadAction>() { + protected void run(final Result> result) { + result.setResult(ArtifactValidationUtil.getInstance(getProject()).getSelfIncludingArtifacts()); + } + }.execute().getResultObject(); + if (selfIncludingArtifacts.contains(artifact)) { + myContext.addMessage(CompilerMessageCategory.ERROR, "Artifact '" + artifact.getName() + "' includes itself in the output layout", null, -1, -1); + return Collections.emptyList(); + } + + final String outputPath = artifact.getOutputPath(); + if (outputPath == null || outputPath.length() == 0) { + myContext.addMessage(CompilerMessageCategory.ERROR, "Cannot build '" + artifact.getName() + "' artifact: output path is not specified", + null, -1, -1); + return Collections.emptyList(); + } + + new ReadAction() { + protected void run(final Result result) { + collectItems(artifact, outputPath); + } + }.execute(); + return new ArrayList(myBuilderContext.getProcessingItems()); + } + + private void collectItems(@NotNull Artifact artifact, @NotNull String outputPath) { + final CompositePackagingElement rootElement = artifact.getRootElement(); + final VirtualFile outputFile = LocalFileSystem.getInstance().findFileByPath(outputPath); + final CopyToDirectoryInstructionCreator instructionCreator = new CopyToDirectoryInstructionCreator(myBuilderContext, outputPath, outputFile); + final PackagingElementResolvingContext resolvingContext = ArtifactManager.getInstance(getProject()).getResolvingContext(); + rootElement.computeIncrementalCompilerInstructions(instructionCreator, resolvingContext, myBuilderContext, artifact.getArtifactType()); + } + + private boolean doBuild(final List> changedItems, + final Set processedItems, + final Set writtenPaths, final Set deletedJars) { + final boolean testMode = ApplicationManager.getApplication().isUnitTestMode(); + + final DeploymentUtil deploymentUtil = DeploymentUtil.getInstance(); + final FileFilter fileFilter = new IgnoredFileFilter(); + final Set changedJars = new THashSet(); + for (String deletedJar : deletedJars) { + ContainerUtil.addIfNotNull(myBuilderContext.getJarInfo(deletedJar), changedJars); + } + + try { + onBuildStartedOrFinished(false); + if (myContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) { + return false; + } + + int i = 0; + for (final Pair item : changedItems) { + final ArtifactCompilerCompileItem sourceItem = item.getFirst(); + myContext.getProgressIndicator().checkCanceled(); + + final Ref exception = Ref.create(null); + new ReadAction() { + protected void run(final Result result) { + final File fromFile = VfsUtil.virtualToIoFile(sourceItem.getFile()); + for (DestinationInfo destination : sourceItem.getDestinations()) { + if (destination instanceof ExplodedDestinationInfo) { + final ExplodedDestinationInfo explodedDestination = (ExplodedDestinationInfo)destination; + File toFile = new File(FileUtil.toSystemDependentName(explodedDestination.getOutputPath())); + if (fromFile.exists()) { + try { + deploymentUtil.copyFile(fromFile, toFile, myContext, writtenPaths, fileFilter); + } + catch (IOException e) { + exception.set(e); + return; + } + } + } + else { + changedJars.add(((JarDestinationInfo)destination).getJarInfo()); + } + } + } + }.execute(); + if (exception.get() != null) { + throw exception.get(); + } + + myContext.getProgressIndicator().setFraction(++i * 1.0 / changedItems.size()); + processedItems.add(sourceItem); + if (testMode) { + CompilerManagerImpl.addRecompiledPath(FileUtil.toSystemDependentName(sourceItem.getFile().getPath())); + } + } + + JarsBuilder builder = new JarsBuilder(changedJars, fileFilter, myContext); + final boolean processed = builder.buildJars(writtenPaths); + if (!processed) { + return false; + } + + Set recompiledSources = new HashSet(); + for (JarInfo info : builder.getJarsToBuild()) { + for (Pair pair : info.getPackedFiles()) { + recompiledSources.add(pair.getSecond()); + } + } + for (VirtualFile source : recompiledSources) { + ArtifactCompilerCompileItem item = myBuilderContext.getItemBySource(source); + LOG.assertTrue(item != null, source); + processedItems.add(item); + if (testMode) { + CompilerManagerImpl.addRecompiledPath(FileUtil.toSystemDependentName(item.getFile().getPath())); + } + } + + onBuildStartedOrFinished(true); + } + catch (ProcessCanceledException e) { + throw e; + } + catch (Exception e) { + LOG.info(e); + myContext.addMessage(CompilerMessageCategory.ERROR, e.getLocalizedMessage(), null, -1, -1); + return false; + } + return true; + } + + private void onBuildStartedOrFinished(final boolean finished) throws Exception { + final Set artifacts = myContext.getUserData(ArtifactsCompiler.AFFECTED_ARTIFACTS); + if (artifacts != null) { + for (Artifact artifact : artifacts) { + for (ArtifactPropertiesProvider provider : artifact.getPropertiesProviders()) { + final ArtifactProperties properties = artifact.getProperties(provider); + if (finished) { + properties.onBuildFinished(artifact, myContext); + } + else { + properties.onBuildStarted(artifact, myContext); + } + } + } + } + } + + private static THashSet createPathsHashSet() { + return SystemInfo.isFileSystemCaseSensitive + ? new THashSet() + : new THashSet(CaseInsensitiveStringHashingStrategy.INSTANCE); + } + + @Override + public void processItems(@NotNull ArtifactBuildTarget target, @NotNull final List> changedItems, + @NotNull List> obsoleteItems, + @NotNull final OutputConsumer consumer) { + + final THashSet deletedJars = deleteFiles(obsoleteItems, changedItems); + + final Set writtenPaths = createPathsHashSet(); + final Ref built = Ref.create(false); + final Set processedItems = new HashSet(); + CompilerUtil.runInContext(myContext, "Copying files", new ThrowableRunnable() { + public void run() throws RuntimeException { + built.set(doBuild(changedItems, processedItems, writtenPaths, deletedJars)); + } + }); + if (!built.get()) { + return; + } + + myContext.getProgressIndicator().setText(CompilerBundle.message("packaging.compiler.message.updating.caches")); + myContext.getProgressIndicator().setText2(""); + for (String path : writtenPaths) { + consumer.addFileToRefresh(new File(path)); + } + for (ArtifactCompilerCompileItem item : processedItems) { + consumer.addProcessedItem(item); + } + myContext.putUserData(ArtifactsCompiler.WRITTEN_PATHS_KEY, writtenPaths); + } + + private THashSet deleteFiles(List> obsoleteItems, + List> changedItems) { + myContext.getProgressIndicator().setText(CompilerBundle.message("packaging.compiler.message.deleting.outdated.files")); + + final boolean testMode = ApplicationManager.getApplication().isUnitTestMode(); + final THashSet deletedJars = new THashSet(); + final THashSet notDeletedJars = new THashSet(); + if (LOG.isDebugEnabled()) { + LOG.debug("Deleting outdated files..."); + } + + Set pathToDelete = new THashSet(); + for (Pair item : changedItems) { + final ArtifactPackagingItemOutputState cached = item.getSecond(); + if (cached != null) { + for (Pair destination : cached.myDestinations) { + pathToDelete.add(destination.getFirst()); + } + } + } + for (Pair item : changedItems) { + for (DestinationInfo destination : item.getFirst().getDestinations()) { + pathToDelete.remove(destination.getOutputPath()); + } + } + for (Pair item : obsoleteItems) { + for (Pair destination : item.getSecond().myDestinations) { + pathToDelete.add(destination.getFirst()); + } + } + + int notDeletedFilesCount = 0; + List filesToRefresh = new ArrayList(); + + for (String fullPath : pathToDelete) { + int end = fullPath.indexOf(JarFileSystem.JAR_SEPARATOR); + boolean isJar = end != -1; + String filePath = isJar ? fullPath.substring(0, end) : fullPath; + boolean deleted = false; + if (isJar) { + if (notDeletedJars.contains(filePath)) { + continue; + } + deleted = deletedJars.contains(filePath); + } + + File file = new File(FileUtil.toSystemDependentName(filePath)); + if (!deleted) { + filesToRefresh.add(file); + deleted = FileUtil.delete(file); + } + + if (deleted) { + if (isJar) { + deletedJars.add(filePath); + } + if (testMode) { + CompilerManagerImpl.addDeletedPath(file.getAbsolutePath()); + } + } + else { + if (isJar) { + notDeletedJars.add(filePath); + } + if (notDeletedFilesCount++ > 50) { + myContext.addMessage(CompilerMessageCategory.WARNING, "Deletion of outdated files stopped because too many files cannot be deleted", null, -1, -1); + break; + } + myContext.addMessage(CompilerMessageCategory.WARNING, "Cannot delete file '" + filePath + "'", null, -1, -1); + if (LOG.isDebugEnabled()) { + LOG.debug("Cannot delete file " + file); + } + } + } + + CompilerUtil.refreshIOFiles(filesToRefresh); + return deletedJars; + } + +} diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsProcessingItemsBuilderContext.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsProcessingItemsBuilderContext.java index 33f599162f8c..21597e988500 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsProcessingItemsBuilderContext.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsProcessingItemsBuilderContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -32,15 +32,14 @@ import java.util.Map; * @author nik */ public class ArtifactsProcessingItemsBuilderContext implements ArtifactIncrementalCompilerContext { - private boolean myCollectingEnabledItems; - protected final Map myItemsBySource; + protected final Map myItemsBySource; private final Map mySourceByOutput; private final Map myJarByPath; private final CompileContext myCompileContext; public ArtifactsProcessingItemsBuilderContext(CompileContext compileContext) { myCompileContext = compileContext; - myItemsBySource = new HashMap(); + myItemsBySource = new HashMap(); mySourceByOutput = new HashMap(); myJarByPath = new HashMap(); } @@ -51,19 +50,14 @@ public class ArtifactsProcessingItemsBuilderContext implements ArtifactIncrement } if (checkOutputPath(destinationInfo.getOutputPath(), sourceFile)) { - getOrCreateProcessingItem(sourceFile).addDestination(destinationInfo, myCollectingEnabledItems); + getOrCreateProcessingItem(sourceFile).addDestination(destinationInfo); return true; } return false; } - public ArtifactPackagingProcessingItem[] getProcessingItems() { - final Collection processingItems = myItemsBySource.values(); - return processingItems.toArray(new ArtifactPackagingProcessingItem[processingItems.size()]); - } - - public void setCollectingEnabledItems(boolean collectingEnabledItems) { - myCollectingEnabledItems = collectingEnabledItems; + public Collection getProcessingItems() { + return myItemsBySource.values(); } public boolean checkOutputPath(final String outputPath, final VirtualFile sourceFile) { @@ -76,7 +70,7 @@ public class ArtifactsProcessingItemsBuilderContext implements ArtifactIncrement return false; } - public ArtifactPackagingProcessingItem getItemBySource(VirtualFile source) { + public ArtifactCompilerCompileItem getItemBySource(VirtualFile source) { return myItemsBySource.get(source); } @@ -102,10 +96,10 @@ public class ArtifactsProcessingItemsBuilderContext implements ArtifactIncrement return myCompileContext; } - public ArtifactPackagingProcessingItem getOrCreateProcessingItem(VirtualFile sourceFile) { - ArtifactPackagingProcessingItem item = myItemsBySource.get(sourceFile); + public ArtifactCompilerCompileItem getOrCreateProcessingItem(VirtualFile sourceFile) { + ArtifactCompilerCompileItem item = myItemsBySource.get(sourceFile); if (item == null) { - item = new ArtifactPackagingProcessingItem(sourceFile); + item = new ArtifactCompilerCompileItem(sourceFile); myItemsBySource.put(sourceFile, item); } return item; diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/CopyToDirectoryInstructionCreator.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/CopyToDirectoryInstructionCreator.java index 46862ac9dec4..12caefa285bd 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/CopyToDirectoryInstructionCreator.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/CopyToDirectoryInstructionCreator.java @@ -29,7 +29,8 @@ public class CopyToDirectoryInstructionCreator extends IncrementalCompilerInstru private final String myOutputPath; private final @Nullable VirtualFile myOutputFile; - public CopyToDirectoryInstructionCreator(ArtifactsProcessingItemsBuilderContext context, String outputPath, @Nullable VirtualFile outputFile) { + public CopyToDirectoryInstructionCreator(ArtifactsProcessingItemsBuilderContext context, String outputPath, + @Nullable VirtualFile outputFile) { super(context); myOutputPath = outputPath; myOutputFile = outputFile; diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/IncrementalArtifactsCompiler.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/IncrementalArtifactsCompiler.java deleted file mode 100644 index 9a322302d56c..000000000000 --- a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/IncrementalArtifactsCompiler.java +++ /dev/null @@ -1,583 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.packaging.impl.compiler; - -import com.intellij.compiler.CompilerManagerImpl; -import com.intellij.compiler.impl.CompilerCacheManager; -import com.intellij.compiler.impl.CompilerUtil; -import com.intellij.compiler.impl.FileProcessingCompilerStateCache; -import com.intellij.compiler.impl.packagingCompiler.*; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ReadAction; -import com.intellij.openapi.application.Result; -import com.intellij.openapi.compiler.*; -import com.intellij.openapi.compiler.make.BuildParticipant; -import com.intellij.openapi.compiler.make.BuildParticipantProvider; -import com.intellij.openapi.deployment.DeploymentUtil; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.Ref; -import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.JarFileSystem; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VfsUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.newvfs.RefreshQueue; -import com.intellij.packaging.artifacts.Artifact; -import com.intellij.packaging.artifacts.ArtifactManager; -import com.intellij.packaging.artifacts.ArtifactProperties; -import com.intellij.packaging.artifacts.ArtifactPropertiesProvider; -import com.intellij.packaging.elements.CompositePackagingElement; -import com.intellij.packaging.elements.PackagingElementResolvingContext; -import com.intellij.packaging.impl.artifacts.ArtifactValidationUtil; -import com.intellij.testFramework.LightVirtualFile; -import com.intellij.util.ArrayUtil; -import com.intellij.util.ThrowableRunnable; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.text.CaseInsensitiveStringHashingStrategy; -import gnu.trove.THashSet; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.DataInput; -import java.io.File; -import java.io.FileFilter; -import java.io.IOException; -import java.util.*; - -/** - * @author nik - */ -public class IncrementalArtifactsCompiler implements PackagingCompiler { - private static final Logger LOG = Logger.getInstance("#com.intellij.packaging.impl.compiler.IncrementalArtifactsCompiler"); - private static final Key> WRITTEN_PATHS_KEY = Key.create("artifacts_written_paths"); - private static final Key> FILES_TO_DELETE_KEY = Key.create("artifacts_files_to_delete"); - private static final Key> AFFECTED_ARTIFACTS = Key.create("affected_artifacts"); - private static final Key BUILDER_CONTEXT_KEY = Key.create("artifacts_builder_context"); - @Nullable private PackagingCompilerCache myOutputItemsCache; - - @Nullable - public static IncrementalArtifactsCompiler getInstance(@NotNull Project project) { - final IncrementalArtifactsCompiler[] compilers = CompilerManager.getInstance(project).getCompilers(IncrementalArtifactsCompiler.class); - return compilers.length == 1 ? compilers[0] : null; - } - - private static ArtifactPackagingProcessingItem[] collectItems(ArtifactsProcessingItemsBuilderContext builderContext, final Project project) { - final CompileContext context = builderContext.getCompileContext(); - - final Set artifactsToBuild = ArtifactCompileScope.getArtifactsToBuild(project, context.getCompileScope()); - if (LOG.isDebugEnabled()) { - LOG.debug("artifacts to build: " + artifactsToBuild); - } - List additionalArtifacts = new ArrayList(); - for (BuildParticipantProvider provider : BuildParticipantProvider.EXTENSION_POINT_NAME.getExtensions()) { - for (Module module : ModuleManager.getInstance(project).getModules()) { - final Collection participants = provider.getParticipants(module); - for (BuildParticipant participant : participants) { - ContainerUtil.addIfNotNull(participant.createArtifact(context), additionalArtifacts); - } - } - } - if (LOG.isDebugEnabled() && !additionalArtifacts.isEmpty()) { - LOG.debug("additional artifacts to build: " + additionalArtifacts); - } - artifactsToBuild.addAll(additionalArtifacts); - - final List allArtifacts = new ArrayList(Arrays.asList(ArtifactManager.getInstance(project).getArtifacts())); - allArtifacts.addAll(additionalArtifacts); - for (Artifact artifact : allArtifacts) { - final String outputPath = artifact.getOutputPath(); - if (outputPath != null && outputPath.length() != 0) { - collectItems(builderContext, artifact, outputPath, project, artifactsToBuild.contains(artifact)); - } - else if (artifactsToBuild.contains(artifact)) { - context.addMessage(CompilerMessageCategory.ERROR, "Cannot build '" + artifact.getName() + "' artifact: output path is not specified", - null, -1, -1); - } - } - context.putUserData(AFFECTED_ARTIFACTS, artifactsToBuild); - return builderContext.getProcessingItems(); - } - - @NotNull - public ProcessingItem[] getProcessingItems(final CompileContext context) { - return new ReadAction() { - protected void run(final Result result) { - final Project project = context.getProject(); - final Set selfIncludingArtifacts = ArtifactValidationUtil.getInstance(project).getSelfIncludingArtifacts(); - if (!selfIncludingArtifacts.isEmpty()) { - LOG.info("Self including artifacts: " + selfIncludingArtifacts); - if (!ArtifactCompileScope.getArtifactsToBuild(project, context.getCompileScope()).isEmpty()) { - for (Artifact artifact : selfIncludingArtifacts) { - context.addMessage(CompilerMessageCategory.ERROR, "Artifact '" + artifact.getName() + "' includes itself in the output layout", null, -1, -1); - } - } - result.setResult(ProcessingItem.EMPTY_ARRAY); - return; - } - - ArtifactsProcessingItemsBuilderContext builderContext = new ArtifactsProcessingItemsBuilderContext(context); - context.putUserData(BUILDER_CONTEXT_KEY, builderContext); - ArtifactPackagingProcessingItem[] allProcessingItems = collectItems(builderContext, project); - - if (LOG.isDebugEnabled()) { - int num = Math.min(5000, allProcessingItems.length); - LOG.debug("All files (" + num + " of " + allProcessingItems.length + "):"); - for (int i = 0; i < num; i++) { - LOG.debug(allProcessingItems[i].getFile().getPath()); - } - } - - try { - final FileProcessingCompilerStateCache cache = - CompilerCacheManager.getInstance(project).getFileProcessingCompilerCache(IncrementalArtifactsCompiler.this); - for (ArtifactPackagingProcessingItem item : allProcessingItems) { - item.init(cache); - } - } - catch (IOException e) { - context.requestRebuildNextTime(e.getMessage()); - context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), null, -1, -1); - result.setResult(ProcessingItem.EMPTY_ARRAY); - LOG.info(e); - return; - } - - boolean hasFilesToDelete = collectFilesToDelete(context, builderContext.getProcessingItems()); - if (hasFilesToDelete) { - MockProcessingItem mockItem = new MockProcessingItem(new LightVirtualFile("239239293")); - result.setResult(ArrayUtil.append(allProcessingItems, mockItem, ProcessingItem.class)); - } - else { - result.setResult(allProcessingItems); - } - } - }.execute().getResultObject(); - } - - private static void collectItems(@NotNull ArtifactsProcessingItemsBuilderContext builderContext, - @NotNull Artifact artifact, - @NotNull String outputPath, - final Project project, boolean enable) { - final CompositePackagingElement rootElement = artifact.getRootElement(); - final VirtualFile outputFile = LocalFileSystem.getInstance().findFileByPath(outputPath); - final CopyToDirectoryInstructionCreator instructionCreator = - new CopyToDirectoryInstructionCreator(builderContext, outputPath, outputFile); - final PackagingElementResolvingContext resolvingContext = ArtifactManager.getInstance(project).getResolvingContext(); - builderContext.setCollectingEnabledItems(enable); - rootElement.computeIncrementalCompilerInstructions(instructionCreator, resolvingContext, builderContext, artifact.getArtifactType()); - } - - public ProcessingItem[] process(final CompileContext context, final ProcessingItem[] items) { - final Set deletedJars = deleteOutdatedFiles(context); - - final List processedItems = new ArrayList(); - final Set writtenPaths = createPathsHashSet(); - final Ref built = Ref.create(false); - CompilerUtil.runInContext(context, "Copying files", new ThrowableRunnable() { - public void run() throws RuntimeException { - built.set(doBuild(context, items, processedItems, writtenPaths, deletedJars)); - } - }); - if (!built.get()) { - return ProcessingItem.EMPTY_ARRAY; - } - - context.getProgressIndicator().setText(CompilerBundle.message("packaging.compiler.message.updating.caches")); - context.getProgressIndicator().setText2(""); - refreshOutputFiles(writtenPaths); - new ReadAction() { - protected void run(final Result result) { - processDestinations(processedItems); - } - }.execute(); - removeInvalidItems(processedItems); - updateOutputCache(context.getProject(), processedItems); - context.putUserData(WRITTEN_PATHS_KEY, writtenPaths); - return processedItems.toArray(new ProcessingItem[processedItems.size()]); - } - - private static boolean doBuild(final CompileContext context, - final ProcessingItem[] items, - final List processedItems, - final Set writtenPaths, - final Set deletedJars) { - final boolean testMode = ApplicationManager.getApplication().isUnitTestMode(); - - if (LOG.isDebugEnabled()) { - int num = Math.min(200, items.length); - LOG.debug("Files to process (" + num + " of " + items.length + "):"); - for (int i = 0; i < num; i++) { - LOG.debug(items[i].getFile().getPath()); - } - } - final DeploymentUtil deploymentUtil = DeploymentUtil.getInstance(); - final FileFilter fileFilter = new IgnoredFileFilter(); - final ArtifactsProcessingItemsBuilderContext builderContext = context.getUserData(BUILDER_CONTEXT_KEY); - final Set changedJars = new THashSet(); - for (String deletedJar : deletedJars) { - ContainerUtil.addIfNotNull(builderContext.getJarInfo(deletedJar), changedJars); - } - - try { - onBuildStartedOrFinished(builderContext, false); - if (context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { - return false; - } - - int i = 0; - for (final ProcessingItem item0 : items) { - if (item0 instanceof MockProcessingItem) continue; - final ArtifactPackagingProcessingItem item = (ArtifactPackagingProcessingItem)item0; - context.getProgressIndicator().checkCanceled(); - - final Ref exception = Ref.create(null); - new ReadAction() { - protected void run(final Result result) { - final File fromFile = VfsUtil.virtualToIoFile(item.getFile()); - for (DestinationInfo destination : item.getEnabledDestinations()) { - if (destination instanceof ExplodedDestinationInfo) { - final ExplodedDestinationInfo explodedDestination = (ExplodedDestinationInfo)destination; - File toFile = new File(FileUtil.toSystemDependentName(explodedDestination.getOutputPath())); - if (fromFile.exists()) { - try { - deploymentUtil.copyFile(fromFile, toFile, context, writtenPaths, fileFilter); - } - catch (IOException e) { - exception.set(e); - return; - } - } - } - else { - changedJars.add(((JarDestinationInfo)destination).getJarInfo()); - } - } - } - }.execute(); - if (exception.get() != null) { - throw exception.get(); - } - - context.getProgressIndicator().setFraction(++i * 1.0 / items.length); - processedItems.add(item); - if (testMode) { - CompilerManagerImpl.addRecompiledPath(FileUtil.toSystemDependentName(item.getFile().getPath())); - } - } - - JarsBuilder builder = new JarsBuilder(changedJars, fileFilter, context); - final boolean processed = builder.buildJars(writtenPaths); - if (!processed) { - return false; - } - - Set recompiledSources = new HashSet(); - for (JarInfo info : builder.getJarsToBuild()) { - for (Pair pair : info.getPackedFiles()) { - recompiledSources.add(pair.getSecond()); - } - } - for (ArtifactPackagingProcessingItem processedItem : processedItems) { - recompiledSources.remove(processedItem.getFile()); - } - for (VirtualFile source : recompiledSources) { - ArtifactPackagingProcessingItem item = builderContext.getItemBySource(source); - LOG.assertTrue(item != null, source); - processedItems.add(item); - if (testMode) { - CompilerManagerImpl.addRecompiledPath(FileUtil.toSystemDependentName(item.getFile().getPath())); - } - } - - onBuildStartedOrFinished(builderContext, true); - } - catch (ProcessCanceledException e) { - throw e; - } - catch (Exception e) { - LOG.info(e); - context.addMessage(CompilerMessageCategory.ERROR, e.getLocalizedMessage(), null, -1, -1); - return false; - } - return true; - } - - public static Set getAffectedArtifacts(final CompileContext compileContext) { - return compileContext.getUserData(AFFECTED_ARTIFACTS); - } - - @Nullable - public static Set getWrittenPaths(@NotNull CompileContext context) { - return context.getUserData(WRITTEN_PATHS_KEY); - } - - @NotNull - public String getDescription() { - return "Artifacts Packaging Compiler"; - } - - @NotNull - private PackagingCompilerCache getOutputItemsCache(final Project project) { - if (myOutputItemsCache == null) { - myOutputItemsCache = new PackagingCompilerCache( - CompilerPaths.getCompilerSystemDirectory(project).getPath() + File.separator + "incremental_artifacts_timestamp.dat"); - } - return myOutputItemsCache; - } - - public void processOutdatedItem(final CompileContext context, final String url, @Nullable final ValidityState state) { - } - - private boolean collectFilesToDelete(final CompileContext context, final ArtifactPackagingProcessingItem[] allProcessingItems) { - List filesToDelete = new ArrayList(); - Set outputPaths = createPathsHashSet(); - for (ArtifactPackagingProcessingItem item : allProcessingItems) { - for (Pair destinationInfo : item.getDestinations()) { - String outputPath = getOutputPathWithJarSeparator(destinationInfo.getFirst()); - outputPaths.add(outputPath); - } - } - - final Iterator pathIterator = getOutputItemsCache(context.getProject()).getUrlsIterator(); - while (pathIterator.hasNext()) { - String path = pathIterator.next(); - if (!outputPaths.contains(path)) { - filesToDelete.add(path); - } - } - - if (LOG.isDebugEnabled()) { - LOG.debug("Files to delete (" + filesToDelete.size() + "):"); - for (String path : filesToDelete) { - LOG.debug(path); - } - } - - if (filesToDelete.isEmpty()) { - return false; - } - context.putUserData(FILES_TO_DELETE_KEY, filesToDelete); - return true; - } - - private static String getOutputPathWithJarSeparator(DestinationInfo destinationInfo) { - String outputPath = destinationInfo.getOutputFilePath(); - if (destinationInfo instanceof JarDestinationInfo) { - final String fullOutputPath = destinationInfo.getOutputPath(); - final String fileOutputPath = destinationInfo.getOutputFilePath(); - if (fullOutputPath.startsWith(fileOutputPath)) { - outputPath += JarFileSystem.JAR_SEPARATOR + DeploymentUtil.trimForwardSlashes(fullOutputPath.substring(fileOutputPath.length())); - } - } - return outputPath; - } - - private static void onBuildStartedOrFinished(ArtifactsProcessingItemsBuilderContext context, final boolean finished) throws Exception { - final CompileContext compileContext = context.getCompileContext(); - final Set artifacts = getAffectedArtifacts(compileContext); - for (Artifact artifact : artifacts) { - for (ArtifactPropertiesProvider provider : artifact.getPropertiesProviders()) { - final ArtifactProperties properties = artifact.getProperties(provider); - if (finished) { - properties.onBuildFinished(artifact, compileContext); - } - else { - properties.onBuildStarted(artifact, compileContext); - } - } - } - } - - private static THashSet createPathsHashSet() { - return SystemInfo.isFileSystemCaseSensitive - ? new THashSet() - : new THashSet(CaseInsensitiveStringHashingStrategy.INSTANCE); - } - - private static void removeInvalidItems(List processedItems) { - Set files = new THashSet(processedItems.size()); - for (ArtifactPackagingProcessingItem item : processedItems) { - files.add(item.getFile()); - } - RefreshQueue.getInstance().refresh(false, false, null, VfsUtil.toVirtualFileArray(files)); - - final Iterator iterator = processedItems.iterator(); - while (iterator.hasNext()) { - ArtifactPackagingProcessingItem item = iterator.next(); - final VirtualFile file = item.getFile(); - if (!file.isValid()) { - iterator.remove(); - } - } - } - - private static void processDestinations(final List items) { - for (ArtifactPackagingProcessingItem item : items) { - item.setProcessed(); - } - } - - private Set deleteOutdatedFiles(final CompileContext context) { - context.getProgressIndicator().setText(CompilerBundle.message("packaging.compiler.message.deleting.outdated.files")); - final List filesToDelete = context.getUserData(FILES_TO_DELETE_KEY); - final Set deletedJars; - if (filesToDelete != null) { - deletedJars = deleteFiles(filesToDelete, context); - } - else { - deletedJars = Collections.emptySet(); - } - context.getProgressIndicator().checkCanceled(); - return deletedJars; - } - - private Set deleteFiles(final List paths, CompileContext context) { - final Set artifactsToBuild = getAffectedArtifacts(context); - - final boolean testMode = ApplicationManager.getApplication().isUnitTestMode(); - final THashSet deletedJars = new THashSet(); - final THashSet notDeletedJars = new THashSet(); - if (LOG.isDebugEnabled()) { - LOG.debug("Deleting outdated files..."); - } - - int notDeletedFilesCount = 0; - final Artifact[] allArtifacts = ArtifactManager.getInstance(context.getProject()).getArtifacts(); - List filesToRefresh = new ArrayList(); - for (String fullPath : paths) { - boolean isUnderOutput = false; - boolean isInArtifactsToBuild = false; - for (Artifact artifact : allArtifacts) { - final String path = artifact.getOutputPath(); - if (!StringUtil.isEmpty(path) && FileUtil.startsWith(fullPath, path)) { - isUnderOutput = true; - if (artifactsToBuild.contains(artifact)) { - isInArtifactsToBuild = true; - break; - } - } - } - if (isUnderOutput && !isInArtifactsToBuild) continue; - - int end = fullPath.indexOf(JarFileSystem.JAR_SEPARATOR); - boolean isJar = end != -1; - String filePath = isJar ? fullPath.substring(0, end) : fullPath; - boolean deleted = false; - if (isJar) { - if (notDeletedJars.contains(filePath)) { - continue; - } - deleted = deletedJars.contains(filePath); - } - - File file = new File(FileUtil.toSystemDependentName(filePath)); - if (!deleted) { - filesToRefresh.add(file); - deleted = FileUtil.delete(file); - } - - if (deleted) { - if (isJar) { - deletedJars.add(filePath); - } - if (testMode) { - CompilerManagerImpl.addDeletedPath(file.getAbsolutePath()); - } - getOutputItemsCache(context.getProject()).remove(fullPath); - } - else { - if (isJar) { - notDeletedJars.add(filePath); - } - if (notDeletedFilesCount++ > 50) { - context.addMessage(CompilerMessageCategory.WARNING, "Deletion of outdated files stopped because too many files cannot be deleted", null, -1, -1); - break; - } - context.addMessage(CompilerMessageCategory.WARNING, "Cannot delete file '" + filePath + "'", null, -1, -1); - if (LOG.isDebugEnabled()) { - LOG.debug("Cannot delete file " + file); - } - } - } - - CompilerUtil.refreshIOFiles(filesToRefresh); - return deletedJars; - } - - private void updateOutputCache(final Project project, final List processedItems) { - for (ArtifactPackagingProcessingItem processedItem : processedItems) { - for (DestinationInfo destinationInfo : processedItem.getEnabledDestinations()) { - final VirtualFile virtualFile = destinationInfo.getOutputFile(); - if (virtualFile != null) { - final String path = getOutputPathWithJarSeparator(destinationInfo); - if (LOG.isDebugEnabled()) { - LOG.debug("update output cache: file " + path); - } - getOutputItemsCache(project).update(path, virtualFile.getTimeStamp()); - } - } - } - saveCacheIfDirty(project); - } - - private static void refreshOutputFiles(Set writtenPaths) { - final ArrayList filesToRefresh = new ArrayList(); - for (String path : writtenPaths) { - filesToRefresh.add(new File(path)); - } - CompilerUtil.refreshIOFiles(filesToRefresh); - } - - private void saveCacheIfDirty(final Project project) { - if (getOutputItemsCache(project).isDirty()) { - getOutputItemsCache(project).save(); - } - } - - public ValidityState createValidityState(final DataInput is) throws IOException { - return new ArtifactPackagingItemValidityState(is); - } - - public boolean validateConfiguration(final CompileScope scope) { - return true; - } - - private static class MockProcessingItem implements ProcessingItem { - private final VirtualFile myFile; - - public MockProcessingItem(final VirtualFile file) { - myFile = file; - } - - @NotNull - public VirtualFile getFile() { - return myFile; - } - - @Nullable - public ValidityState getValidityState() { - return null; - } - } -} diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/PackIntoArchiveInstructionCreator.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/PackIntoArchiveInstructionCreator.java index a703503175b2..cfeb4b1646d9 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/PackIntoArchiveInstructionCreator.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/PackIntoArchiveInstructionCreator.java @@ -30,8 +30,8 @@ public class PackIntoArchiveInstructionCreator extends IncrementalCompilerInstru private final JarInfo myJarInfo; private final String myPathInJar; - public PackIntoArchiveInstructionCreator(ArtifactsProcessingItemsBuilderContext context, JarInfo jarInfo, String pathInJar, - DestinationInfo jarDestination) { + public PackIntoArchiveInstructionCreator(ArtifactsProcessingItemsBuilderContext context, JarInfo jarInfo, + String pathInJar, DestinationInfo jarDestination) { super(context); myJarInfo = jarInfo; myPathInJar = pathInJar; @@ -55,7 +55,8 @@ public class PackIntoArchiveInstructionCreator extends IncrementalCompilerInstru public IncrementalCompilerInstructionCreator archive(@NotNull String archiveFileName) { final JarInfo jarInfo = new JarInfo(); - if (!myContext.registerJarFile(jarInfo, myJarDestination.getOutputPath() + "/" + archiveFileName)) { + final String outputPath = myJarDestination.getOutputPath() + "/" + archiveFileName; + if (!myContext.registerJarFile(jarInfo, outputPath)) { return new SkipAllInstructionCreator(myContext); } final JarDestinationInfo destination = new JarDestinationInfo(childPathInJar(archiveFileName), myJarInfo, myJarDestination); 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 3d18372af496..3b0e586020f2 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 @@ -35,7 +35,7 @@ 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.IncrementalArtifactsCompiler; +import com.intellij.packaging.impl.compiler.ArtifactsCompiler; import com.intellij.util.concurrency.Semaphore; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; @@ -148,7 +148,7 @@ public class BuildArtifactsBeforeRunTaskProvider extends BeforeRunTaskProvider + From f08e3105c0110040590d1b9cdc3c019b1297d4af Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Tue, 27 Jul 2010 22:27:07 +0400 Subject: [PATCH 17/17] IDEA-54306: Preference "when empty changelist becomes inactive" is not persisted --- .../com/intellij/openapi/vcs/VcsConfiguration.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java index 59dc044c95c5..5b9fe2914bc0 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java @@ -51,6 +51,7 @@ public final class VcsConfiguration implements PersistentStateComponent @NonNls private static final String VALUE_ATTR = "value"; @NonNls private static final String CONFIRM_MOVE_TO_FAILED_COMMIT_ELEMENT = "confirmMoveToFailedCommit"; + @NonNls private static final String CONFIRM_REMOVE_EMPTY_CHANGELIST_ELEMENT = "confirmRemoveEmptyChangelist"; private Project myProject; public boolean OFFER_MOVE_TO_ANOTHER_CHANGELIST_ON_PARTIAL_COMMIT = true; @@ -164,10 +165,14 @@ public final class VcsConfiguration implements PersistentStateComponent public void readExternal(Element element) throws InvalidDataException { DefaultJDOMExternalizer.readExternal(this, element); - final Element child = element.getChild(CONFIRM_MOVE_TO_FAILED_COMMIT_ELEMENT); + Element child = element.getChild(CONFIRM_MOVE_TO_FAILED_COMMIT_ELEMENT); if (child != null) { MOVE_TO_FAILED_COMMIT_CHANGELIST = VcsShowConfirmationOption.Value.fromString(child.getAttributeValue(VALUE_ATTR)); } + child = element.getChild(CONFIRM_REMOVE_EMPTY_CHANGELIST_ELEMENT); + if (child != null) { + REMOVE_EMPTY_INACTIVE_CHANGELISTS = VcsShowConfirmationOption.Value.fromString(child.getAttributeValue(VALUE_ATTR)); + } final List messages = element.getChildren(MESSAGE_ELEMENT_NAME); for (final Object message : messages) { saveCommitMessage(((Element)message).getAttributeValue(VALUE_ATTR)); @@ -188,6 +193,11 @@ public final class VcsConfiguration implements PersistentStateComponent confirmChild.setAttribute(VALUE_ATTR, MOVE_TO_FAILED_COMMIT_CHANGELIST.toString()); element.addContent(confirmChild); } + if (REMOVE_EMPTY_INACTIVE_CHANGELISTS != VcsShowConfirmationOption.Value.SHOW_CONFIRMATION) { + Element confirmChild = new Element(CONFIRM_REMOVE_EMPTY_CHANGELIST_ELEMENT); + confirmChild.setAttribute(VALUE_ATTR, REMOVE_EMPTY_INACTIVE_CHANGELISTS.toString()); + element.addContent(confirmChild); + } for (String message : myLastCommitMessages) { final Element messageElement = new Element(MESSAGE_ELEMENT_NAME); messageElement.setAttribute(VALUE_ATTR, message);