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.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.DeclarationParsingMode.LOCAL;
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);
@@ -1376,7 +1377,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
IElementType keywordToken = tt();
IElementType declType = null;
if (keywordToken == CLASS_KEYWORD || keywordToken == TRAIT_KEYWORD || keywordToken == INTERFACE_KEYWORD) {
declType = myJetParsing.parseClass(isEnum);
declType = myJetParsing.parseClass(isEnum, LOCAL);
}
else if (keywordToken == FUN_KEYWORD) {
declType = myJetParsing.parseFunction();
@@ -1400,7 +1401,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
return null;
}
myJetParsing.parseObject(NameParsingMode.REQUIRED, true);
myJetParsing.parseObject(NameParsingMode.REQUIRED, true, LOCAL);
declType = OBJECT_DECLARATION;
}
return declType;
@@ -1934,7 +1935,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
public void parseObjectLiteral() {
PsiBuilder.Marker literal = 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);
literal.done(OBJECT_LITERAL);
}
@@ -32,6 +32,7 @@ import java.util.Map;
import static org.jetbrains.kotlin.JetNodeTypes.*;
import static org.jetbrains.kotlin.lexer.JetTokens.*;
import static org.jetbrains.kotlin.parsing.JetParsing.AnnotationParsingMode.*;
import static org.jetbrains.kotlin.parsing.JetParsing.DeclarationParsingMode.*;
public class JetParsing extends AbstractJetParsing {
private static final Logger LOG = Logger.getInstance(JetParsing.class);
@@ -387,7 +388,7 @@ public class JetParsing extends AbstractJetParsing {
// }
// else
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) {
declType = parseFunction();
@@ -399,7 +400,7 @@ public class JetParsing extends AbstractJetParsing {
declType = parseTypeAlias();
}
else if (keywordToken == OBJECT_KEYWORD) {
parseObject(NameParsingMode.REQUIRED, true);
parseObject(NameParsingMode.REQUIRED, true, TOP_LEVEL);
declType = OBJECT_DECLARATION;
}
else if (at(LBRACE)) {
@@ -439,7 +440,8 @@ public class JetParsing extends AbstractJetParsing {
boolean empty = true;
while (!eof()) {
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 (!tryParseModifier(tokenConsumer)) {
@@ -693,6 +695,12 @@ public class JetParsing extends AbstractJetParsing {
PROHIBITED
}
public enum DeclarationParsingMode {
TOP_LEVEL,
CLASS_MEMBER,
LOCAL
}
/*
* class
* : modifiers ("class" | "interface") SimpleName
@@ -707,7 +715,13 @@ public class JetParsing extends AbstractJetParsing {
* : "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) {
assert _at(OBJECT_KEYWORD);
}
@@ -743,7 +757,9 @@ public class JetParsing extends AbstractJetParsing {
OptionalMarker constructorModifiersMarker = new OptionalMarker(object);
PsiBuilder.Marker beforeConstructorModifiers = 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
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;
}
IElementType parseClass(boolean enumClass) {
return parseClassOrObject(false, NameParsingMode.REQUIRED, true, enumClass);
IElementType parseClass(boolean enumClass, DeclarationParsingMode declarationParsingMode) {
return parseClassOrObject(false, NameParsingMode.REQUIRED, true, enumClass, declarationParsingMode);
}
void parseObject(NameParsingMode nameParsingMode, boolean optionalBody) {
parseClassOrObject(true, nameParsingMode, optionalBody, false);
void parseObject(NameParsingMode nameParsingMode, boolean optionalBody, DeclarationParsingMode declarationParsingMode) {
parseClassOrObject(true, nameParsingMode, optionalBody, false, declarationParsingMode);
}
/*
@@ -1023,7 +1039,7 @@ public class JetParsing extends AbstractJetParsing {
IElementType keywordToken = tt();
IElementType declType = null;
if (keywordToken == CLASS_KEYWORD || keywordToken == TRAIT_KEYWORD || keywordToken == INTERFACE_KEYWORD) {
declType = parseClass(isEnum);
declType = parseClass(isEnum, CLASS_MEMBER);
}
else if (keywordToken == FUN_KEYWORD) {
declType = parseFunction();
@@ -1035,7 +1051,7 @@ public class JetParsing extends AbstractJetParsing {
declType = parseTypeAlias();
}
else if (keywordToken == OBJECT_KEYWORD) {
parseObject(isDefault ? NameParsingMode.ALLOWED : NameParsingMode.REQUIRED, true);
parseObject(isDefault ? NameParsingMode.ALLOWED : NameParsingMode.REQUIRED, true, CLASS_MEMBER);
declType = OBJECT_DECLARATION;
}
else if (at(INIT_KEYWORD)) {
@@ -2313,7 +2329,8 @@ public class JetParsing extends AbstractJetParsing {
ONLY_ESCAPED_REGULAR_ANNOTATIONS(false, false, false),
ALLOW_UNESCAPED_REGULAR_ANNOTATIONS(true, false, false),
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 isFileAnnotationParsingMode;
@@ -1,4 +1,15 @@
fun foo() {
class A1 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')
PsiWhiteSpace(' ')
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(' ')
PRIMARY_CONSTRUCTOR
MODIFIER_LIST
PsiElement(private)('private')
PsiWhiteSpace(' ')
ANNOTATION_ENTRY
PsiElement(AT)('@')
CONSTRUCTOR_CALLEE
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Ann')
PsiWhiteSpace(' ')
PsiElement(private)('private')
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 ')
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')
PsiElement(RBRACE)('}')