Prohibit unescaped annotations on primary constructor of local class

This commit is contained in:
Denis Zharkov
2015-05-16 17:43:29 +03:00
parent 89337ff51e
commit dd14b36921
4 changed files with 133 additions and 17 deletions
@@ -35,6 +35,7 @@ import static org.jetbrains.kotlin.JetNodeTypes.*;
import static org.jetbrains.kotlin.lexer.JetTokens.*; import static org.jetbrains.kotlin.lexer.JetTokens.*;
import static org.jetbrains.kotlin.parsing.JetParsing.AnnotationParsingMode.ALLOW_UNESCAPED_REGULAR_ANNOTATIONS; import static org.jetbrains.kotlin.parsing.JetParsing.AnnotationParsingMode.ALLOW_UNESCAPED_REGULAR_ANNOTATIONS;
import static org.jetbrains.kotlin.parsing.JetParsing.AnnotationParsingMode.ONLY_ESCAPED_REGULAR_ANNOTATIONS; import static org.jetbrains.kotlin.parsing.JetParsing.AnnotationParsingMode.ONLY_ESCAPED_REGULAR_ANNOTATIONS;
import static org.jetbrains.kotlin.parsing.JetParsing.DeclarationParsingMode.LOCAL;
public class JetExpressionParsing extends AbstractJetParsing { public class JetExpressionParsing extends AbstractJetParsing {
private static final TokenSet WHEN_CONDITION_RECOVERY_SET = TokenSet.create(RBRACE, IN_KEYWORD, NOT_IN, IS_KEYWORD, NOT_IS, ELSE_KEYWORD); private static final TokenSet WHEN_CONDITION_RECOVERY_SET = TokenSet.create(RBRACE, IN_KEYWORD, NOT_IN, IS_KEYWORD, NOT_IS, ELSE_KEYWORD);
@@ -1376,7 +1377,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
IElementType keywordToken = tt(); IElementType keywordToken = tt();
IElementType declType = null; IElementType declType = null;
if (keywordToken == CLASS_KEYWORD || keywordToken == TRAIT_KEYWORD || keywordToken == INTERFACE_KEYWORD) { if (keywordToken == CLASS_KEYWORD || keywordToken == TRAIT_KEYWORD || keywordToken == INTERFACE_KEYWORD) {
declType = myJetParsing.parseClass(isEnum); declType = myJetParsing.parseClass(isEnum, LOCAL);
} }
else if (keywordToken == FUN_KEYWORD) { else if (keywordToken == FUN_KEYWORD) {
declType = myJetParsing.parseFunction(); declType = myJetParsing.parseFunction();
@@ -1400,7 +1401,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
return null; return null;
} }
myJetParsing.parseObject(NameParsingMode.REQUIRED, true); myJetParsing.parseObject(NameParsingMode.REQUIRED, true, LOCAL);
declType = OBJECT_DECLARATION; declType = OBJECT_DECLARATION;
} }
return declType; return declType;
@@ -1934,7 +1935,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
public void parseObjectLiteral() { public void parseObjectLiteral() {
PsiBuilder.Marker literal = mark(); PsiBuilder.Marker literal = mark();
PsiBuilder.Marker declaration = mark(); PsiBuilder.Marker declaration = mark();
myJetParsing.parseObject(NameParsingMode.PROHIBITED, false); // Body is not optional because of foo(object : A, B) myJetParsing.parseObject(NameParsingMode.PROHIBITED, false, LOCAL); // Body is not optional because of foo(object : A, B)
declaration.done(OBJECT_DECLARATION); declaration.done(OBJECT_DECLARATION);
literal.done(OBJECT_LITERAL); literal.done(OBJECT_LITERAL);
} }
@@ -32,6 +32,7 @@ import java.util.Map;
import static org.jetbrains.kotlin.JetNodeTypes.*; import static org.jetbrains.kotlin.JetNodeTypes.*;
import static org.jetbrains.kotlin.lexer.JetTokens.*; import static org.jetbrains.kotlin.lexer.JetTokens.*;
import static org.jetbrains.kotlin.parsing.JetParsing.AnnotationParsingMode.*; import static org.jetbrains.kotlin.parsing.JetParsing.AnnotationParsingMode.*;
import static org.jetbrains.kotlin.parsing.JetParsing.DeclarationParsingMode.*;
public class JetParsing extends AbstractJetParsing { public class JetParsing extends AbstractJetParsing {
private static final Logger LOG = Logger.getInstance(JetParsing.class); private static final Logger LOG = Logger.getInstance(JetParsing.class);
@@ -387,7 +388,7 @@ public class JetParsing extends AbstractJetParsing {
// } // }
// else // else
if (keywordToken == CLASS_KEYWORD || keywordToken == TRAIT_KEYWORD || keywordToken == INTERFACE_KEYWORD) { if (keywordToken == CLASS_KEYWORD || keywordToken == TRAIT_KEYWORD || keywordToken == INTERFACE_KEYWORD) {
declType = parseClass(detector.isEnumDetected()); declType = parseClass(detector.isEnumDetected(), TOP_LEVEL);
} }
else if (keywordToken == FUN_KEYWORD) { else if (keywordToken == FUN_KEYWORD) {
declType = parseFunction(); declType = parseFunction();
@@ -399,7 +400,7 @@ public class JetParsing extends AbstractJetParsing {
declType = parseTypeAlias(); declType = parseTypeAlias();
} }
else if (keywordToken == OBJECT_KEYWORD) { else if (keywordToken == OBJECT_KEYWORD) {
parseObject(NameParsingMode.REQUIRED, true); parseObject(NameParsingMode.REQUIRED, true, TOP_LEVEL);
declType = OBJECT_DECLARATION; declType = OBJECT_DECLARATION;
} }
else if (at(LBRACE)) { else if (at(LBRACE)) {
@@ -439,7 +440,8 @@ public class JetParsing extends AbstractJetParsing {
boolean empty = true; boolean empty = true;
while (!eof()) { while (!eof()) {
if (annotationParsingMode.atMemberStart && atSet(SOFT_KEYWORDS_AT_MEMBER_START)) break; if (annotationParsingMode.atMemberStart && atSet(SOFT_KEYWORDS_AT_MEMBER_START)) break;
if (annotationParsingMode == PRIMARY_CONSTRUCTOR_MODIFIER_LIST && atSet(CONSTRUCTOR_KEYWORD, WHERE_KEYWORD)) break; if ((annotationParsingMode == PRIMARY_CONSTRUCTOR_MODIFIER_LIST || annotationParsingMode == PRIMARY_CONSTRUCTOR_MODIFIER_LIST_LOCAL) &&
atSet(CONSTRUCTOR_KEYWORD, WHERE_KEYWORD)) break;
if (at(AT)) { if (at(AT)) {
if (!tryParseModifier(tokenConsumer)) { if (!tryParseModifier(tokenConsumer)) {
@@ -693,6 +695,12 @@ public class JetParsing extends AbstractJetParsing {
PROHIBITED PROHIBITED
} }
public enum DeclarationParsingMode {
TOP_LEVEL,
CLASS_MEMBER,
LOCAL
}
/* /*
* class * class
* : modifiers ("class" | "interface") SimpleName * : modifiers ("class" | "interface") SimpleName
@@ -707,7 +715,13 @@ public class JetParsing extends AbstractJetParsing {
* : "object" SimpleName? ":" delegationSpecifier{","}? classBody? * : "object" SimpleName? ":" delegationSpecifier{","}? classBody?
* ; * ;
*/ */
IElementType parseClassOrObject(boolean object, NameParsingMode nameParsingMode, boolean optionalBody, boolean enumClass) { IElementType parseClassOrObject(
boolean object,
NameParsingMode nameParsingMode,
boolean optionalBody,
boolean enumClass,
DeclarationParsingMode declarationParsingMode
) {
if (object) { if (object) {
assert _at(OBJECT_KEYWORD); assert _at(OBJECT_KEYWORD);
} }
@@ -743,7 +757,9 @@ public class JetParsing extends AbstractJetParsing {
OptionalMarker constructorModifiersMarker = new OptionalMarker(object); OptionalMarker constructorModifiersMarker = new OptionalMarker(object);
PsiBuilder.Marker beforeConstructorModifiers = mark(); PsiBuilder.Marker beforeConstructorModifiers = mark();
PsiBuilder.Marker primaryConstructorMarker = mark(); PsiBuilder.Marker primaryConstructorMarker = mark();
boolean hasConstructorModifiers = parseModifierList(PRIMARY_CONSTRUCTOR_MODIFIER_LIST); boolean hasConstructorModifiers = parseModifierList(
declarationParsingMode != LOCAL ? PRIMARY_CONSTRUCTOR_MODIFIER_LIST : PRIMARY_CONSTRUCTOR_MODIFIER_LIST_LOCAL
);
// Some modifiers found, but no parentheses following: class has already ended, and we are looking at something else // Some modifiers found, but no parentheses following: class has already ended, and we are looking at something else
if ((object && at(CONSTRUCTOR_KEYWORD)) || (hasConstructorModifiers && !atSet(LPAR, LBRACE, COLON, CONSTRUCTOR_KEYWORD))) { if ((object && at(CONSTRUCTOR_KEYWORD)) || (hasConstructorModifiers && !atSet(LPAR, LBRACE, COLON, CONSTRUCTOR_KEYWORD))) {
@@ -808,12 +824,12 @@ public class JetParsing extends AbstractJetParsing {
return object ? OBJECT_DECLARATION : CLASS; return object ? OBJECT_DECLARATION : CLASS;
} }
IElementType parseClass(boolean enumClass) { IElementType parseClass(boolean enumClass, DeclarationParsingMode declarationParsingMode) {
return parseClassOrObject(false, NameParsingMode.REQUIRED, true, enumClass); return parseClassOrObject(false, NameParsingMode.REQUIRED, true, enumClass, declarationParsingMode);
} }
void parseObject(NameParsingMode nameParsingMode, boolean optionalBody) { void parseObject(NameParsingMode nameParsingMode, boolean optionalBody, DeclarationParsingMode declarationParsingMode) {
parseClassOrObject(true, nameParsingMode, optionalBody, false); parseClassOrObject(true, nameParsingMode, optionalBody, false, declarationParsingMode);
} }
/* /*
@@ -1023,7 +1039,7 @@ public class JetParsing extends AbstractJetParsing {
IElementType keywordToken = tt(); IElementType keywordToken = tt();
IElementType declType = null; IElementType declType = null;
if (keywordToken == CLASS_KEYWORD || keywordToken == TRAIT_KEYWORD || keywordToken == INTERFACE_KEYWORD) { if (keywordToken == CLASS_KEYWORD || keywordToken == TRAIT_KEYWORD || keywordToken == INTERFACE_KEYWORD) {
declType = parseClass(isEnum); declType = parseClass(isEnum, CLASS_MEMBER);
} }
else if (keywordToken == FUN_KEYWORD) { else if (keywordToken == FUN_KEYWORD) {
declType = parseFunction(); declType = parseFunction();
@@ -1035,7 +1051,7 @@ public class JetParsing extends AbstractJetParsing {
declType = parseTypeAlias(); declType = parseTypeAlias();
} }
else if (keywordToken == OBJECT_KEYWORD) { else if (keywordToken == OBJECT_KEYWORD) {
parseObject(isDefault ? NameParsingMode.ALLOWED : NameParsingMode.REQUIRED, true); parseObject(isDefault ? NameParsingMode.ALLOWED : NameParsingMode.REQUIRED, true, CLASS_MEMBER);
declType = OBJECT_DECLARATION; declType = OBJECT_DECLARATION;
} }
else if (at(INIT_KEYWORD)) { else if (at(INIT_KEYWORD)) {
@@ -2313,7 +2329,8 @@ public class JetParsing extends AbstractJetParsing {
ONLY_ESCAPED_REGULAR_ANNOTATIONS(false, false, false), ONLY_ESCAPED_REGULAR_ANNOTATIONS(false, false, false),
ALLOW_UNESCAPED_REGULAR_ANNOTATIONS(true, false, false), ALLOW_UNESCAPED_REGULAR_ANNOTATIONS(true, false, false),
ALLOW_UNESCAPED_REGULAR_ANNOTATIONS_AT_MEMBER_MODIFIER_LIST(true, false, true), ALLOW_UNESCAPED_REGULAR_ANNOTATIONS_AT_MEMBER_MODIFIER_LIST(true, false, true),
PRIMARY_CONSTRUCTOR_MODIFIER_LIST(true, false, false); PRIMARY_CONSTRUCTOR_MODIFIER_LIST(true, false, false),
PRIMARY_CONSTRUCTOR_MODIFIER_LIST_LOCAL(false, false, false);
boolean allowShortAnnotations; boolean allowShortAnnotations;
boolean isFileAnnotationParsingMode; boolean isFileAnnotationParsingMode;
@@ -1,4 +1,15 @@
fun foo() { fun foo() {
class A1 constructor() class A1 constructor()
class A2 Ann private constructor() class A2 Ann private constructor()
class A3 private @Ann("") constructor()
class A4 @Ann("") constructor()
class A5
Ann
constructor()
class A6
Ann("")
constructor()
} }
@@ -27,21 +27,108 @@ JetFile: local.kt
PsiElement(class)('class') PsiElement(class)('class')
PsiWhiteSpace(' ') PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('A2') PsiElement(IDENTIFIER)('A2')
PsiWhiteSpace(' ')
PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line)
PsiElement(IDENTIFIER)('Ann')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('private')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('constructor')
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n\n ')
CLASS
PsiElement(class)('class')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('A3')
PsiWhiteSpace(' ') PsiWhiteSpace(' ')
PRIMARY_CONSTRUCTOR PRIMARY_CONSTRUCTOR
MODIFIER_LIST MODIFIER_LIST
PsiElement(private)('private')
PsiWhiteSpace(' ')
ANNOTATION_ENTRY ANNOTATION_ENTRY
PsiElement(AT)('@')
CONSTRUCTOR_CALLEE CONSTRUCTOR_CALLEE
TYPE_REFERENCE TYPE_REFERENCE
USER_TYPE USER_TYPE
REFERENCE_EXPRESSION REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Ann') PsiElement(IDENTIFIER)('Ann')
PsiWhiteSpace(' ') VALUE_ARGUMENT_LIST
PsiElement(private)('private') PsiElement(LPAR)('(')
VALUE_ARGUMENT
STRING_TEMPLATE
PsiElement(OPEN_QUOTE)('"')
PsiElement(CLOSING_QUOTE)('"')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ') PsiWhiteSpace(' ')
PsiElement(constructor)('constructor') PsiElement(constructor)('constructor')
VALUE_PARAMETER_LIST VALUE_PARAMETER_LIST
PsiElement(LPAR)('(') PsiElement(LPAR)('(')
PsiElement(RPAR)(')') PsiElement(RPAR)(')')
PsiWhiteSpace('\n ')
CLASS
PsiElement(class)('class')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('A4')
PsiWhiteSpace(' ')
PRIMARY_CONSTRUCTOR
MODIFIER_LIST
ANNOTATION_ENTRY
PsiElement(AT)('@')
CONSTRUCTOR_CALLEE
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Ann')
VALUE_ARGUMENT_LIST
PsiElement(LPAR)('(')
VALUE_ARGUMENT
STRING_TEMPLATE
PsiElement(OPEN_QUOTE)('"')
PsiElement(CLOSING_QUOTE)('"')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(constructor)('constructor')
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n\n ')
CLASS
PsiElement(class)('class')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('A5')
PsiWhiteSpace('\n ')
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Ann')
PsiWhiteSpace('\n ')
CALL_EXPRESSION
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('constructor')
VALUE_ARGUMENT_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n\n ')
CLASS
PsiElement(class)('class')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('A6')
PsiWhiteSpace('\n ')
CALL_EXPRESSION
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Ann')
VALUE_ARGUMENT_LIST
PsiElement(LPAR)('(')
VALUE_ARGUMENT
STRING_TEMPLATE
PsiElement(OPEN_QUOTE)('"')
PsiElement(CLOSING_QUOTE)('"')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n ')
CALL_EXPRESSION
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('constructor')
VALUE_ARGUMENT_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n') PsiWhiteSpace('\n')
PsiElement(RBRACE)('}') PsiElement(RBRACE)('}')