From 3c60d0de93944eba9add3da0ef26e1a3905aa834 Mon Sep 17 00:00:00 2001 From: Zalim Bashorov Date: Mon, 8 Sep 2014 13:43:45 +0400 Subject: [PATCH] Parser: added the support file annotations. --- .../src/org/jetbrains/jet/JetNodeTypes.java | 1 + .../jet/lang/parsing/AbstractJetParsing.java | 11 +- .../lang/parsing/JetExpressionParsing.java | 13 +- .../jet/lang/parsing/JetParsing.java | 143 ++++++++++++++---- .../org/jetbrains/jet/lang/psi/JetFile.java | 38 ++++- .../jet/lang/psi/JetFileAnnotationList.java | 57 +++++++ .../jetbrains/jet/lang/psi/JetVisitor.java | 4 + .../stubs/elements/JetFileElementType.java | 2 +- .../stubs/elements/JetStubElementTypes.java | 3 + .../org/jetbrains/jet/lexer/JetTokens.java | 3 +- .../onFile/fileAnnotationInWrongPlace.kt | 13 ++ .../onFile/fileAnnotationInWrongPlace.txt | 93 ++++++++++++ .../annotation/onFile/manyAnnotationBlocks.kt | 3 + .../onFile/manyAnnotationBlocks.txt | 39 +++++ .../onFile/manyInOneAnnotationBlock.kt | 3 + .../onFile/manyInOneAnnotationBlock.txt | 34 +++++ .../onFile/nonFIleAnnotationBeforePackage.kt | 8 + .../onFile/nonFIleAnnotationBeforePackage.txt | 88 +++++++++++ .../testData/psi/annotation/onFile/single.kt | 2 + .../testData/psi/annotation/onFile/single.txt | 20 +++ ...houtFileAnnotationAndPackageDeclaration.kt | 3 + ...outFileAnnotationAndPackageDeclaration.txt | 42 +++++ .../psi/annotation/onFile/withoutPackage.kt | 4 + .../psi/annotation/onFile/withoutPackage.txt | 60 ++++++++ .../withoutPackageWithSimpleAnnotation.kt | 4 + .../withoutPackageWithSimpleAnnotation.txt | 57 +++++++ .../psi/script/manyAnnotationsOnFile.kts | 3 + .../psi/script/manyAnnotationsOnFile.txt | 42 +++++ .../jet/parsing/JetParsingTestGenerated.java | 77 +++++++++- 29 files changed, 824 insertions(+), 46 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFileAnnotationList.java create mode 100644 compiler/testData/psi/annotation/onFile/fileAnnotationInWrongPlace.kt create mode 100644 compiler/testData/psi/annotation/onFile/fileAnnotationInWrongPlace.txt create mode 100644 compiler/testData/psi/annotation/onFile/manyAnnotationBlocks.kt create mode 100644 compiler/testData/psi/annotation/onFile/manyAnnotationBlocks.txt create mode 100644 compiler/testData/psi/annotation/onFile/manyInOneAnnotationBlock.kt create mode 100644 compiler/testData/psi/annotation/onFile/manyInOneAnnotationBlock.txt create mode 100644 compiler/testData/psi/annotation/onFile/nonFIleAnnotationBeforePackage.kt create mode 100644 compiler/testData/psi/annotation/onFile/nonFIleAnnotationBeforePackage.txt create mode 100644 compiler/testData/psi/annotation/onFile/single.kt create mode 100644 compiler/testData/psi/annotation/onFile/single.txt create mode 100644 compiler/testData/psi/annotation/onFile/withoutFileAnnotationAndPackageDeclaration.kt create mode 100644 compiler/testData/psi/annotation/onFile/withoutFileAnnotationAndPackageDeclaration.txt create mode 100644 compiler/testData/psi/annotation/onFile/withoutPackage.kt create mode 100644 compiler/testData/psi/annotation/onFile/withoutPackage.txt create mode 100644 compiler/testData/psi/annotation/onFile/withoutPackageWithSimpleAnnotation.kt create mode 100644 compiler/testData/psi/annotation/onFile/withoutPackageWithSimpleAnnotation.txt create mode 100644 compiler/testData/psi/script/manyAnnotationsOnFile.kts create mode 100644 compiler/testData/psi/script/manyAnnotationsOnFile.txt diff --git a/compiler/frontend/src/org/jetbrains/jet/JetNodeTypes.java b/compiler/frontend/src/org/jetbrains/jet/JetNodeTypes.java index 493ede61a64..7c882c60d8d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/JetNodeTypes.java +++ b/compiler/frontend/src/org/jetbrains/jet/JetNodeTypes.java @@ -52,6 +52,7 @@ public interface JetNodeTypes { IElementType CLASS_BODY = JetStubElementTypes.CLASS_BODY; IElementType IMPORT_LIST = JetStubElementTypes.IMPORT_LIST; + IElementType FILE_ANNOTATION_LIST = JetStubElementTypes.FILE_ANNOTATION_LIST; IElementType IMPORT_DIRECTIVE = JetStubElementTypes.IMPORT_DIRECTIVE; IElementType MODIFIER_LIST = JetStubElementTypes.MODIFIER_LIST; IElementType PRIMARY_CONSTRUCTOR_MODIFIER_LIST = JetStubElementTypes.PRIMARY_CONSTRUCTOR_MODIFIER_LIST; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/AbstractJetParsing.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/AbstractJetParsing.java index 3d70aee01ba..1d8862f7bd3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/AbstractJetParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/AbstractJetParsing.java @@ -19,14 +19,13 @@ package org.jetbrains.jet.lang.parsing; import com.intellij.lang.PsiBuilder; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; +import com.intellij.util.containers.Stack; import org.jetbrains.jet.lexer.JetKeywordToken; import org.jetbrains.jet.lexer.JetToken; import org.jetbrains.jet.lexer.JetTokens; import java.util.HashMap; import java.util.Map; -import com.intellij.util.containers.Stack; - import static org.jetbrains.jet.lexer.JetTokens.*; @@ -109,8 +108,14 @@ import static org.jetbrains.jet.lexer.JetTokens.*; } protected boolean errorAndAdvance(String message) { + return errorAndAdvance(message, 1); + } + + protected boolean errorAndAdvance(String message, int advanceTokenCount) { PsiBuilder.Marker err = mark(); - advance(); // erroneous token + for (int i = 0; i < advanceTokenCount; i++) { + advance(); // erroneous token + } err.error(message); return false; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java index f1aa41bc7b0..8408026a70c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java @@ -30,6 +30,8 @@ import java.util.HashSet; import java.util.Set; import static org.jetbrains.jet.JetNodeTypes.*; +import static org.jetbrains.jet.lang.parsing.JetParsing.AnnotationParsingMode.REGULAR_ANNOTATIONS_ALLOW_SHORTS; +import static org.jetbrains.jet.lang.parsing.JetParsing.AnnotationParsingMode.REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS; import static org.jetbrains.jet.lexer.JetTokens.*; public class JetExpressionParsing extends AbstractJetParsing { @@ -339,13 +341,10 @@ public class JetExpressionParsing extends AbstractJetParsing { if (at(LBRACKET)) { if (!parseLocalDeclaration()) { PsiBuilder.Marker expression = mark(); - myJetParsing.parseAnnotations(false); + myJetParsing.parseAnnotations(REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS); parsePrefixExpression(); expression.done(ANNOTATED_EXPRESSION); } - else { - return; - } } else { myBuilder.disableJoiningComplexTokens(); @@ -770,7 +769,7 @@ public class JetExpressionParsing extends AbstractJetParsing { int valPos = matchTokenStreamPredicate(new FirstBefore(new At(VAL_KEYWORD), new AtSet(RPAR, LBRACE, RBRACE, SEMICOLON, EQ))); if (valPos >= 0) { PsiBuilder.Marker property = mark(); - myJetParsing.parseModifierList(MODIFIER_LIST, true); + myJetParsing.parseModifierList(MODIFIER_LIST, REGULAR_ANNOTATIONS_ALLOW_SHORTS); myJetParsing.parseProperty(true); property.done(PROPERTY); } @@ -954,7 +953,7 @@ public class JetExpressionParsing extends AbstractJetParsing { private boolean parseLocalDeclaration() { PsiBuilder.Marker decl = mark(); JetParsing.TokenDetector enumDetector = new JetParsing.TokenDetector(ENUM_KEYWORD); - myJetParsing.parseModifierList(MODIFIER_LIST, enumDetector, false); + myJetParsing.parseModifierList(MODIFIER_LIST, enumDetector, REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS); IElementType declType = parseLocalDeclarationRest(enumDetector.isDetected()); @@ -1200,7 +1199,7 @@ public class JetExpressionParsing extends AbstractJetParsing { PsiBuilder.Marker parameter = mark(); int parameterNamePos = matchTokenStreamPredicate(new LastBefore(new At(IDENTIFIER), new AtSet(COMMA, RPAR, COLON, ARROW))); - createTruncatedBuilder(parameterNamePos).parseModifierList(MODIFIER_LIST, false); + createTruncatedBuilder(parameterNamePos).parseModifierList(MODIFIER_LIST, REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS); expect(IDENTIFIER, "Expecting parameter declaration"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java index 1644e65d41a..4eb10f5cd02 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.lang.parsing; import com.intellij.lang.PsiBuilder; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; @@ -28,9 +29,12 @@ import java.util.HashMap; import java.util.Map; import static org.jetbrains.jet.JetNodeTypes.*; +import static org.jetbrains.jet.lang.parsing.JetParsing.AnnotationParsingMode.*; import static org.jetbrains.jet.lexer.JetTokens.*; public class JetParsing extends AbstractJetParsing { + private static final Logger LOG = Logger.getInstance(JetParsing.class); + // TODO: token sets to constants, including derived methods public static final Map MODIFIER_KEYWORD_MAP = new HashMap(); static { @@ -167,18 +171,25 @@ public class JetParsing extends AbstractJetParsing { /* *preamble - * : packageDirective? import* + * : fileAnnotationList? packageDirective? import* * ; */ private void parsePreamble() { + PsiBuilder.Marker firstEntry = mark(); + + /* + * fileAnnotationList + * : fileAnnotations* + */ + parseFileAnnotationList(FILE_ANNOTATIONS_BEFORE_PACKAGE); + /* * packageDirective * : modifiers "package" SimpleName{"."} SEMI? * ; */ PsiBuilder.Marker packageDirective = mark(); - PsiBuilder.Marker firstEntry = mark(); - parseModifierList(MODIFIER_LIST, true); + parseModifierList(MODIFIER_LIST, REGULAR_ANNOTATIONS_ALLOW_SHORTS); if (at(PACKAGE_KEYWORD)) { advance(); // PACKAGE_KEYWORD @@ -188,7 +199,11 @@ public class JetParsing extends AbstractJetParsing { if (at(LBRACE)) { // Because it's blocked package and it will be parsed as one of top level objects + packageDirective.drop(); firstEntry.rollbackTo(); + + parseFileAnnotationList(/*reportErrorForNonFileAnnotations =*/ false); + packageDirective = mark(); packageDirective.done(PACKAGE_DIRECTIVE); return; } @@ -198,7 +213,12 @@ public class JetParsing extends AbstractJetParsing { consumeIf(SEMICOLON); } else { + // When package directive is omitted we should not report error on non-file annotations at the beginning of the file. + // So, we rollback the parsing position and reparse file annotation list without report error on non-file annotations. firstEntry.rollbackTo(); + + parseFileAnnotationList(FILE_ANNOTATIONS_WHEN_PACKAGE_OMITTED); + packageDirective = mark(); } packageDirective.done(PACKAGE_DIRECTIVE); @@ -342,7 +362,7 @@ public class JetParsing extends AbstractJetParsing { PsiBuilder.Marker decl = mark(); TokenDetector detector = new TokenDetector(ENUM_KEYWORD); - parseModifierList(MODIFIER_LIST, detector, true); + parseModifierList(MODIFIER_LIST, detector, REGULAR_ANNOTATIONS_ALLOW_SHORTS); IElementType keywordToken = tt(); IElementType declType = null; @@ -379,8 +399,11 @@ public class JetParsing extends AbstractJetParsing { /* * (modifier | attribute)* */ - boolean parseModifierList(IElementType nodeType, boolean allowShortAnnotations) { - return parseModifierList(nodeType, null, allowShortAnnotations); + boolean parseModifierList( + @NotNull IElementType nodeType, + @NotNull AnnotationParsingMode annotationParsingMode + ) { + return parseModifierList(nodeType, null, annotationParsingMode); } /** @@ -388,7 +411,11 @@ public class JetParsing extends AbstractJetParsing { * * Feeds modifiers (not attributes) into the passed consumer, if it is not null */ - boolean parseModifierList(IElementType nodeType, @Nullable Consumer tokenConsumer, boolean allowShortAnnotations) { + boolean parseModifierList( + @NotNull IElementType nodeType, + @Nullable Consumer tokenConsumer, + @NotNull AnnotationParsingMode annotationParsingMode + ) { PsiBuilder.Marker list = mark(); boolean empty = true; while (!eof()) { @@ -396,8 +423,8 @@ public class JetParsing extends AbstractJetParsing { if (tokenConsumer != null) tokenConsumer.consume(tt()); advance(); // MODIFIER } - else if (at(LBRACKET) || (allowShortAnnotations && at(IDENTIFIER))) { - parseAnnotation(allowShortAnnotations); + else if (at(LBRACKET) || (annotationParsingMode.allowShortAnnotations && at(IDENTIFIER))) { + parseAnnotation(annotationParsingMode); } else { break; @@ -414,29 +441,68 @@ public class JetParsing extends AbstractJetParsing { } /* - * annotations - * : annotation* + * fileAnnotationList + * : ("[" "file:" annotationEntry+ "]")* * ; */ - void parseAnnotations(boolean allowShortAnnotations) { - while (true) { - if (!(parseAnnotation(allowShortAnnotations))) break; + private void parseFileAnnotationList(AnnotationParsingMode mode) { + if (!mode.isFileAnnotationParsingMode) { + LOG.error("expected file annotation parsing mode, but:" + mode); + } + + PsiBuilder.Marker fileAnnotationsList = mark(); + + if (parseAnnotations(mode)) { + fileAnnotationsList.done(FILE_ANNOTATION_LIST); + } + else { + fileAnnotationsList.drop(); } } + /* + * annotations + * : annotation* + * ; + */ + boolean parseAnnotations(AnnotationParsingMode mode) { + if (!parseAnnotation(mode)) return false; + + while (parseAnnotation(mode)) { + // do nothing + } + + return true; + } + /* * annotation - * : "[" annotationEntry+ "]" + * : "[" ("file" ":")? annotationEntry+ "]" * : annotationEntry * ; */ - private boolean parseAnnotation(boolean allowShortAnnotations) { + private boolean parseAnnotation(AnnotationParsingMode mode) { if (at(LBRACKET)) { PsiBuilder.Marker annotation = mark(); myBuilder.disableNewlines(); advance(); // LBRACKET + if (mode.isFileAnnotationParsingMode) { + if (mode == FILE_ANNOTATIONS_WHEN_PACKAGE_OMITTED && !(at(FILE_KEYWORD) && lookahead(1) == COLON)) { + annotation.rollbackTo(); + myBuilder.restoreNewlinesState(); + return false; + } + + String message = "Expecting \"" + FILE_KEYWORD.getValue() + COLON.getValue() + "\" prefix for file annotations"; + expect(FILE_KEYWORD, message); + expect(COLON, message, TokenSet.create(IDENTIFIER, RBRACKET)); + } + else if (at(FILE_KEYWORD) && lookahead(1) == COLON) { + errorAndAdvance("File annotations are only allowed before package declaration", 2); + } + if (!at(IDENTIFIER)) { error("Expecting a list of attributes"); } @@ -460,10 +526,11 @@ public class JetParsing extends AbstractJetParsing { annotation.done(ANNOTATION); return true; } - else if (allowShortAnnotations && at(IDENTIFIER)) { + else if (mode.allowShortAnnotations && at(IDENTIFIER)) { parseAnnotationEntry(); return true; } + return false; } @@ -509,7 +576,7 @@ public class JetParsing extends AbstractJetParsing { boolean typeParametersDeclared = parseTypeParameterList(TYPE_PARAMETER_GT_RECOVERY_SET); PsiBuilder.Marker beforeConstructorModifiers = mark(); - boolean hasConstructorModifiers = parseModifierList(PRIMARY_CONSTRUCTOR_MODIFIER_LIST, false); + boolean hasConstructorModifiers = parseModifierList(PRIMARY_CONSTRUCTOR_MODIFIER_LIST, REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS); // Some modifiers found, but no parentheses following: class has already ended, and we are looking at something else if (hasConstructorModifiers && !atSet(LPAR, LBRACE, COLON) ) { @@ -569,7 +636,7 @@ public class JetParsing extends AbstractJetParsing { TokenSet constructorNameFollow = TokenSet.create(SEMICOLON, COLON, LPAR, LT, LBRACE); int lastId = findLastBefore(ENUM_MEMBER_FIRST, constructorNameFollow, false); TokenDetector enumDetector = new TokenDetector(ENUM_KEYWORD); - createTruncatedBuilder(lastId).parseModifierList(MODIFIER_LIST, enumDetector, false); + createTruncatedBuilder(lastId).parseModifierList(MODIFIER_LIST, enumDetector, REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS); IElementType type; if (at(IDENTIFIER)) { @@ -666,7 +733,7 @@ public class JetParsing extends AbstractJetParsing { PsiBuilder.Marker decl = mark(); TokenDetector enumDetector = new TokenDetector(ENUM_KEYWORD); - parseModifierList(MODIFIER_LIST, enumDetector, true); + parseModifierList(MODIFIER_LIST, enumDetector, REGULAR_ANNOTATIONS_ALLOW_SHORTS); IElementType declType = parseMemberDeclarationRest(enumDetector.isDetected()); @@ -777,7 +844,7 @@ public class JetParsing extends AbstractJetParsing { */ private void parseInitializer() { PsiBuilder.Marker initializer = mark(); - parseAnnotations(false); + parseAnnotations(REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS); IElementType type; if (at(THIS_KEYWORD)) { @@ -1020,7 +1087,7 @@ public class JetParsing extends AbstractJetParsing { private boolean parsePropertyGetterOrSetter() { PsiBuilder.Marker getterOrSetter = mark(); - parseModifierList(MODIFIER_LIST, false); + parseModifierList(MODIFIER_LIST, REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS); if (!at(GET_KEYWORD) && !at(SET_KEYWORD)) { getterOrSetter.rollbackTo(); @@ -1150,7 +1217,7 @@ public class JetParsing extends AbstractJetParsing { */ private void parseReceiverType(String title, TokenSet nameFollow, int lastDot) { if (lastDot == -1) { // There's no explicit receiver type specified - parseAnnotations(false); + parseAnnotations(REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS); } else { createTruncatedBuilder(lastDot).parseTypeRef(); @@ -1249,7 +1316,7 @@ public class JetParsing extends AbstractJetParsing { */ private void parseDelegationSpecifier() { PsiBuilder.Marker delegator = mark(); - parseAnnotations(false); + parseAnnotations(REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS); PsiBuilder.Marker reference = mark(); parseTypeRef(); @@ -1349,7 +1416,7 @@ public class JetParsing extends AbstractJetParsing { private void parseTypeConstraint() { PsiBuilder.Marker constraint = mark(); - parseAnnotations(false); + parseAnnotations(REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS); if (at(CLASS_KEYWORD)) { advance(); // CLASS_KEYWORD @@ -1431,7 +1498,7 @@ public class JetParsing extends AbstractJetParsing { // we don't support this case now // myBuilder.disableJoiningComplexTokens(); PsiBuilder.Marker typeRefMarker = mark(); - parseAnnotations(false); + parseAnnotations(REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS); if (at(IDENTIFIER) || at(PACKAGE_KEYWORD)) { parseUserType(); @@ -1533,7 +1600,8 @@ public class JetParsing extends AbstractJetParsing { PsiBuilder.Marker reference = mark(); while (true) { - if (expect(IDENTIFIER, "Expecting type name", TokenSet.orSet(JetExpressionParsing.EXPRESSION_FIRST, JetExpressionParsing.EXPRESSION_FOLLOW))) { + if (expect(IDENTIFIER, "Expecting type name", + TokenSet.orSet(JetExpressionParsing.EXPRESSION_FIRST, JetExpressionParsing.EXPRESSION_FOLLOW))) { reference.done(REFERENCE_EXPRESSION); } else { @@ -1600,7 +1668,7 @@ public class JetParsing extends AbstractJetParsing { // TokenSet stopAt = TokenSet.create(COMMA, COLON, GT); // parseModifierListWithShortAnnotations(MODIFIER_LIST, lookFor, stopAt); // Currently we do not allow annotations - parseModifierList(MODIFIER_LIST, false); + parseModifierList(MODIFIER_LIST, REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS); if (at(MUL)) { advance(); // MUL @@ -1626,7 +1694,7 @@ public class JetParsing extends AbstractJetParsing { private void parseModifierListWithShortAnnotations(IElementType modifierList, TokenSet lookFor, TokenSet stopAt) { int lastId = findLastBefore(lookFor, stopAt, false); - createTruncatedBuilder(lastId).parseModifierList(modifierList, true); + createTruncatedBuilder(lastId).parseModifierList(modifierList, REGULAR_ANNOTATIONS_ALLOW_SHORTS); } /* @@ -1741,7 +1809,7 @@ public class JetParsing extends AbstractJetParsing { if (isFunctionTypeContents) { if (!tryParseValueParameter()) { PsiBuilder.Marker valueParameter = mark(); - parseModifierList(MODIFIER_LIST, false); // lazy, out, ref + parseModifierList(MODIFIER_LIST, REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS); // lazy, out, ref parseTypeRef(); valueParameter.done(VALUE_PARAMETER); } @@ -1857,4 +1925,19 @@ public class JetParsing extends AbstractJetParsing { return detected; } } + + static enum AnnotationParsingMode { + FILE_ANNOTATIONS_BEFORE_PACKAGE(false, true), + FILE_ANNOTATIONS_WHEN_PACKAGE_OMITTED(false, true), + REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS(false, false), + REGULAR_ANNOTATIONS_ALLOW_SHORTS(true, false); + + boolean allowShortAnnotations; + boolean isFileAnnotationParsingMode; + + AnnotationParsingMode(boolean allowShortAnnotations, boolean onlyFileAnnotations) { + this.allowShortAnnotations = allowShortAnnotations; + this.isFileAnnotationParsingMode = onlyFileAnnotations; + } + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFile.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFile.java index 320dfa7fbe2..08b488efa94 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFile.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFile.java @@ -30,6 +30,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.lang.psi.stubs.PsiJetFileStub; +import org.jetbrains.jet.lang.psi.stubs.elements.JetPlaceHolderStubElementType; import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementTypes; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.plugin.JetFileType; @@ -39,7 +40,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -public class JetFile extends PsiFileBase implements JetDeclarationContainer, JetElement, PsiClassOwner { +public class JetFile extends PsiFileBase implements JetDeclarationContainer, JetAnnotated, JetElement, PsiClassOwner { private final boolean isCompiled; @@ -80,12 +81,25 @@ public class JetFile extends PsiFileBase implements JetDeclarationContainer, Jet @Nullable public JetImportList getImportList() { + return findChildByTypeOrClass(JetStubElementTypes.IMPORT_LIST, JetImportList.class); + } + + @Nullable + public JetFileAnnotationList getFileAnnotationList() { + return findChildByTypeOrClass(JetStubElementTypes.FILE_ANNOTATION_LIST, JetFileAnnotationList.class); + } + + @Nullable + public >> T findChildByTypeOrClass( + @NotNull JetPlaceHolderStubElementType elementType, + @NotNull Class elementClass + ) { PsiJetFileStub stub = getStub(); if (stub != null) { - StubElement importListStub = stub.findChildStubByType(JetStubElementTypes.IMPORT_LIST); + StubElement importListStub = stub.findChildStubByType(elementType); return importListStub != null ? importListStub.getPsi() : null; } - return findChildByClass(JetImportList.class); + return findChildByClass(elementClass); } @NotNull @@ -205,4 +219,22 @@ public class JetFile extends PsiFileBase implements JetDeclarationContainer, Jet public R accept(@NotNull JetVisitor visitor, D data) { return visitor.visitJetFile(this, data); } + + @NotNull + @Override + public List getAnnotations() { + JetFileAnnotationList fileAnnotationList = getFileAnnotationList(); + if (fileAnnotationList == null) return Collections.emptyList(); + + return fileAnnotationList.getAnnotations(); + } + + @NotNull + @Override + public List getAnnotationEntries() { + JetFileAnnotationList fileAnnotationList = getFileAnnotationList(); + if (fileAnnotationList == null) return Collections.emptyList(); + + return fileAnnotationList.getAnnotationEntries(); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFileAnnotationList.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFileAnnotationList.java new file mode 100644 index 00000000000..adc61e1fd46 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFileAnnotationList.java @@ -0,0 +1,57 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.psi; + +import com.intellij.lang.ASTNode; +import kotlin.Function1; +import kotlin.KotlinPackage; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.stubs.PsiJetPlaceHolderStub; +import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementTypes; + +import java.util.List; + +public class JetFileAnnotationList extends JetElementImplStub> { + + public JetFileAnnotationList(@NotNull ASTNode node) { + super(node); + } + + public JetFileAnnotationList(@NotNull PsiJetPlaceHolderStub stub) { + super(stub, JetStubElementTypes.FILE_ANNOTATION_LIST); + } + + @Override + public R accept(@NotNull JetVisitor visitor, D data) { + return visitor.visitFileAnnotationList(this, data); + } + + @NotNull + public List getAnnotations() { + return getStubOrPsiChildrenAsList(JetStubElementTypes.ANNOTATION); + } + + @NotNull + public List getAnnotationEntries() { + return KotlinPackage.flatMap(getAnnotations(), new Function1>() { + @Override + public List invoke(JetAnnotation annotation) { + return annotation.getEntries(); + } + }); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetVisitor.java index 857a93e9c3d..545fe33ed25 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetVisitor.java @@ -74,6 +74,10 @@ public class JetVisitor extends PsiElementVisitor { return visitJetElement(importList, data); } + public R visitFileAnnotationList(@NotNull JetFileAnnotationList fileAnnotationList, D data) { + return visitJetElement(fileAnnotationList, data); + } + public R visitClassBody(@NotNull JetClassBody classBody, D data) { return visitJetElement(classBody, data); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFileElementType.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFileElementType.java index 6addb68814f..80959b656bf 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFileElementType.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFileElementType.java @@ -36,7 +36,7 @@ import org.jetbrains.jet.plugin.JetLanguage; import java.io.IOException; public class JetFileElementType extends IStubFileElementType { - public static final int STUB_VERSION = 29; + public static final int STUB_VERSION = 30; public JetFileElementType() { super("jet.FILE", JetLanguage.INSTANCE); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetStubElementTypes.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetStubElementTypes.java index b9e7e7d4ba2..e45554a20de 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetStubElementTypes.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetStubElementTypes.java @@ -52,6 +52,9 @@ public interface JetStubElementTypes { JetPlaceHolderStubElementType IMPORT_LIST = new JetPlaceHolderStubElementType("IMPORT_LIST", JetImportList.class); + JetPlaceHolderStubElementType FILE_ANNOTATION_LIST = + new JetPlaceHolderStubElementType("FILE_ANNOTATION_LIST", JetFileAnnotationList.class); + JetImportDirectiveElementType IMPORT_DIRECTIVE = new JetImportDirectiveElementType("IMPORT_DIRECTIVE"); JetPlaceHolderStubElementType PACKAGE_DIRECTIVE = diff --git a/compiler/frontend/src/org/jetbrains/jet/lexer/JetTokens.java b/compiler/frontend/src/org/jetbrains/jet/lexer/JetTokens.java index a960ca01afa..2d13a5b70c4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lexer/JetTokens.java +++ b/compiler/frontend/src/org/jetbrains/jet/lexer/JetTokens.java @@ -131,6 +131,7 @@ public interface JetTokens { JetSingleValueToken COMMA = new JetSingleValueToken("COMMA", ","); JetToken EOL_OR_SEMICOLON = new JetToken("EOL_OR_SEMICOLON"); + JetKeywordToken FILE_KEYWORD = JetKeywordToken.softKeyword("file"); JetKeywordToken IMPORT_KEYWORD = JetKeywordToken.softKeyword("import"); JetKeywordToken WHERE_KEYWORD = JetKeywordToken.softKeyword("where"); JetKeywordToken BY_KEYWORD = JetKeywordToken.softKeyword("by"); @@ -163,7 +164,7 @@ public interface JetTokens { NOT_IN, NOT_IS, CAPITALIZED_THIS_KEYWORD, AS_SAFE ); - TokenSet SOFT_KEYWORDS = TokenSet.create(IMPORT_KEYWORD, WHERE_KEYWORD, BY_KEYWORD, GET_KEYWORD, + TokenSet SOFT_KEYWORDS = TokenSet.create(FILE_KEYWORD, IMPORT_KEYWORD, WHERE_KEYWORD, BY_KEYWORD, GET_KEYWORD, SET_KEYWORD, ABSTRACT_KEYWORD, ENUM_KEYWORD, OPEN_KEYWORD, INNER_KEYWORD, ANNOTATION_KEYWORD, OVERRIDE_KEYWORD, PRIVATE_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD, PROTECTED_KEYWORD, CATCH_KEYWORD, FINALLY_KEYWORD, OUT_KEYWORD, FINAL_KEYWORD, VARARG_KEYWORD, REIFIED_KEYWORD diff --git a/compiler/testData/psi/annotation/onFile/fileAnnotationInWrongPlace.kt b/compiler/testData/psi/annotation/onFile/fileAnnotationInWrongPlace.kt new file mode 100644 index 00000000000..33134b6e936 --- /dev/null +++ b/compiler/testData/psi/annotation/onFile/fileAnnotationInWrongPlace.kt @@ -0,0 +1,13 @@ +package bar + +[file: foo] +val prop + +[file:bar baz] +fun func() {} + +[file:baz] +class C + +[file:] +trait T diff --git a/compiler/testData/psi/annotation/onFile/fileAnnotationInWrongPlace.txt b/compiler/testData/psi/annotation/onFile/fileAnnotationInWrongPlace.txt new file mode 100644 index 00000000000..b8bf1232a7d --- /dev/null +++ b/compiler/testData/psi/annotation/onFile/fileAnnotationInWrongPlace.txt @@ -0,0 +1,93 @@ +JetFile: fileAnnotationInWrongPlace.kt + PACKAGE_DIRECTIVE + PsiElement(package)('package') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') + PsiWhiteSpace('\n\n') + PROPERTY + MODIFIER_LIST + ANNOTATION + PsiElement(LBRACKET)('[') + PsiErrorElement:File annotations are only allowed before package declaration + PsiElement(file)('file') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('prop') + PsiWhiteSpace('\n\n') + FUN + MODIFIER_LIST + ANNOTATION + PsiElement(LBRACKET)('[') + PsiErrorElement:File annotations are only allowed before package declaration + PsiElement(file)('file') + PsiElement(COLON)(':') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('baz') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('func') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + CLASS + MODIFIER_LIST + ANNOTATION + PsiElement(LBRACKET)('[') + PsiErrorElement:File annotations are only allowed before package declaration + PsiElement(file)('file') + PsiElement(COLON)(':') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('baz') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('C') + PsiWhiteSpace('\n\n') + CLASS + MODIFIER_LIST + ANNOTATION + PsiElement(LBRACKET)('[') + PsiErrorElement:File annotations are only allowed before package declaration + PsiElement(file)('file') + PsiElement(COLON)(':') + PsiErrorElement:Expecting a list of attributes + + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + PsiElement(trait)('trait') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('T') diff --git a/compiler/testData/psi/annotation/onFile/manyAnnotationBlocks.kt b/compiler/testData/psi/annotation/onFile/manyAnnotationBlocks.kt new file mode 100644 index 00000000000..bfb1ddc8b8d --- /dev/null +++ b/compiler/testData/psi/annotation/onFile/manyAnnotationBlocks.kt @@ -0,0 +1,3 @@ +[file: foo] +[file:bar baz] +package bar diff --git a/compiler/testData/psi/annotation/onFile/manyAnnotationBlocks.txt b/compiler/testData/psi/annotation/onFile/manyAnnotationBlocks.txt new file mode 100644 index 00000000000..cca9d75aa9f --- /dev/null +++ b/compiler/testData/psi/annotation/onFile/manyAnnotationBlocks.txt @@ -0,0 +1,39 @@ +JetFile: manyAnnotationBlocks.kt + FILE_ANNOTATION_LIST + ANNOTATION + PsiElement(LBRACKET)('[') + PsiElement(file)('file') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + ANNOTATION + PsiElement(LBRACKET)('[') + PsiElement(file)('file') + PsiElement(COLON)(':') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('baz') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + PACKAGE_DIRECTIVE + PsiElement(package)('package') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') diff --git a/compiler/testData/psi/annotation/onFile/manyInOneAnnotationBlock.kt b/compiler/testData/psi/annotation/onFile/manyInOneAnnotationBlock.kt new file mode 100644 index 00000000000..65623326763 --- /dev/null +++ b/compiler/testData/psi/annotation/onFile/manyInOneAnnotationBlock.kt @@ -0,0 +1,3 @@ +[file: foo bar +baz] +package bar diff --git a/compiler/testData/psi/annotation/onFile/manyInOneAnnotationBlock.txt b/compiler/testData/psi/annotation/onFile/manyInOneAnnotationBlock.txt new file mode 100644 index 00000000000..e9124c7d0d3 --- /dev/null +++ b/compiler/testData/psi/annotation/onFile/manyInOneAnnotationBlock.txt @@ -0,0 +1,34 @@ +JetFile: manyInOneAnnotationBlock.kt + FILE_ANNOTATION_LIST + ANNOTATION + PsiElement(LBRACKET)('[') + PsiElement(file)('file') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') + PsiWhiteSpace('\n') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('baz') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + PACKAGE_DIRECTIVE + PsiElement(package)('package') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') diff --git a/compiler/testData/psi/annotation/onFile/nonFIleAnnotationBeforePackage.kt b/compiler/testData/psi/annotation/onFile/nonFIleAnnotationBeforePackage.kt new file mode 100644 index 00000000000..563b148f895 --- /dev/null +++ b/compiler/testData/psi/annotation/onFile/nonFIleAnnotationBeforePackage.kt @@ -0,0 +1,8 @@ +[foo] +[file bar] +[file, baz] +[file] +[:foo.bar] +[file:] +[:] +package boo diff --git a/compiler/testData/psi/annotation/onFile/nonFIleAnnotationBeforePackage.txt b/compiler/testData/psi/annotation/onFile/nonFIleAnnotationBeforePackage.txt new file mode 100644 index 00000000000..0770ea6028a --- /dev/null +++ b/compiler/testData/psi/annotation/onFile/nonFIleAnnotationBeforePackage.txt @@ -0,0 +1,88 @@ +JetFile: nonFIleAnnotationBeforePackage.kt + FILE_ANNOTATION_LIST + ANNOTATION + PsiElement(LBRACKET)('[') + PsiErrorElement:Expecting "file:" prefix for file annotations + + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + ANNOTATION + PsiElement(LBRACKET)('[') + PsiElement(file)('file') + PsiErrorElement:Expecting "file:" prefix for file annotations + + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + ANNOTATION + PsiElement(LBRACKET)('[') + PsiElement(file)('file') + PsiErrorElement:Expecting "file:" prefix for file annotations + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('baz') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + ANNOTATION + PsiElement(LBRACKET)('[') + PsiElement(file)('file') + PsiErrorElement:Expecting "file:" prefix for file annotations + + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + ANNOTATION + PsiElement(LBRACKET)('[') + PsiErrorElement:Expecting "file:" prefix for file annotations + + PsiElement(COLON)(':') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + ANNOTATION + PsiElement(LBRACKET)('[') + PsiElement(file)('file') + PsiElement(COLON)(':') + PsiErrorElement:Expecting a list of annotations + + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + ANNOTATION + PsiElement(LBRACKET)('[') + PsiErrorElement:Expecting "file:" prefix for file annotations + + PsiElement(COLON)(':') + PsiErrorElement:Expecting a list of annotations + + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + PACKAGE_DIRECTIVE + PsiElement(package)('package') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('boo') diff --git a/compiler/testData/psi/annotation/onFile/single.kt b/compiler/testData/psi/annotation/onFile/single.kt new file mode 100644 index 00000000000..80c13d85fb9 --- /dev/null +++ b/compiler/testData/psi/annotation/onFile/single.kt @@ -0,0 +1,2 @@ +[file: foo] +package bar diff --git a/compiler/testData/psi/annotation/onFile/single.txt b/compiler/testData/psi/annotation/onFile/single.txt new file mode 100644 index 00000000000..f40e24ab8ce --- /dev/null +++ b/compiler/testData/psi/annotation/onFile/single.txt @@ -0,0 +1,20 @@ +JetFile: single.kt + FILE_ANNOTATION_LIST + ANNOTATION + PsiElement(LBRACKET)('[') + PsiElement(file)('file') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + PACKAGE_DIRECTIVE + PsiElement(package)('package') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') diff --git a/compiler/testData/psi/annotation/onFile/withoutFileAnnotationAndPackageDeclaration.kt b/compiler/testData/psi/annotation/onFile/withoutFileAnnotationAndPackageDeclaration.kt new file mode 100644 index 00000000000..d4c79c5a846 --- /dev/null +++ b/compiler/testData/psi/annotation/onFile/withoutFileAnnotationAndPackageDeclaration.kt @@ -0,0 +1,3 @@ +[ann] fun foo(): String? = null + +annotation class ann diff --git a/compiler/testData/psi/annotation/onFile/withoutFileAnnotationAndPackageDeclaration.txt b/compiler/testData/psi/annotation/onFile/withoutFileAnnotationAndPackageDeclaration.txt new file mode 100644 index 00000000000..65b8819d9e5 --- /dev/null +++ b/compiler/testData/psi/annotation/onFile/withoutFileAnnotationAndPackageDeclaration.txt @@ -0,0 +1,42 @@ +JetFile: withoutFileAnnotationAndPackageDeclaration.kt + PACKAGE_DIRECTIVE + + FUN + MODIFIER_LIST + ANNOTATION + PsiElement(LBRACKET)('[') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('ann') + PsiElement(RBRACKET)(']') + PsiWhiteSpace(' ') + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('String') + PsiElement(QUEST)('?') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + NULL + PsiElement(null)('null') + PsiWhiteSpace('\n\n') + CLASS + MODIFIER_LIST + PsiElement(annotation)('annotation') + PsiWhiteSpace(' ') + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('ann') diff --git a/compiler/testData/psi/annotation/onFile/withoutPackage.kt b/compiler/testData/psi/annotation/onFile/withoutPackage.kt new file mode 100644 index 00000000000..979db5a485e --- /dev/null +++ b/compiler/testData/psi/annotation/onFile/withoutPackage.kt @@ -0,0 +1,4 @@ +[file: foo] +[foo bar] +[file: baz] +fun foo() {} diff --git a/compiler/testData/psi/annotation/onFile/withoutPackage.txt b/compiler/testData/psi/annotation/onFile/withoutPackage.txt new file mode 100644 index 00000000000..c26c98d8400 --- /dev/null +++ b/compiler/testData/psi/annotation/onFile/withoutPackage.txt @@ -0,0 +1,60 @@ +JetFile: withoutPackage.kt + FILE_ANNOTATION_LIST + ANNOTATION + PsiElement(LBRACKET)('[') + PsiElement(file)('file') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + PACKAGE_DIRECTIVE + + FUN + MODIFIER_LIST + ANNOTATION + PsiElement(LBRACKET)('[') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + ANNOTATION + PsiElement(LBRACKET)('[') + PsiErrorElement:File annotations are only allowed before package declaration + PsiElement(file)('file') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('baz') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') diff --git a/compiler/testData/psi/annotation/onFile/withoutPackageWithSimpleAnnotation.kt b/compiler/testData/psi/annotation/onFile/withoutPackageWithSimpleAnnotation.kt new file mode 100644 index 00000000000..074b57d44f3 --- /dev/null +++ b/compiler/testData/psi/annotation/onFile/withoutPackageWithSimpleAnnotation.kt @@ -0,0 +1,4 @@ +[file: foo] +foo bar +[file: baz] +fun foo() {} diff --git a/compiler/testData/psi/annotation/onFile/withoutPackageWithSimpleAnnotation.txt b/compiler/testData/psi/annotation/onFile/withoutPackageWithSimpleAnnotation.txt new file mode 100644 index 00000000000..2f203c7f8f7 --- /dev/null +++ b/compiler/testData/psi/annotation/onFile/withoutPackageWithSimpleAnnotation.txt @@ -0,0 +1,57 @@ +JetFile: withoutPackageWithSimpleAnnotation.kt + FILE_ANNOTATION_LIST + ANNOTATION + PsiElement(LBRACKET)('[') + PsiElement(file)('file') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + PACKAGE_DIRECTIVE + + FUN + MODIFIER_LIST + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') + PsiWhiteSpace('\n') + ANNOTATION + PsiElement(LBRACKET)('[') + PsiErrorElement:File annotations are only allowed before package declaration + PsiElement(file)('file') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('baz') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/testData/psi/script/manyAnnotationsOnFile.kts b/compiler/testData/psi/script/manyAnnotationsOnFile.kts new file mode 100644 index 00000000000..bfb1ddc8b8d --- /dev/null +++ b/compiler/testData/psi/script/manyAnnotationsOnFile.kts @@ -0,0 +1,3 @@ +[file: foo] +[file:bar baz] +package bar diff --git a/compiler/testData/psi/script/manyAnnotationsOnFile.txt b/compiler/testData/psi/script/manyAnnotationsOnFile.txt new file mode 100644 index 00000000000..a16ff0f6464 --- /dev/null +++ b/compiler/testData/psi/script/manyAnnotationsOnFile.txt @@ -0,0 +1,42 @@ +JetFile: manyAnnotationsOnFile.kts + FILE_ANNOTATION_LIST + ANNOTATION + PsiElement(LBRACKET)('[') + PsiElement(file)('file') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + ANNOTATION + PsiElement(LBRACKET)('[') + PsiElement(file)('file') + PsiElement(COLON)(':') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('baz') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + PACKAGE_DIRECTIVE + PsiElement(package)('package') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') + SCRIPT + BLOCK + diff --git a/compiler/tests/org/jetbrains/jet/parsing/JetParsingTestGenerated.java b/compiler/tests/org/jetbrains/jet/parsing/JetParsingTestGenerated.java index 48167c90de5..2863d0da202 100644 --- a/compiler/tests/org/jetbrains/jet/parsing/JetParsingTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/parsing/JetParsingTestGenerated.java @@ -35,7 +35,7 @@ import java.util.regex.Pattern; public class JetParsingTestGenerated extends AbstractJetParsingTest { @TestMetadata("compiler/testData/psi") @TestDataPath("$PROJECT_ROOT") - @InnerTestClasses({Psi.Examples.class, Psi.FunctionReceivers.class, Psi.GreatSyntacticShift.class, Psi.Kdoc.class, Psi.PropertyDelegate.class, Psi.Recovery.class, Psi.Script.class, Psi.StringTemplates.class}) + @InnerTestClasses({Psi.Annotation.class, Psi.Examples.class, Psi.FunctionReceivers.class, Psi.GreatSyntacticShift.class, Psi.Kdoc.class, Psi.PropertyDelegate.class, Psi.Recovery.class, Psi.Script.class, Psi.StringTemplates.class}) @RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class) public static class Psi extends AbstractJetParsingTest { @TestMetadata("AbsentInnerType.kt") @@ -546,6 +546,75 @@ public class JetParsingTestGenerated extends AbstractJetParsingTest { doParsingTest(fileName); } + @TestMetadata("compiler/testData/psi/annotation") + @TestDataPath("$PROJECT_ROOT") + @InnerTestClasses({Annotation.OnFile.class}) + @RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class) + public static class Annotation extends AbstractJetParsingTest { + public void testAllFilesPresentInAnnotation() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/psi/annotation"), Pattern.compile("^(.*)\\.kts?$"), true); + } + + @TestMetadata("compiler/testData/psi/annotation/onFile") + @TestDataPath("$PROJECT_ROOT") + @RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class) + public static class OnFile extends AbstractJetParsingTest { + public void testAllFilesPresentInOnFile() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/psi/annotation/onFile"), Pattern.compile("^(.*)\\.kts?$"), true); + } + + @TestMetadata("fileAnnotationInWrongPlace.kt") + public void testFileAnnotationInWrongPlace() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/annotation/onFile/fileAnnotationInWrongPlace.kt"); + doParsingTest(fileName); + } + + @TestMetadata("manyAnnotationBlocks.kt") + public void testManyAnnotationBlocks() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/annotation/onFile/manyAnnotationBlocks.kt"); + doParsingTest(fileName); + } + + @TestMetadata("manyInOneAnnotationBlock.kt") + public void testManyInOneAnnotationBlock() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/annotation/onFile/manyInOneAnnotationBlock.kt"); + doParsingTest(fileName); + } + + @TestMetadata("nonFIleAnnotationBeforePackage.kt") + public void testNonFIleAnnotationBeforePackage() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/annotation/onFile/nonFIleAnnotationBeforePackage.kt"); + doParsingTest(fileName); + } + + @TestMetadata("single.kt") + public void testSingle() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/annotation/onFile/single.kt"); + doParsingTest(fileName); + } + + @TestMetadata("withoutFileAnnotationAndPackageDeclaration.kt") + public void testWithoutFileAnnotationAndPackageDeclaration() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/annotation/onFile/withoutFileAnnotationAndPackageDeclaration.kt"); + doParsingTest(fileName); + } + + @TestMetadata("withoutPackage.kt") + public void testWithoutPackage() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/annotation/onFile/withoutPackage.kt"); + doParsingTest(fileName); + } + + @TestMetadata("withoutPackageWithSimpleAnnotation.kt") + public void testWithoutPackageWithSimpleAnnotation() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/annotation/onFile/withoutPackageWithSimpleAnnotation.kt"); + doParsingTest(fileName); + } + + } + + } + @TestMetadata("compiler/testData/psi/examples") @TestDataPath("$PROJECT_ROOT") @InnerTestClasses({Examples.Array.class, Examples.Collections.class, Examples.Io.class, Examples.Map.class, Examples.Priorityqueues.class, Examples.Util.class}) @@ -1251,6 +1320,12 @@ public class JetParsingTestGenerated extends AbstractJetParsingTest { doParsingTest(fileName); } + @TestMetadata("manyAnnotationsOnFile.kts") + public void testManyAnnotationsOnFile() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/script/manyAnnotationsOnFile.kts"); + doParsingTest(fileName); + } + @TestMetadata("Shebang.kts") public void testShebang() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/script/Shebang.kts");