New Java parser (work in progress)

This commit is contained in:
Roman Shevchenko
2010-07-28 11:36:09 +04:00
parent fb03ab9d6d
commit c654288e18
21 changed files with 730 additions and 39 deletions
@@ -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<PsiBuilder.Marker, Boolean> 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<PsiBuilder.Marker, Boolean> 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<PsiBuilder.Marker, Boolean> 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();
@@ -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) {
@@ -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;
}
}
}
@@ -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());
}
@@ -0,0 +1,33 @@
PsiJavaFile:CompletionHack0.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiField:s
PsiModifierList:
<empty list>
PsiErrorElement:Unexpected token
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:X
PsiIdentifier:X('X')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiWhiteSpace(' ')
PsiErrorElement:Unexpected identifier
PsiIdentifier:IntelliJIdeaRulezz('IntelliJIdeaRulezz')
PsiJavaToken:GT('>')
PsiWhiteSpace('\n ')
PsiTypeElement:String
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:s('s')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiLiteralExpression:""
PsiJavaToken:STRING_LITERAL('""')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,31 @@
PsiJavaFile:CompletionHack1.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiField:s
PsiModifierList:
<empty list>
PsiErrorElement:Unexpected token
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:X
PsiIdentifier:X('X')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiErrorElement:'>' expected.
<empty list>
PsiWhiteSpace('\n ')
PsiTypeElement:String
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:s('s')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiLiteralExpression:""
PsiJavaToken:STRING_LITERAL('""')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -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)
<empty list>
PsiErrorElement:'>' expected.
<empty list>
PsiWhiteSpace(' ')
PsiTypeElement:descr
PsiJavaCodeReferenceElement:descr
PsiIdentifier:descr('descr')
PsiReferenceParameterList
<empty list>
PsiErrorElement:Identifier expected
<empty list>
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('}')
@@ -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)
<empty list>
PsiJavaToken:GT('>')
PsiWhiteSpace(' ')
PsiIdentifier:test('test')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace('\n ')
PsiMethod:test1
PsiModifierList:
<empty list>
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:E
PsiIdentifier:E('E')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiJavaToken:GT('>')
PsiWhiteSpace(' ')
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:test1('test1')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace('\n ')
PsiMethod:test2
PsiModifierList:
<empty list>
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:E1
PsiIdentifier:E1('E1')
PsiWhiteSpace(' ')
PsiElement(EXTENDS_BOUND_LIST)
PsiKeyword:extends('extends')
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:Integer
PsiIdentifier:Integer('Integer')
PsiReferenceParameterList
<empty list>
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiTypeParameter:E2
PsiIdentifier:E2('E2')
PsiWhiteSpace(' ')
PsiElement(EXTENDS_BOUND_LIST)
PsiKeyword:extends('extends')
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:Runnable
PsiIdentifier:Runnable('Runnable')
PsiReferenceParameterList
<empty list>
PsiJavaToken:GT('>')
PsiWhiteSpace(' ')
PsiTypeElement:String
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:test2('test2')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,43 @@
PsiJavaFile:GenericMethodErrors.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiModifierList:
<empty list>
PsiErrorElement:Unexpected token
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:Error
PsiIdentifier:Error('Error')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiErrorElement:'>' expected.
<empty list>
PsiWhiteSpace(' ')
PsiTypeElement:sss
PsiJavaCodeReferenceElement:sss
PsiIdentifier:sss('sss')
PsiReferenceParameterList
<empty list>
PsiErrorElement:Identifier expected
<empty list>
PsiWhiteSpace(' ')
PsiErrorElement:Unexpected token
PsiJavaToken:DIV('/')
PsiJavaToken:GT('>')
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:test <error>
PsiIdentifier:test('test')
PsiWhiteSpace(' ')
PsiReferenceParameterList
PsiJavaToken:LT('<')
PsiTypeElement:error
PsiJavaCodeReferenceElement:error
PsiIdentifier:error('error')
PsiReferenceParameterList
<empty list>
PsiJavaToken:GT('>')
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,24 @@
PsiJavaFile:MethodNormal0.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:f
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:f('f')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiWhiteSpace(' ')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,20 @@
PsiJavaFile:MethodNormal1.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:f
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:f('f')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,21 @@
PsiJavaFile:Unclosed0.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:f
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:f('f')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiErrorElement:'{' or ';' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,22 @@
PsiJavaFile:Unclosed1.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:f
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:f('f')
PsiParameterList:(
PsiJavaToken:LPARENTH('(')
PsiErrorElement:')' expected
<empty list>
PsiReferenceList
<empty list>
PsiErrorElement:'{' or ';' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,37 @@
PsiJavaFile:Unclosed2.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:f
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:f('f')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiErrorElement:'{' or ';' expected
<empty list>
PsiWhiteSpace('\n ')
PsiMethod:g
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:g('g')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,29 @@
PsiJavaFile:Unclosed3.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:f
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:f('f')
PsiParameterList:(int a
PsiJavaToken:LPARENTH('(')
PsiParameter:a
PsiModifierList:
<empty list>
PsiTypeElement:int
PsiKeyword:int('int')
PsiWhiteSpace(' ')
PsiIdentifier:a('a')
PsiErrorElement:')' expected
<empty list>
PsiReferenceList
<empty list>
PsiErrorElement:'{' or ';' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,33 @@
PsiJavaFile:Unclosed4.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:f
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:f('f')
PsiParameterList:(int a,,
PsiJavaToken:LPARENTH('(')
PsiParameter:a
PsiModifierList:
<empty list>
PsiTypeElement:int
PsiKeyword:int('int')
PsiWhiteSpace(' ')
PsiIdentifier:a('a')
PsiJavaToken:COMMA(',')
PsiErrorElement:Parameter expected
<empty list>
PsiJavaToken:COMMA(',')
PsiErrorElement:Identifier or type expected
<empty list>
PsiReferenceList
<empty list>
PsiErrorElement:'{' or ';' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,30 @@
PsiJavaFile:Unclosed5.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:f
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:void
PsiKeyword:void('void')
PsiWhiteSpace(' ')
PsiIdentifier:f('f')
PsiParameterList:(int a,)
PsiJavaToken:LPARENTH('(')
PsiParameter:a
PsiModifierList:
<empty list>
PsiTypeElement:int
PsiKeyword:int('int')
PsiWhiteSpace(' ')
PsiIdentifier:a('a')
PsiJavaToken:COMMA(',')
PsiErrorElement:Identifier or type expected
<empty list>
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,55 @@
PsiJavaFile:WildcardParsing.java
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiMethod:x
PsiModifierList:
<empty list>
PsiTypeParameterList
<empty list>
PsiTypeElement:List<? extends B>
PsiJavaCodeReferenceElement:List<? extends B>
PsiIdentifier:List('List')
PsiReferenceParameterList
PsiJavaToken:LT('<')
PsiTypeElement:? extends B
PsiJavaToken:QUEST('?')
PsiWhiteSpace(' ')
PsiKeyword:extends('extends')
PsiWhiteSpace(' ')
PsiTypeElement:B
PsiJavaCodeReferenceElement:B
PsiIdentifier:B('B')
PsiReferenceParameterList
<empty list>
PsiJavaToken:GT('>')
PsiWhiteSpace(' ')
PsiIdentifier:x('x')
PsiParameterList:(Collection<? super B> x)
PsiJavaToken:LPARENTH('(')
PsiParameter:x
PsiModifierList:
<empty list>
PsiTypeElement:Collection<? super B>
PsiJavaCodeReferenceElement:Collection<? super B>
PsiIdentifier:Collection('Collection')
PsiReferenceParameterList
PsiJavaToken:LT('<')
PsiTypeElement:? super B
PsiJavaToken:QUEST('?')
PsiWhiteSpace(' ')
PsiKeyword:super('super')
PsiWhiteSpace(' ')
PsiTypeElement:B
PsiJavaCodeReferenceElement:B
PsiIdentifier:B('B')
PsiReferenceParameterList
<empty list>
PsiJavaToken:GT('>')
PsiWhiteSpace(' ')
PsiIdentifier:x('x')
PsiJavaToken:RPARENTH(')')
PsiReferenceList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -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
@@ -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
@@ -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 <E> test();\n" +
" <E> void test1();\n" +
" <E1 extends Integer, E2 extends Runnable> String test2(); }", false, false); }
public void testGenericMethodErrors() { doParserTest("{ <Error sss /> test <error>(); }", false, false); }
public void testErrors() { doParserTest("{ public static <error descr=\"2\">protected int f1 = 0; }", false, false); }
public void testCompletionHack0() { doParserTest("{ <X IntelliJIdeaRulezz>\n String s = \"\"; }", false, false); }
public void testCompletionHack1() { doParserTest("{ <X\n String s = \"\"; }", false, false); }
public void testWildcardParsing() { doParserTest("{ List<? extends B> x(Collection<? super B> 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) {