New Java parser (work in progress)

This commit is contained in:
Roman Shevchenko
2010-07-22 16:17:30 +04:00
parent 4736a40076
commit 310e1ffc64
100 changed files with 3341 additions and 4 deletions
@@ -0,0 +1,437 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.java.parser;
import com.intellij.codeInsight.daemon.JavaErrorMessages;
import com.intellij.lang.LighterASTNode;
import com.intellij.lang.PsiBuilder;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.impl.source.tree.ElementType;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.ILazyParseableElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.lang.PsiBuilderUtil.expect;
import static com.intellij.lang.java.parser.JavaParserUtil.*;
public class DeclarationParser {
public enum Context {
FILE, CLASS, CODE_BLOCK, ANNOTATION_INTERFACE
}
private static final TokenSet AFTER_END_DECLARATION_SET = TokenSet.create(JavaElementType.FIELD, JavaElementType.METHOD);
private DeclarationParser() { }
@Nullable
public static PsiBuilder.Marker parseClassBodyWithBraces(final PsiBuilder builder, final boolean isAnnotation, final boolean isEnum) {
if (builder.getTokenType() != JavaTokenType.LBRACE) return null;
final PsiBuilder.Marker marker = builder.mark();
marker.drop();
builder.advanceLexer();
if (isEnum) {
parseEnumConstants(builder);
}
parseClassBodyDeclarations(builder, isAnnotation);
expectOrError(builder, JavaTokenType.RBRACE, JavaErrorMessages.message("expected.rbrace"));
return marker;
}
@Nullable
private static PsiBuilder.Marker parseClassFromKeyword(final PsiBuilder builder, final PsiBuilder.Marker start,
final boolean isAnnotation) {
// todo: implement
throw new UnsupportedOperationException(builder.toString() + start + isAnnotation);
}
private static void parseEnumConstants(final PsiBuilder builder) {
while (builder.getTokenType() != null) {
if (expect(builder, JavaTokenType.SEMICOLON)) {
return;
}
if (builder.getTokenType() == JavaTokenType.PRIVATE_KEYWORD || builder.getTokenType() == JavaTokenType.PROTECTED_KEYWORD) {
error(builder, JavaErrorMessages.message("expected.semicolon"));
return;
}
final PsiBuilder.Marker enumConstant = parseEnumConstant(builder);
if (enumConstant == null) {
error(builder, JavaErrorMessages.message("expected.identifier"));
}
if (!expect(builder, JavaTokenType.COMMA)) {
if (builder.getTokenType() != null && builder.getTokenType() != JavaTokenType.SEMICOLON) {
error(builder, JavaErrorMessages.message("expected.comma.or.semicolon"));
}
}
}
}
@Nullable
private static PsiBuilder.Marker parseEnumConstant(final PsiBuilder builder) {
final PsiBuilder.Marker constant = builder.mark();
parseModifierList(builder);
if (expect(builder, JavaTokenType.IDENTIFIER)) {
if (builder.getTokenType() == JavaTokenType.LPARENTH) {
ExpressionParser.parseArgumentList(builder);
}
else {
emptyElement(builder, JavaElementType.EXPRESSION_LIST);
}
if (builder.getTokenType() == JavaTokenType.LBRACE) {
final PsiBuilder.Marker constantInit = builder.mark();
parseClassBodyWithBraces(builder, false, false);
constantInit.done(JavaElementType.ENUM_CONSTANT_INITIALIZER);
}
constant.done(JavaElementType.ENUM_CONSTANT);
return constant;
}
else {
constant.rollbackTo();
return null;
}
}
private static void parseClassBodyDeclarations(final PsiBuilder builder, final boolean isAnnotation) {
final Context context = isAnnotation ? Context.ANNOTATION_INTERFACE : Context.CLASS;
PsiBuilder.Marker invalidElements = null;
while (true) {
final IElementType tokenType = builder.getTokenType();
if (tokenType == null || tokenType == JavaTokenType.RBRACE) break;
if (tokenType == JavaTokenType.SEMICOLON) {
if (invalidElements != null) {
invalidElements.error(JavaErrorMessages.message("unexpected.token"));
invalidElements = null;
}
builder.advanceLexer();
continue;
}
final PsiBuilder.Marker declaration = parseDeclaration(builder, context);
if (declaration != null) {
if (invalidElements != null) {
invalidElements.errorBefore(JavaErrorMessages.message("unexpected.token"), declaration);
invalidElements = null;
}
continue;
}
if (invalidElements == null) {
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.advanceLexer();
}
}
if (invalidElements != null) {
invalidElements.error(JavaErrorMessages.message("unexpected.token"));
}
}
@Nullable
private static PsiBuilder.Marker parseDeclaration(final PsiBuilder builder, final Context context) {
final IElementType tokenType = builder.getTokenType();
if (tokenType == null) return null;
if (tokenType == JavaTokenType.LBRACE) {
if (context == Context.FILE || context == Context.CODE_BLOCK) return null;
}
else if (tokenType == JavaTokenType.IDENTIFIER || ElementType.PRIMITIVE_TYPE_BIT_SET.contains(tokenType)) {
if (context == Context.FILE) return null;
}
else if (tokenType instanceof ILazyParseableElementType) {
final PsiBuilder.Marker declaration = builder.mark();
declaration.drop();
builder.advanceLexer();
return declaration;
}
else if (!ElementType.MODIFIER_BIT_SET.contains(tokenType) &&
!ElementType.CLASS_KEYWORD_BIT_SET.contains(tokenType) &&
tokenType != JavaTokenType.AT &&
(context == Context.CODE_BLOCK || tokenType != JavaTokenType.LT)) {
return null;
}
final PsiBuilder.Marker declaration = builder.mark();
final PsiBuilder.Marker modList = parseModifierList(builder);
if (expect(builder, JavaTokenType.AT)) {
if (tokenType == JavaTokenType.INTERFACE_KEYWORD) {
return parseClassFromKeyword(builder, declaration, true);
}
else {
declaration.rollbackTo();
return null;
}
}
else if (ElementType.CLASS_KEYWORD_BIT_SET.contains(tokenType)) {
final PsiBuilder.Marker root = parseClassFromKeyword(builder, declaration, false);
if (context == Context.FILE) {
// todo: append following declarations to root
boolean declarationsAfterEnd = false;
while (builder.getTokenType() != null && builder.getTokenType() != JavaTokenType.RBRACE) {
final PsiBuilder.Marker position = builder.mark();
final PsiBuilder.Marker element = parseDeclaration(builder, Context.CLASS);
if (element != null && AFTER_END_DECLARATION_SET.contains(((LighterASTNode)element).getTokenType())) {
if (!declarationsAfterEnd) {
element.precede().error(JavaErrorMessages.message("expected.class.or.interface"));
}
declarationsAfterEnd = true;
position.drop();
}
else {
position.rollbackTo();
break;
}
}
if (declarationsAfterEnd) {
expectOrError(builder, JavaTokenType.RBRACE, JavaErrorMessages.message("expected.rbrace"));
}
}
return root;
}
PsiBuilder.Marker typeParams = null;
if (builder.getTokenType() == JavaTokenType.LT) {
typeParams = ReferenceParser.parseTypeParameters(builder);
}
if (context == Context.FILE) {
if (typeParams == null) {
error(builder, JavaErrorMessages.message("expected.class.or.interface"));
}
else {
typeParams.precede().errorBefore(JavaErrorMessages.message("expected.class.or.interface"), typeParams);
}
declaration.drop();
return modList;
}
// todo: implement
throw new UnsupportedOperationException(builder.toString() + context);
}
@NotNull
private static PsiBuilder.Marker parseModifierList(final PsiBuilder builder) {
final PsiBuilder.Marker modList = builder.mark();
while (true) {
final IElementType tokenType = builder.getTokenType();
if (tokenType == null) break;
if (ElementType.MODIFIER_BIT_SET.contains(tokenType)) {
builder.advanceLexer();
}
else if (tokenType == JavaTokenType.AT) {
final PsiBuilder.Marker pos = builder.mark();
builder.advanceLexer();
final IElementType nextTokenType = builder.getTokenType();
pos.rollbackTo();
if (ElementType.KEYWORD_BIT_SET.contains(nextTokenType)) {
break;
}
parseAnnotation(builder);
}
else {
break;
}
}
modList.done(JavaElementType.MODIFIER_LIST);
return modList;
}
@Nullable
public static PsiBuilder.Marker parseAnnotations(final PsiBuilder builder) {
PsiBuilder.Marker firstAnno = null;
while (builder.getTokenType() == JavaTokenType.AT) {
final PsiBuilder.Marker anno = parseAnnotation(builder);
if (firstAnno == null) firstAnno = anno;
}
return firstAnno;
}
@NotNull
private static PsiBuilder.Marker parseAnnotation(final PsiBuilder builder) {
final PsiBuilder.Marker anno = builder.mark();
builder.advanceLexer();
final PsiBuilder.Marker classRef = ReferenceParser.parseJavaCodeReference(builder, true, false, false);
if (classRef == null) {
error(builder, JavaErrorMessages.message("expected.class.reference"));
}
parseAnnotationParameterList(builder);
anno.done(JavaElementType.ANNOTATION);
return anno;
}
@NotNull
private static PsiBuilder.Marker parseAnnotationParameterList(final PsiBuilder builder) {
PsiBuilder.Marker list = builder.mark();
if (!expect(builder, JavaTokenType.LPARENTH)) {
list.done(JavaElementType.ANNOTATION_PARAMETER_LIST);
return list;
}
if (expect(builder, JavaTokenType.RPARENTH)) {
list.done(JavaElementType.ANNOTATION_PARAMETER_LIST);
return list;
}
final boolean isFirstParamNamed = parseAnnotationParameter(builder, true);
boolean isFirstParamWarned = false;
boolean afterBad = false;
while (true) {
final IElementType tokenType = builder.getTokenType();
if (tokenType == null) {
error(builder, JavaErrorMessages.message("expected.parameter"));
break;
}
else if (expect(builder, JavaTokenType.RPARENTH)) {
break;
}
else if (tokenType == JavaTokenType.COMMA) {
final PsiBuilder.Marker errorStart = builder.mark();
final PsiBuilder.Marker errorEnd = builder.mark();
builder.advanceLexer();
final boolean hasParamName = parseAnnotationParameter(builder, false);
if (!isFirstParamNamed && hasParamName && !isFirstParamWarned) {
errorStart.errorBefore(JavaErrorMessages.message("annotation.name.is.missing"), errorEnd);
isFirstParamWarned = true;
}
else {
errorStart.drop();
}
errorEnd.drop();
}
else if (!afterBad) {
error(builder, JavaErrorMessages.message("expected.comma.or.rparen"));
builder.advanceLexer();
afterBad = true;
}
else {
afterBad = false;
parseAnnotationParameter(builder, false);
}
}
list.done(JavaElementType.ANNOTATION_PARAMETER_LIST);
return list;
}
private static boolean parseAnnotationParameter(final PsiBuilder builder, final boolean mayBeSimple) {
PsiBuilder.Marker pair = builder.mark();
if (mayBeSimple) {
final PsiBuilder.Marker value = parseAnnotationValue(builder);
if (value != null && builder.getTokenType() != JavaTokenType.EQ) {
pair.done(JavaElementType.NAME_VALUE_PAIR);
return false;
}
pair.rollbackTo();
pair = builder.mark();
}
final boolean hasName = expectOrError(builder, JavaTokenType.IDENTIFIER, JavaErrorMessages.message("expected.identifier"));
expectOrError(builder, JavaTokenType.EQ, JavaErrorMessages.message("expected.eq"));
parseAnnotationValue(builder);
pair.done(JavaElementType.NAME_VALUE_PAIR);
return hasName;
}
@Nullable
private static PsiBuilder.Marker parseAnnotationValue(final PsiBuilder builder) {
final PsiBuilder.Marker result;
final IElementType tokenType = builder.getTokenType();
if (tokenType == JavaTokenType.AT) {
result = parseAnnotation(builder);
}
else if (tokenType == JavaTokenType.LBRACE) {
result = parseAnnotationArrayInitializer(builder);
}
else {
result = ExpressionParser.parseConditional(builder);
}
if (result == null) {
error(builder, JavaErrorMessages.message("expected.value"));
}
return result;
}
@NotNull
private static PsiBuilder.Marker parseAnnotationArrayInitializer(final PsiBuilder builder) {
final PsiBuilder.Marker annoArray = builder.mark();
builder.advanceLexer();
if (expect(builder, JavaTokenType.RBRACE)) {
annoArray.done(JavaElementType.ANNOTATION_ARRAY_INITIALIZER);
return annoArray;
}
parseAnnotationValue(builder);
while (true) {
if (expect(builder, JavaTokenType.RBRACE)) {
break;
}
else if (expect(builder, JavaTokenType.COMMA)) {
parseAnnotationValue(builder);
}
else {
error(builder, JavaErrorMessages.message("expected.rbrace"));
break;
}
}
annoArray.done(JavaElementType.ANNOTATION_ARRAY_INITIALIZER);
return annoArray;
}
}
@@ -0,0 +1,852 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.java.parser;
import com.intellij.codeInsight.daemon.JavaErrorMessages;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.PsiBuilderUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.TokenType;
import com.intellij.psi.impl.source.tree.ElementType;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.lang.java.parser.JavaParserUtil.areTypeAnnotationsSupported;
import static com.intellij.lang.java.parser.JavaParserUtil.error;
public class ExpressionParser {
private static final Logger LOG = Logger.getInstance("#com.intellij.lang.java.parser.ExpressionParser");
private enum ExprType {
CONDITIONAL_OR, CONDITIONAL_AND, OR, XOR, AND, EQUALITY, RELATIONAL, SHIFT, ADDITIVE, MULTIPLICATIVE, UNARY, TYPE
}
private static final TokenSet ASSIGNMENT_OPS = TokenSet.create(
JavaTokenType.EQ, JavaTokenType.ASTERISKEQ, JavaTokenType.DIVEQ, JavaTokenType.PERCEQ, JavaTokenType.PLUSEQ, JavaTokenType.MINUSEQ,
JavaTokenType.LTLTEQ, JavaTokenType.GTGTEQ, JavaTokenType.GTGTGTEQ, JavaTokenType.ANDEQ, JavaTokenType.OREQ, JavaTokenType.XOREQ);
private static final TokenSet RELATIONAL_OPS = TokenSet.create(JavaTokenType.LT, JavaTokenType.GT, JavaTokenType.LE, JavaTokenType.GE);
private static final TokenSet POSTFIX_OPS = TokenSet.create(JavaTokenType.PLUSPLUS, JavaTokenType.MINUSMINUS);
private static final TokenSet PREF_ARITHMETIC_OPS = TokenSet.orSet(POSTFIX_OPS, TokenSet.create(JavaTokenType.PLUS, JavaTokenType.MINUS));
private static final TokenSet PREFIX_OPS = TokenSet.orSet(PREF_ARITHMETIC_OPS, TokenSet.create(JavaTokenType.TILDE, JavaTokenType.EXCL));
private static final TokenSet LITERALS = TokenSet.create(
JavaTokenType.TRUE_KEYWORD, JavaTokenType.FALSE_KEYWORD, JavaTokenType.NULL_KEYWORD, JavaTokenType.INTEGER_LITERAL,
JavaTokenType.LONG_LITERAL, JavaTokenType.FLOAT_LITERAL, JavaTokenType.DOUBLE_LITERAL, JavaTokenType.CHARACTER_LITERAL,
JavaTokenType.STRING_LITERAL);
private static final TokenSet CONDITIONAL_OR_OPS = TokenSet.create(JavaTokenType.OROR);
private static final TokenSet CONDITIONAL_AND_OPS = TokenSet.create(JavaTokenType.ANDAND);
private static final TokenSet OR_OPS = TokenSet.create(JavaTokenType.OR);
private static final TokenSet XOR_OPS = TokenSet.create(JavaTokenType.XOR);
private static final TokenSet AND_OPS = TokenSet.create(JavaTokenType.AND);
private static final TokenSet EQUALITY_OPS = TokenSet.create(JavaTokenType.EQEQ, JavaTokenType.NE);
private static final TokenSet SHIFT_OPS = TokenSet.create(JavaTokenType.LTLT, JavaTokenType.GTGT, JavaTokenType.GTGTGT);
private static final TokenSet ADDITIVE_OPS = TokenSet.create(JavaTokenType.PLUS, JavaTokenType.MINUS);
private static final TokenSet MULTIPLICATIVE_OPS = TokenSet.create(JavaTokenType.ASTERISK, JavaTokenType.DIV, JavaTokenType.PERC);
private static final TokenSet ARGS_LIST_END = TokenSet.create(JavaTokenType.RPARENTH, JavaTokenType.RBRACE, JavaTokenType.RBRACKET);
private static final TokenSet ARGS_LIST_CONTINUE = TokenSet.create(
JavaTokenType.IDENTIFIER, TokenType.BAD_CHARACTER, JavaTokenType.COMMA, JavaTokenType.INTEGER_LITERAL, JavaTokenType.STRING_LITERAL);
private ExpressionParser() { }
@Nullable
public static PsiBuilder.Marker parse(final PsiBuilder builder) {
return parseAssignment(builder);
}
@Nullable
private static PsiBuilder.Marker parseAssignment(final PsiBuilder builder) {
final PsiBuilder.Marker left = parseConditional(builder);
if (left == null) return null;
final IElementType tokenType = getGtTokenType(builder);
if (ASSIGNMENT_OPS.contains(tokenType)) {
final PsiBuilder.Marker assignment = left.precede();
advanceGtToken(builder, tokenType);
final PsiBuilder.Marker right = parse(builder);
if (right == null) {
error(builder, JavaErrorMessages.message("expected.expression"));
}
assignment.done(JavaElementType.ASSIGNMENT_EXPRESSION);
return assignment;
}
return left;
}
@Nullable
public static PsiBuilder.Marker parseConditional(final PsiBuilder builder) {
final PsiBuilder.Marker condition = parseExpression(builder, ExprType.CONDITIONAL_OR);
if (condition == null) return null;
if (builder.getTokenType() != JavaTokenType.QUEST) return condition;
final PsiBuilder.Marker ternary = condition.precede();
builder.advanceLexer();
final PsiBuilder.Marker truePart = parse(builder);
if (truePart == null) {
error(builder, JavaErrorMessages.message("expected.expression"));
ternary.done(JavaElementType.CONDITIONAL_EXPRESSION);
return ternary;
}
if (builder.getTokenType() != JavaTokenType.COLON) {
error(builder, JavaErrorMessages.message("expected.colon"));
ternary.done(JavaElementType.CONDITIONAL_EXPRESSION);
return ternary;
}
builder.advanceLexer();
final PsiBuilder.Marker falsePart = parseConditional(builder);
if (falsePart == null) {
error(builder, JavaErrorMessages.message("expected.expression"));
ternary.done(JavaElementType.CONDITIONAL_EXPRESSION);
return ternary;
}
ternary.done(JavaElementType.CONDITIONAL_EXPRESSION);
return ternary;
}
@Nullable
private static PsiBuilder.Marker parseExpression(final PsiBuilder builder, final ExprType type) {
switch (type) {
case CONDITIONAL_OR:
return parseBinary(builder, ExprType.CONDITIONAL_AND, CONDITIONAL_OR_OPS);
case CONDITIONAL_AND:
return parseBinary(builder, ExprType.OR, CONDITIONAL_AND_OPS);
case OR:
return parseBinary(builder, ExprType.XOR, OR_OPS);
case XOR:
return parseBinary(builder, ExprType.AND, XOR_OPS);
case AND:
return parseBinary(builder, ExprType.EQUALITY, AND_OPS);
case EQUALITY:
return parseBinary(builder, ExprType.RELATIONAL, EQUALITY_OPS);
case RELATIONAL:
return parseRelational(builder);
case SHIFT:
return parseBinary(builder, ExprType.ADDITIVE, SHIFT_OPS);
case ADDITIVE:
return parseBinary(builder, ExprType.MULTIPLICATIVE, ADDITIVE_OPS);
case MULTIPLICATIVE:
return parseBinary(builder, ExprType.UNARY, MULTIPLICATIVE_OPS);
case UNARY:
return parseUnary(builder);
case TYPE:
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseType(builder);
return typeInfo != null ? typeInfo.marker : null;
default:
LOG.error("Unexpected type: " + type);
return null;
}
}
@Nullable
private static PsiBuilder.Marker parseBinary(final PsiBuilder builder, final ExprType type, final TokenSet ops) {
PsiBuilder.Marker left = parseExpression(builder, type);
if (left == null) return null;
while (true) {
final IElementType tokenType = getGtTokenType(builder);
if (tokenType == null || !ops.contains(tokenType)) break;
final PsiBuilder.Marker binary = left.precede();
advanceGtToken(builder, tokenType);
final PsiBuilder.Marker right = parseExpression(builder, type);
if (right == null) {
error(builder, JavaErrorMessages.message("expected.expression"));
binary.done(JavaElementType.BINARY_EXPRESSION);
return binary;
}
binary.done(JavaElementType.BINARY_EXPRESSION);
left = binary;
}
return left;
}
@Nullable
private static PsiBuilder.Marker parseRelational(final PsiBuilder builder) {
PsiBuilder.Marker left = parseExpression(builder, ExprType.SHIFT);
if (left == null) return null;
while (true) {
final IElementType toCreate;
final ExprType toParse;
final IElementType tokenType = getGtTokenType(builder);
if (RELATIONAL_OPS.contains(tokenType)) {
toCreate = JavaElementType.BINARY_EXPRESSION;
toParse = ExprType.SHIFT;
}
else if (tokenType == JavaTokenType.INSTANCEOF_KEYWORD) {
toCreate = JavaElementType.INSTANCE_OF_EXPRESSION;
toParse = ExprType.TYPE;
}
else {
break;
}
final PsiBuilder.Marker expression = left.precede();
builder.advanceLexer();
final PsiBuilder.Marker right = parseExpression(builder, toParse);
if (right == null) {
error(builder, toParse == ExprType.TYPE ?
JavaErrorMessages.message("expected.type") : JavaErrorMessages.message("expected.expression"));
expression.done(toCreate);
return expression;
}
expression.done(toCreate);
left = expression;
}
return left;
}
@Nullable
private static PsiBuilder.Marker parseUnary(final PsiBuilder builder) {
final IElementType tokenType = builder.getTokenType();
if (PREFIX_OPS.contains(tokenType)) {
final PsiBuilder.Marker unary = builder.mark();
builder.advanceLexer();
final PsiBuilder.Marker operand = parseUnary(builder);
if (operand == null) {
error(builder, JavaErrorMessages.message("expected.expression"));
}
unary.done(JavaElementType.PREFIX_EXPRESSION);
return unary;
}
else if (tokenType == JavaTokenType.LPARENTH) {
final PsiBuilder.Marker typeCast = builder.mark();
builder.advanceLexer();
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseType(builder);
if (typeInfo == null || builder.getTokenType() != JavaTokenType.RPARENTH) {
typeCast.rollbackTo();
return parsePostfix(builder);
}
builder.advanceLexer();
if (PREF_ARITHMETIC_OPS.contains(builder.getTokenType())) {
if (!typeInfo.isPrimitive) {
typeCast.rollbackTo();
return parsePostfix(builder);
}
}
final PsiBuilder.Marker expr = parseUnary(builder);
if (expr == null) {
if (!typeInfo.isParameterized) {
typeCast.rollbackTo();
return parsePostfix(builder);
}
else {
error(builder, JavaErrorMessages.message("expected.expression"));
}
}
typeCast.done(JavaElementType.TYPE_CAST_EXPRESSION);
return typeCast;
}
else {
return parsePostfix(builder);
}
}
@Nullable
private static PsiBuilder.Marker parsePostfix(final PsiBuilder builder) {
PsiBuilder.Marker operand = parsePrimary(builder, false);
if (operand == null) return null;
while (POSTFIX_OPS.contains(builder.getTokenType())) {
final PsiBuilder.Marker postfix = operand.precede();
builder.advanceLexer();
postfix.done(JavaElementType.POSTFIX_EXPRESSION);
operand = postfix;
}
return operand;
}
@Nullable
private static PsiBuilder.Marker parsePrimary(final PsiBuilder builder, final boolean planB) {
PsiBuilder.Marker startMarker = builder.mark();
final Pair<PsiBuilder.Marker, IElementType> exprTypePair = parsePrimaryExpressionStart(builder);
if (exprTypePair == null) {
startMarker.drop();
return null;
}
PsiBuilder.Marker expr = exprTypePair.first;
IElementType exprType = exprTypePair.second;
while (true) {
final IElementType tokenType = builder.getTokenType();
if (tokenType == JavaTokenType.DOT) {
final PsiBuilder.Marker dotPos = builder.mark();
builder.advanceLexer();
final IElementType dotTokenType = builder.getTokenType();
if (dotTokenType == JavaTokenType.CLASS_KEYWORD && exprType == JavaElementType.REFERENCE_EXPRESSION) {
if (planB) {
error(builder, JavaErrorMessages.message("expected.identifier"));
PsiBuilderUtil.drop(startMarker, dotPos);
return expr;
}
final PsiBuilder.Marker copy = startMarker.precede();
startMarker.rollbackTo();
final PsiBuilder.Marker classObjAccess = parseClassObjectAccess(builder);
if (classObjAccess == null) {
copy.rollbackTo();
return parsePrimary(builder, true);
}
startMarker = copy;
expr = classObjAccess;
exprType = JavaElementType.CLASS_OBJECT_ACCESS_EXPRESSION;
}
else if (dotTokenType == JavaTokenType.NEW_KEYWORD) {
dotPos.drop();
expr = parseNew(builder, expr);
exprType = JavaElementType.NEW_EXPRESSION;
}
else if ((dotTokenType == JavaTokenType.THIS_KEYWORD || dotTokenType == JavaTokenType.SUPER_KEYWORD) &&
exprType == JavaElementType.REFERENCE_EXPRESSION) {
if (planB) {
dotPos.rollbackTo();
startMarker.drop();
return expr;
}
final PsiBuilder.Marker copy = startMarker.precede();
startMarker.rollbackTo();
final PsiBuilder.Marker ref = ReferenceParser.parseJavaCodeReference(builder, false, true, false);
if (ref == null || builder.getTokenType() != JavaTokenType.DOT) {
copy.rollbackTo();
return parsePrimary(builder, true);
}
builder.advanceLexer();
if (builder.getTokenType() != dotTokenType) {
copy.rollbackTo();
return parsePrimary(builder, true);
}
builder.advanceLexer();
startMarker = copy;
exprType = dotTokenType == JavaTokenType.THIS_KEYWORD ? JavaElementType.THIS_EXPRESSION : JavaElementType.SUPER_EXPRESSION;
expr = ref.precede();
expr.done(exprType);
}
else if (dotTokenType == JavaTokenType.SUPER_KEYWORD) {
dotPos.drop();
final PsiBuilder.Marker refExpr = expr.precede();
builder.advanceLexer();
refExpr.done(exprType = JavaElementType.REFERENCE_EXPRESSION);
expr = refExpr;
}
else {
dotPos.drop();
final PsiBuilder.Marker refExpr = expr.precede();
ReferenceParser.parseReferenceParameterList(builder, false);
if (!JavaParserUtil.expectOrError(builder, JavaTokenType.IDENTIFIER, JavaErrorMessages.message("expected.identifier"))) {
refExpr.done(JavaElementType.REFERENCE_EXPRESSION);
startMarker.drop();
return refExpr;
}
refExpr.done(exprType = JavaElementType.REFERENCE_EXPRESSION);
expr = refExpr;
}
}
else if (tokenType == JavaTokenType.LPARENTH) {
if (exprType != JavaElementType.REFERENCE_EXPRESSION) {
if (exprType == JavaElementType.SUPER_EXPRESSION) {
if (planB) {
startMarker.drop();
return expr;
}
final PsiBuilder.Marker copy = startMarker.precede();
startMarker.rollbackTo();
final Pair<PsiBuilder.Marker, IElementType> qualifier = parsePrimaryExpressionStart(builder);
if (qualifier != null) {
final PsiBuilder.Marker refExpr = qualifier.first.precede();
if (builder.getTokenType() == JavaTokenType.DOT) {
builder.advanceLexer();
if (builder.getTokenType() == JavaTokenType.SUPER_KEYWORD) {
builder.advanceLexer();
refExpr.done(exprType = JavaElementType.REFERENCE_EXPRESSION);
expr = refExpr;
startMarker = copy;
continue;
}
}
}
copy.rollbackTo();
return parsePrimary(builder, true);
}
else {
startMarker.drop();
return expr;
}
}
final PsiBuilder.Marker callExpr = expr.precede();
parseArgumentList(builder);
callExpr.done(exprType = JavaElementType.METHOD_CALL_EXPRESSION);
expr = callExpr;
}
else if (tokenType == JavaTokenType.LBRACKET) {
if (planB) {
startMarker.drop();
return expr;
}
builder.advanceLexer();
if (builder.getTokenType() == JavaTokenType.RBRACKET && exprType == JavaElementType.REFERENCE_EXPRESSION) {
final PsiBuilder.Marker copy = startMarker.precede();
startMarker.rollbackTo();
final PsiBuilder.Marker classObjAccess = parseClassObjectAccess(builder);
if (classObjAccess == null) {
copy.rollbackTo();
return parsePrimary(builder, true);
}
startMarker = copy;
expr = classObjAccess;
exprType = JavaElementType.CLASS_OBJECT_ACCESS_EXPRESSION;
}
else {
final PsiBuilder.Marker arrayAccess = expr.precede();
final PsiBuilder.Marker index = parse(builder);
if (index == null) {
error(builder, JavaErrorMessages.message("expected.expression"));
arrayAccess.done(JavaElementType.ARRAY_ACCESS_EXPRESSION);
startMarker.drop();
return arrayAccess;
}
if (builder.getTokenType() != JavaTokenType.RBRACKET) {
error(builder, JavaErrorMessages.message("expected.rbracket"));
arrayAccess.done(JavaElementType.ARRAY_ACCESS_EXPRESSION);
startMarker.drop();
return arrayAccess;
}
builder.advanceLexer();
arrayAccess.done(exprType = JavaElementType.ARRAY_ACCESS_EXPRESSION);
expr = arrayAccess;
}
}
else {
startMarker.drop();
return expr;
}
}
}
@Nullable
private static Pair<PsiBuilder.Marker, IElementType> parsePrimaryExpressionStart(final PsiBuilder builder) {
IElementType tokenType = builder.getTokenType();
if (LITERALS.contains(tokenType)) {
final PsiBuilder.Marker literal = builder.mark();
builder.advanceLexer();
literal.done(JavaElementType.LITERAL_EXPRESSION);
return Pair.create(literal, JavaElementType.LITERAL_EXPRESSION);
}
if (tokenType == JavaTokenType.LPARENTH) {
final PsiBuilder.Marker parenth = builder.mark();
builder.advanceLexer();
final PsiBuilder.Marker inner = parse(builder);
if (inner == null) {
error(builder, JavaErrorMessages.message("expected.expression"));
}
JavaParserUtil.expectOrError(builder, JavaTokenType.RPARENTH, JavaErrorMessages.message("expected.rparen"));
parenth.done(JavaElementType.PARENTH_EXPRESSION);
return Pair.create(parenth, JavaElementType.PARENTH_EXPRESSION);
}
if (tokenType == JavaTokenType.LBRACE) {
final PsiBuilder.Marker arrayInit = parseArrayInitializer(builder);
return arrayInit != null ? Pair.create(arrayInit, JavaElementType.ARRAY_INITIALIZER_EXPRESSION) : null;
}
PsiBuilder.Marker annotation = null;
final PsiBuilder.Marker beforeAnnotation = builder.mark();
if (tokenType == JavaTokenType.AT) {
annotation = DeclarationParser.parseAnnotations(builder);
tokenType = builder.getTokenType();
}
if (tokenType == JavaTokenType.IDENTIFIER) {
final PsiBuilder.Marker refExpr;
if (annotation != null) {
final PsiBuilder.Marker refParam = annotation.precede();
refParam.doneBefore(JavaElementType.REFERENCE_PARAMETER_LIST, annotation);
refExpr = refParam.precede();
}
else {
refExpr = builder.mark();
builder.mark().done(JavaElementType.REFERENCE_PARAMETER_LIST);
}
builder.advanceLexer();
refExpr.done(JavaElementType.REFERENCE_EXPRESSION);
beforeAnnotation.drop();
return Pair.create(refExpr, JavaElementType.REFERENCE_EXPRESSION);
}
if (annotation != null) {
beforeAnnotation.rollbackTo();
tokenType = builder.getTokenType();
}
else {
beforeAnnotation.drop();
}
if (tokenType == JavaTokenType.THIS_KEYWORD) {
final PsiBuilder.Marker expr = builder.mark();
builder.mark().done(JavaElementType.REFERENCE_PARAMETER_LIST);
builder.advanceLexer();
final IElementType type = builder.getTokenType() != JavaTokenType.LPARENTH ?
JavaElementType.THIS_EXPRESSION : JavaElementType.REFERENCE_EXPRESSION;
expr.done(type);
return Pair.create(expr, type);
}
if (tokenType == JavaTokenType.SUPER_KEYWORD) {
final PsiBuilder.Marker expr = builder.mark();
builder.mark().done(JavaElementType.REFERENCE_PARAMETER_LIST);
builder.advanceLexer();
final IElementType type = builder.getTokenType() != JavaTokenType.LPARENTH ?
JavaElementType.SUPER_EXPRESSION : JavaElementType.REFERENCE_EXPRESSION;
expr.done(type);
return Pair.create(expr, type);
}
if (tokenType == JavaTokenType.NEW_KEYWORD) {
final PsiBuilder.Marker newExpr = parseNew(builder, null);
return Pair.create(newExpr, JavaElementType.NEW_EXPRESSION);
}
if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(tokenType)) {
final PsiBuilder.Marker classObjAccess = parseClassObjectAccess(builder);
return classObjAccess != null ? Pair.create(classObjAccess, JavaElementType.CLASS_OBJECT_ACCESS_EXPRESSION) : null;
}
return null;
}
@Nullable
private static PsiBuilder.Marker parseArrayInitializer(final PsiBuilder builder) {
if (builder.getTokenType() != JavaTokenType.LBRACE) return null;
final PsiBuilder.Marker arrayInit = builder.mark();
builder.advanceLexer();
boolean expressionMissed = false;
PsiBuilder.Marker lastComma = null;
while (true) {
if (builder.getTokenType() == JavaTokenType.RBRACE) {
builder.advanceLexer();
break;
}
if (builder.getTokenType() == null) {
error(builder, JavaErrorMessages.message("expected.rbrace"));
break;
}
if (expressionMissed && lastComma != null) {
// before comma must be an expression
lastComma.precede().errorBefore(JavaErrorMessages.message("expected.expression"), lastComma);
lastComma.drop();
lastComma = null;
}
final PsiBuilder.Marker arg = parse(builder);
if (arg == null) {
if (builder.getTokenType() == JavaTokenType.COMMA) {
expressionMissed = true;
lastComma = builder.mark();
}
else {
error(builder, JavaErrorMessages.message("expected.rbrace"));
break;
}
}
final IElementType tokenType = builder.getTokenType();
if (tokenType == JavaTokenType.COMMA) {
builder.advanceLexer();
}
else if (tokenType != JavaTokenType.RBRACE) {
error(builder, JavaErrorMessages.message("expected.comma"));
}
}
if (lastComma != null) {
lastComma.drop();
}
arrayInit.done(JavaElementType.ARRAY_INITIALIZER_EXPRESSION);
return arrayInit;
}
@NotNull
private static PsiBuilder.Marker parseNew(final PsiBuilder builder, final PsiBuilder.Marker start) {
final PsiBuilder.Marker newExpr = (start != null ? start.precede() : builder.mark());
builder.advanceLexer();
ReferenceParser.parseReferenceParameterList(builder, false);
final PsiBuilder.Marker refOrType;
final boolean parseAnnotations = areTypeAnnotationsSupported(builder) && builder.getTokenType() == JavaTokenType.AT;
final IElementType tokenType = builder.getTokenType();
if (tokenType == JavaTokenType.IDENTIFIER || parseAnnotations) {
refOrType = ReferenceParser.parseJavaCodeReference(builder, true, true, parseAnnotations);
if (refOrType == null) {
error(builder, JavaErrorMessages.message("expected.identifier"));
newExpr.done(JavaElementType.NEW_EXPRESSION);
return newExpr;
}
}
else if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(tokenType)) {
refOrType = null;
builder.advanceLexer();
}
else {
error(builder, JavaErrorMessages.message("expected.identifier"));
newExpr.done(JavaElementType.NEW_EXPRESSION);
return newExpr;
}
if (refOrType != null && builder.getTokenType() == JavaTokenType.LPARENTH) {
parseArgumentList(builder);
if (builder.getTokenType() == JavaTokenType.LBRACE) {
final PsiBuilder.Marker classElement = refOrType.precede();
DeclarationParser.parseClassBodyWithBraces(builder, false, false);
classElement.done(JavaElementType.ANONYMOUS_CLASS);
}
}
else {
if (builder.getTokenType() != JavaTokenType.LBRACKET) {
error(builder, refOrType == null ?
JavaErrorMessages.message("expected.lbracket") : JavaErrorMessages.message("expected.lparen.or.lbracket"));
newExpr.done(JavaElementType.NEW_EXPRESSION);
return newExpr;
}
int bracketCount = 0;
int dimCount = 0;
while (true) {
if (builder.getTokenType() != JavaTokenType.LBRACKET) break;
builder.advanceLexer();
if (bracketCount == dimCount) {
final PsiBuilder.Marker dimExpr = parse(builder);
if (dimExpr != null) {
dimCount++;
}
}
bracketCount++;
if (!JavaParserUtil.expectOrError(builder, JavaTokenType.RBRACKET, JavaErrorMessages.message("expected.rbracket"))) {
newExpr.done(JavaElementType.NEW_EXPRESSION);
return newExpr;
}
}
if (dimCount == 0) {
if (builder.getTokenType() == JavaTokenType.LBRACE) {
parseArrayInitializer(builder);
}
else {
error(builder, JavaErrorMessages.message("expected.array.initializer"));
}
}
}
newExpr.done(JavaElementType.NEW_EXPRESSION);
return newExpr;
}
@Nullable
private static PsiBuilder.Marker parseClassObjectAccess(final PsiBuilder builder) {
final PsiBuilder.Marker expr = builder.mark();
final PsiBuilder.Marker type = ReferenceParser.parseType(builder, false, false);
if (type == null) {
expr.drop();
return null;
}
if (builder.getTokenType() != JavaTokenType.DOT) {
expr.rollbackTo();
return null;
}
builder.advanceLexer();
if (builder.getTokenType() != JavaTokenType.CLASS_KEYWORD) {
expr.rollbackTo();
return null;
}
builder.advanceLexer();
expr.done(JavaElementType.CLASS_OBJECT_ACCESS_EXPRESSION);
return expr;
}
@NotNull
public static PsiBuilder.Marker parseArgumentList(final PsiBuilder builder) {
final PsiBuilder.Marker list = builder.mark();
builder.advanceLexer();
boolean first = true;
while (true) {
final IElementType tokenType = builder.getTokenType();
if (first && (ARGS_LIST_END.contains(tokenType) || builder.eof())) break;
if (!first && !ARGS_LIST_CONTINUE.contains(tokenType)) break;
boolean hasError = false;
if (!first) {
if (builder.getTokenType() == JavaTokenType.COMMA) {
builder.advanceLexer();
}
else {
hasError = true;
error(builder, JavaErrorMessages.message("expected.comma.or.rparen"));
emptyExpression(builder);
}
}
first = false;
final PsiBuilder.Marker arg = parse(builder);
if (arg == null) {
if (!hasError) {
error(builder, JavaErrorMessages.message("expected.expression"));
emptyExpression(builder);
}
if (!ARGS_LIST_CONTINUE.contains(builder.getTokenType())) break;
if (builder.getTokenType() != JavaTokenType.COMMA && !builder.eof()) {
builder.advanceLexer();
}
}
}
JavaParserUtil.expectOrError(builder, JavaTokenType.RPARENTH, JavaErrorMessages.message("expected.rparen"));
list.done(JavaElementType.EXPRESSION_LIST);
return list;
}
private static void emptyExpression(final PsiBuilder builder) {
builder.mark().done(JavaElementType.EMPTY_EXPRESSION);
}
@Nullable
private static IElementType getGtTokenType(final PsiBuilder builder) {
final PsiBuilder.Marker sp = builder.mark();
IElementType tokenType = builder.getTokenType();
if (tokenType == JavaTokenType.GT) {
builder.advanceLexer();
if (builder.getTokenType() == JavaTokenType.GT) {
builder.advanceLexer();
if (builder.getTokenType() == JavaTokenType.GT) {
builder.advanceLexer();
if (builder.getTokenType() == JavaTokenType.EQ) {
tokenType = JavaTokenType.GTGTGTEQ;
}
else {
tokenType = JavaTokenType.GTGTGT;
}
}
else if (builder.getTokenType() == JavaTokenType.EQ) {
tokenType = JavaTokenType.GTGTEQ;
}
else {
tokenType = JavaTokenType.GTGT;
}
}
}
sp.rollbackTo();
return tokenType;
}
private static void advanceGtToken(final PsiBuilder builder, final IElementType type) {
final PsiBuilder.Marker gtToken = builder.mark();
if (type == JavaTokenType.GTGTGTEQ) {
PsiBuilderUtil.advance(builder, 4);
}
else if (type == JavaTokenType.GTGTGT) {
PsiBuilderUtil.advance(builder, 3);
}
else if (type == JavaTokenType.GTGTEQ) {
PsiBuilderUtil.advance(builder, 3);
}
else if (type == JavaTokenType.GTGT) {
PsiBuilderUtil.advance(builder, 2);
}
else {
gtToken.drop();
builder.advanceLexer();
return;
}
gtToken.collapse(type);
}
}
@@ -0,0 +1,45 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.java.parser;
import com.intellij.lang.ASTNode;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.PsiParser;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import static com.intellij.lang.java.parser.JavaParserUtil.setLanguageLevel;
public class JavaParser implements PsiParser {
private final LanguageLevel myLanguageLevel;
public JavaParser(final LanguageLevel languageLevel) {
myLanguageLevel = languageLevel;
}
@NotNull
public ASTNode parse(final IElementType rootType, final PsiBuilder builder) {
final PsiBuilder.Marker root = builder.mark();
setLanguageLevel(builder, myLanguageLevel);
// parse
root.done(rootType);
return builder.getTreeBuilt();
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.java.parser;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.PsiBuilderUtil;
import com.intellij.openapi.util.Key;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
public class JavaParserUtil {
private static final Key<LanguageLevel> LANG_LEVEL_KEY = Key.create("JavaParserUtil.LanguageLevel");
private JavaParserUtil() { }
public static void setLanguageLevel(final PsiBuilder builder, final LanguageLevel level) {
builder.putUserData(LANG_LEVEL_KEY, level);
}
public static boolean areTypeAnnotationsSupported(final PsiBuilder builder) {
final LanguageLevel level = getLanguageLevel(builder);
return level.isAtLeast(LanguageLevel.JDK_1_7);
}
@NotNull
private static LanguageLevel getLanguageLevel(final PsiBuilder builder) {
final LanguageLevel level = builder.getUserData(LANG_LEVEL_KEY);
assert level != null;
return level;
}
// used instead of PsiBuilder.error() as it drops all but first subsequent error messages
public static void error(final PsiBuilder builder, final String message) {
builder.mark().error(message);
}
public static boolean expectOrError(final PsiBuilder builder, final IElementType expectedType, final String errorMessage) {
if (!PsiBuilderUtil.expect(builder, expectedType)) {
error(builder, errorMessage);
return false;
}
return true;
}
public static void emptyElement(final PsiBuilder builder, final IElementType type) {
builder.mark().done(type);
}
}
@@ -0,0 +1,294 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.java.parser;
import com.intellij.codeInsight.daemon.JavaErrorMessages;
import com.intellij.lang.PsiBuilder;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.impl.source.tree.ElementType;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.lang.PsiBuilderUtil.expect;
import static com.intellij.lang.PsiBuilderUtil.nextTokenType;
import static com.intellij.lang.java.parser.JavaParserUtil.*;
public class ReferenceParser {
public static class TypeInfo {
public boolean isPrimitive = false;
public boolean isParameterized = false;
public boolean isArray = false;
public PsiBuilder.Marker marker = null;
}
private static final TokenSet WILDCARD_KEYWORD_SET = TokenSet.create(JavaTokenType.EXTENDS_KEYWORD, JavaTokenType.SUPER_KEYWORD);
private ReferenceParser() { }
@Nullable
public static TypeInfo parseType(final PsiBuilder builder) {
return parseTypeWithInfo(builder, true, true);
}
@Nullable
public static PsiBuilder.Marker parseType(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard) {
final TypeInfo typeInfo = parseTypeWithInfo(builder, eatLastDot, wildcard);
return typeInfo != null ? typeInfo.marker : null;
}
@Nullable
private static TypeInfo parseTypeWithInfo(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard) {
if (builder.getTokenType() == null) return null;
final TypeInfo typeInfo = new TypeInfo();
final boolean annotationsSupported = areTypeAnnotationsSupported(builder);
PsiBuilder.Marker type = builder.mark();
if (annotationsSupported) {
DeclarationParser.parseAnnotations(builder);
}
final IElementType tokenType = builder.getTokenType();
if (expect(builder, ElementType.PRIMITIVE_TYPE_BIT_SET)) {
typeInfo.isPrimitive = true;
}
else if (tokenType == JavaTokenType.IDENTIFIER) {
parseJavaCodeReference(builder, eatLastDot, true, annotationsSupported, typeInfo);
}
else if (wildcard && tokenType == JavaTokenType.QUEST) {
type.drop();
typeInfo.marker = parseWildcardType(builder);
return typeInfo.marker != null ? typeInfo : null;
}
else {
type.drop();
return null;
}
while (true) {
if (annotationsSupported) {
DeclarationParser.parseAnnotations(builder);
}
type.done(JavaElementType.TYPE);
if (!expect(builder, JavaTokenType.LBRACKET)) {
break;
}
typeInfo.isArray = true;
if (!expectOrError(builder, JavaTokenType.RBRACKET, JavaErrorMessages.message("expected.rbracket"))) {
break;
}
type = type.precede();
}
typeInfo.marker = type;
return typeInfo;
}
@NotNull
private static PsiBuilder.Marker parseWildcardType(final PsiBuilder builder) {
final PsiBuilder.Marker type = builder.mark();
builder.advanceLexer();
if (expect(builder, WILDCARD_KEYWORD_SET)) {
final PsiBuilder.Marker boundType = parseType(builder, true, false);
if (boundType == null) {
error(builder, JavaErrorMessages.message("expected.type"));
}
}
type.done(JavaElementType.TYPE);
return type;
}
@Nullable
public static PsiBuilder.Marker parseJavaCodeReference(final PsiBuilder builder, final boolean eatLastDot,
final boolean parameterList, final boolean annotations) {
return parseJavaCodeReference(builder, eatLastDot, parameterList, annotations, new TypeInfo());
}
@Nullable
private static PsiBuilder.Marker parseJavaCodeReference(final PsiBuilder builder, final boolean eatLastDot,
final boolean parameterList, final boolean annotations,
final TypeInfo typeInfo) {
PsiBuilder.Marker refElement = builder.mark();
if (annotations) {
DeclarationParser.parseAnnotations(builder);
}
if (!expect(builder, JavaTokenType.IDENTIFIER)) {
refElement.rollbackTo();
return null;
}
if (parameterList) {
typeInfo.isParameterized = (builder.getTokenType() == JavaTokenType.LT);
parseReferenceParameterList(builder, true);
}
else {
emptyElement(builder, JavaElementType.REFERENCE_PARAMETER_LIST);
}
boolean hasIdentifier;
while (builder.getTokenType() == JavaTokenType.DOT) {
refElement.done(JavaElementType.JAVA_CODE_REFERENCE);
final PsiBuilder.Marker dotPos = builder.mark();
builder.advanceLexer();
if (expect(builder, JavaTokenType.IDENTIFIER)) {
hasIdentifier = true;
}
else {
if (!eatLastDot) {
dotPos.rollbackTo();
return refElement;
}
hasIdentifier = false;
}
dotPos.drop();
refElement = refElement.precede();
if (!hasIdentifier) {
error(builder, JavaErrorMessages.message("expected.identifier"));
break;
}
if (parameterList) {
typeInfo.isParameterized = (builder.getTokenType() == JavaTokenType.LT);
parseReferenceParameterList(builder, true);
}
else {
emptyElement(builder, JavaElementType.REFERENCE_PARAMETER_LIST);
}
}
refElement.done(JavaElementType.JAVA_CODE_REFERENCE);
return refElement;
}
@NotNull
public static PsiBuilder.Marker parseReferenceParameterList(final PsiBuilder builder, final boolean wildcard) {
final PsiBuilder.Marker list = builder.mark();
if (!expect(builder, JavaTokenType.LT)) {
list.done(JavaElementType.REFERENCE_PARAMETER_LIST);
return list;
}
while (true) {
final PsiBuilder.Marker type = parseType(builder, true, wildcard);
if (type == null) {
error(builder, JavaErrorMessages.message("expected.identifier"));
}
if (expect(builder, JavaTokenType.GT)) {
break;
}
else if (!expectOrError(builder, JavaTokenType.COMMA, JavaErrorMessages.message("expected.gt.or.comma"))) {
break;
}
}
list.done(JavaElementType.REFERENCE_PARAMETER_LIST);
return list;
}
@NotNull
public static PsiBuilder.Marker parseTypeParameters(final PsiBuilder builder) {
final PsiBuilder.Marker list = builder.mark();
if (!expect(builder, JavaTokenType.LT)) {
list.done(JavaElementType.TYPE_PARAMETER_LIST);
return list;
}
while (true) {
final PsiBuilder.Marker param = parseTypeParameter(builder);
if (param == null) {
error(builder, JavaErrorMessages.message("expected.type.parameter"));
}
if (!expect(builder, JavaTokenType.COMMA)) {
break;
}
}
if (!expect(builder, JavaTokenType.GT)) {
// hack for completion
if (builder.getTokenType() == JavaTokenType.IDENTIFIER) {
if (nextTokenType(builder) == JavaTokenType.GT) {
final PsiBuilder.Marker errorElement = builder.mark();
builder.advanceLexer();
errorElement.error(JavaErrorMessages.message("unexpected.identifier"));
builder.advanceLexer();
}
else {
error(builder, JavaErrorMessages.message("expected.gt"));
}
}
else {
error(builder, JavaErrorMessages.message("expected.gt"));
}
}
list.done(JavaElementType.TYPE_PARAMETER_LIST);
return list;
}
@Nullable
private static PsiBuilder.Marker parseTypeParameter(final PsiBuilder builder) {
final PsiBuilder.Marker param = builder.mark();
DeclarationParser.parseAnnotations(builder);
if (!expect(builder, JavaTokenType.IDENTIFIER)) {
param.rollbackTo();
return null;
}
if (expect(builder, JavaTokenType.EXTENDS_KEYWORD)) {
parseReferenceList(builder, JavaElementType.EXTENDS_BOUND_LIST, JavaTokenType.AND);
}
else {
emptyElement(builder, JavaElementType.EXTENDS_BOUND_LIST);
}
param.done(JavaElementType.TYPE_PARAMETER);
return param;
}
@NotNull
private static PsiBuilder.Marker parseReferenceList(final PsiBuilder builder, 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;
}
}
element.done(type);
return element;
}
}
@@ -42,7 +42,7 @@ import java.io.IOException;
public class JavaClassReferenceListElementType extends JavaStubElementType<PsiClassReferenceListStub, PsiReferenceList> {
public JavaClassReferenceListElementType(@NotNull @NonNls String id) {
super(id);
super(id, true);
}
public PsiReferenceList createPsi(final PsiClassReferenceListStub stub) {
@@ -29,8 +29,15 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public abstract class JavaStubElementType<StubT extends StubElement, PsiT extends PsiElement> extends IStubElementType<StubT, PsiT> {
private final boolean myLeftBound;
protected JavaStubElementType(@NotNull @NonNls final String debugName) {
this(debugName, false);
}
protected JavaStubElementType(@NotNull @NonNls final String debugName, final boolean leftBound) {
super(debugName, StdFileTypes.JAVA != null ? StdFileTypes.JAVA.getLanguage() : null);
myLeftBound = leftBound;
}
public String getExternalId() {
@@ -47,4 +54,9 @@ public abstract class JavaStubElementType<StubT extends StubElement, PsiT extend
}
public abstract PsiT createPsi(ASTNode node);
@Override
public boolean isLeftBound() {
return myLeftBound;
}
}
@@ -69,7 +69,7 @@ public interface JavaElementType {
IElementType IMPORT_STATIC_REFERENCE = new IJavaElementType("IMPORT_STATIC_REFERENCE");
IElementType TYPE = new IJavaElementType("TYPE");
IElementType REFERENCE_PARAMETER_LIST = new IJavaElementType("REFERENCE_PARAMETER_LIST");
IElementType REFERENCE_PARAMETER_LIST = new IJavaElementType("REFERENCE_PARAMETER_LIST", true);
IElementType JAVA_CODE_REFERENCE = new IJavaElementType("JAVA_CODE_REFERENCE");
IElementType PACKAGE_STATEMENT = new IJavaElementType("PACKAGE_STATEMENT");
@@ -120,7 +120,7 @@ public interface JavaElementType {
IElementType ANNOTATION_ARRAY_INITIALIZER = new IJavaElementType("ANNOTATION_ARRAY_INITIALIZER");
IElementType NAME_VALUE_PAIR = new IJavaElementType("NAME_VALUE_PAIR");
IElementType ANNOTATION_PARAMETER_LIST = new IJavaElementType("ANNOTATION_PARAMETER_LIST");
IElementType ANNOTATION_PARAMETER_LIST = new IJavaElementType("ANNOTATION_PARAMETER_LIST", true);
IElementType METHOD_RECEIVER = new IJavaElementType("METHOD_RECEIVER");
ILazyParseableElementType CODE_BLOCK = new IErrorCounterReparseableElementType("CODE_BLOCK", StdLanguages.JAVA) {
+1 -1
View File
@@ -3,7 +3,7 @@
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
@@ -0,0 +1,20 @@
PsiJavaFile:Array.java
PsiAnnotation
PsiJavaToken:AT('@')
PsiJavaCodeReferenceElement:Endorsers
PsiIdentifier:Endorsers('Endorsers')
PsiReferenceParameterList
<empty list>
PsiAnnotationParameterList
PsiJavaToken:LPARENTH('(')
PsiNameValuePair
PsiArrayInitializerMemberValue:{"Children", "Unscrupulous dentists"}
PsiJavaToken:LBRACE('{')
PsiLiteralExpression:"Children"
PsiJavaToken:STRING_LITERAL('"Children"')
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiLiteralExpression:"Unscrupulous dentists"
PsiJavaToken:STRING_LITERAL('"Unscrupulous dentists"')
PsiJavaToken:RBRACE('}')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,22 @@
PsiJavaFile:Complex.java
PsiAnnotation
PsiJavaToken:AT('@')
PsiJavaCodeReferenceElement:Author
PsiIdentifier:Author('Author')
PsiReferenceParameterList
<empty list>
PsiAnnotationParameterList
PsiJavaToken:LPARENTH('(')
PsiNameValuePair
PsiIdentifier:first('first')
PsiJavaToken:EQ('=')
PsiLiteralExpression:"Eugene"
PsiJavaToken:STRING_LITERAL('"Eugene"')
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiNameValuePair
PsiIdentifier:second('second')
PsiJavaToken:EQ('=')
PsiLiteralExpression:"Wampirchik"
PsiJavaToken:STRING_LITERAL('"Wampirchik"')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,26 @@
PsiJavaFile:FirstNameMissed.java
PsiAnnotation
PsiJavaToken:AT('@')
PsiJavaCodeReferenceElement:Anno
PsiIdentifier:Anno('Anno')
PsiReferenceParameterList
<empty list>
PsiAnnotationParameterList
PsiJavaToken:LPARENTH('(')
PsiNameValuePair
PsiReferenceExpression:value1
PsiReferenceParameterList
<empty list>
PsiIdentifier:value1('value1')
PsiErrorElement:Annotation attribute must be of the form 'name=value'
<empty list>
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiNameValuePair
PsiIdentifier:param2('param2')
PsiJavaToken:EQ('=')
PsiReferenceExpression:value2
PsiReferenceParameterList
<empty list>
PsiIdentifier:value2('value2')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,9 @@
PsiJavaFile:Marker.java
PsiAnnotation
PsiJavaToken:AT('@')
PsiJavaCodeReferenceElement:Preliminary
PsiIdentifier:Preliminary('Preliminary')
PsiReferenceParameterList
<empty list>
PsiAnnotationParameterList
<empty list>
@@ -0,0 +1,26 @@
PsiJavaFile:Multiple.java
PsiAnnotation
PsiJavaToken:AT('@')
PsiJavaCodeReferenceElement:Preliminary
PsiIdentifier:Preliminary('Preliminary')
PsiReferenceParameterList
<empty list>
PsiAnnotationParameterList
<empty list>
PsiWhiteSpace(' ')
PsiAnnotation
PsiJavaToken:AT('@')
PsiJavaCodeReferenceElement:Other
PsiIdentifier:Other('Other')
PsiReferenceParameterList
<empty list>
PsiAnnotationParameterList
PsiJavaToken:LPARENTH('(')
PsiNameValuePair
PsiIdentifier:name('name')
PsiJavaToken:EQ('=')
PsiReferenceExpression:value
PsiReferenceParameterList
<empty list>
PsiIdentifier:value('value')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,32 @@
PsiJavaFile:Nested.java
PsiAnnotation
PsiJavaToken:AT('@')
PsiJavaCodeReferenceElement:Author
PsiIdentifier:Author('Author')
PsiReferenceParameterList
<empty list>
PsiAnnotationParameterList
PsiJavaToken:LPARENTH('(')
PsiNameValuePair
PsiAnnotation
PsiJavaToken:AT('@')
PsiJavaCodeReferenceElement:Name
PsiIdentifier:Name('Name')
PsiReferenceParameterList
<empty list>
PsiAnnotationParameterList
PsiJavaToken:LPARENTH('(')
PsiNameValuePair
PsiIdentifier:first('first')
PsiJavaToken:EQ('=')
PsiLiteralExpression:"Eugene"
PsiJavaToken:STRING_LITERAL('"Eugene"')
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiNameValuePair
PsiIdentifier:second('second')
PsiJavaToken:EQ('=')
PsiLiteralExpression:"Wampirchik"
PsiJavaToken:STRING_LITERAL('"Wampirchik"')
PsiJavaToken:RPARENTH(')')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,13 @@
PsiJavaFile:ParameterizedAnnotation.java
PsiAnnotation
PsiJavaToken:AT('@')
PsiJavaCodeReferenceElement:Nullable
PsiIdentifier:Nullable('Nullable')
PsiReferenceParameterList
<empty list>
PsiAnnotationParameterList
<empty list>
PsiErrorElement:Unparsed tokens
PsiJavaToken:LT('<')
PsiIdentifier:T('T')
PsiJavaToken:GT('>')
@@ -0,0 +1,24 @@
PsiJavaFile:QualifiedAnnotation.java
PsiAnnotation
PsiJavaToken:AT('@')
PsiJavaCodeReferenceElement:org.jetbrains.annotations.Nullable
PsiJavaCodeReferenceElement:org.jetbrains.annotations
PsiJavaCodeReferenceElement:org.jetbrains
PsiJavaCodeReferenceElement:org
PsiIdentifier:org('org')
PsiReferenceParameterList
<empty list>
PsiJavaToken:DOT('.')
PsiIdentifier:jetbrains('jetbrains')
PsiReferenceParameterList
<empty list>
PsiJavaToken:DOT('.')
PsiIdentifier:annotations('annotations')
PsiReferenceParameterList
<empty list>
PsiJavaToken:DOT('.')
PsiIdentifier:Nullable('Nullable')
PsiReferenceParameterList
<empty list>
PsiAnnotationParameterList
<empty list>
@@ -0,0 +1,13 @@
PsiJavaFile:Simple0.java
PsiAnnotation
PsiJavaToken:AT('@')
PsiJavaCodeReferenceElement:Copyright
PsiIdentifier:Copyright('Copyright')
PsiReferenceParameterList
<empty list>
PsiAnnotationParameterList
PsiJavaToken:LPARENTH('(')
PsiNameValuePair
PsiLiteralExpression:"bla-bla-bla"
PsiJavaToken:STRING_LITERAL('"bla-bla-bla"')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,15 @@
PsiJavaFile:Simple1.java
PsiAnnotation
PsiJavaToken:AT('@')
PsiJavaCodeReferenceElement:Copyright
PsiIdentifier:Copyright('Copyright')
PsiReferenceParameterList
<empty list>
PsiAnnotationParameterList
PsiJavaToken:LPARENTH('(')
PsiNameValuePair
PsiReferenceExpression:treatedAsValue
PsiReferenceParameterList
<empty list>
PsiIdentifier:treatedAsValue('treatedAsValue')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,5 @@
PsiJavaFile:ArrayInitializer0.java
PsiArrayInitializerExpression:{ }
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,8 @@
PsiJavaFile:ArrayInitializer1.java
PsiArrayInitializerExpression:{ 1 }
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,9 @@
PsiJavaFile:ArrayInitializer2.java
PsiArrayInitializerExpression:{ 1, }
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,11 @@
PsiJavaFile:ArrayInitializer3.java
PsiArrayInitializerExpression:{ 1,2 }
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiJavaToken:COMMA(',')
PsiLiteralExpression:2
PsiJavaToken:INTEGER_LITERAL('2')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,13 @@
PsiJavaFile:ArrayInitializer4.java
PsiArrayInitializerExpression:{ 1 2 }
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiErrorElement:',' expected
<empty list>
PsiWhiteSpace(' ')
PsiLiteralExpression:2
PsiJavaToken:INTEGER_LITERAL('2')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,12 @@
PsiJavaFile:ArrayInitializer5.java
PsiArrayInitializerExpression:{ { }
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiArrayInitializerExpression:{ }
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
PsiErrorElement:',' expected
<empty list>
PsiErrorElement:'}' expected
<empty list>
@@ -0,0 +1,7 @@
PsiJavaFile:ArrayInitializer6.java
PsiArrayInitializerExpression:{ , }
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,16 @@
PsiJavaFile:ArrayInitializer7.java
PsiArrayInitializerExpression:{ , , 7 }
PsiJavaToken:LBRACE('{')
PsiErrorElement:Expression expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:COMMA(',')
PsiErrorElement:Expression expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiLiteralExpression:7
PsiJavaToken:INTEGER_LITERAL('7')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,11 @@
PsiJavaFile:Assignment0.java
PsiAssignmentExpression:a = 0
PsiReferenceExpression:a
PsiReferenceParameterList
<empty list>
PsiIdentifier:a('a')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiLiteralExpression:0
PsiJavaToken:INTEGER_LITERAL('0')
@@ -0,0 +1,10 @@
PsiJavaFile:Assignment1.java
PsiAssignmentExpression:a =
PsiReferenceExpression:a
PsiReferenceParameterList
<empty list>
PsiIdentifier:a('a')
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiErrorElement:Expression expected
<empty list>
@@ -0,0 +1,13 @@
PsiJavaFile:Cast.java
PsiTypeCastExpression:(Type)var
PsiJavaToken:LPARENTH('(')
PsiTypeElement:Type
PsiJavaCodeReferenceElement:Type
PsiIdentifier:Type('Type')
PsiReferenceParameterList
<empty list>
PsiJavaToken:RPARENTH(')')
PsiReferenceExpression:var
PsiReferenceParameterList
<empty list>
PsiIdentifier:var('var')
@@ -0,0 +1,16 @@
PsiJavaFile:Cond0.java
PsiConditionalExpression:cond ? true : false
PsiReferenceExpression:cond
PsiReferenceParameterList
<empty list>
PsiIdentifier:cond('cond')
PsiWhiteSpace(' ')
PsiJavaToken:QUEST('?')
PsiWhiteSpace(' ')
PsiLiteralExpression:true
PsiJavaToken:TRUE_KEYWORD('true')
PsiWhiteSpace(' ')
PsiJavaToken:COLON(':')
PsiWhiteSpace(' ')
PsiLiteralExpression:false
PsiJavaToken:FALSE_KEYWORD('false')
@@ -0,0 +1,10 @@
PsiJavaFile:Cond1.java
PsiConditionalExpression:cond ?
PsiReferenceExpression:cond
PsiReferenceParameterList
<empty list>
PsiIdentifier:cond('cond')
PsiWhiteSpace(' ')
PsiJavaToken:QUEST('?')
PsiErrorElement:Expression expected
<empty list>
@@ -0,0 +1,13 @@
PsiJavaFile:Cond2.java
PsiConditionalExpression:cond ? true
PsiReferenceExpression:cond
PsiReferenceParameterList
<empty list>
PsiIdentifier:cond('cond')
PsiWhiteSpace(' ')
PsiJavaToken:QUEST('?')
PsiWhiteSpace(' ')
PsiLiteralExpression:true
PsiJavaToken:TRUE_KEYWORD('true')
PsiErrorElement:':' expected
<empty list>
@@ -0,0 +1,15 @@
PsiJavaFile:Cond3.java
PsiConditionalExpression:cond ? true :
PsiReferenceExpression:cond
PsiReferenceParameterList
<empty list>
PsiIdentifier:cond('cond')
PsiWhiteSpace(' ')
PsiJavaToken:QUEST('?')
PsiWhiteSpace(' ')
PsiLiteralExpression:true
PsiJavaToken:TRUE_KEYWORD('true')
PsiWhiteSpace(' ')
PsiJavaToken:COLON(':')
PsiErrorElement:Expression expected
<empty list>
@@ -0,0 +1,21 @@
PsiJavaFile:CondOr0.java
PsiBinaryExpression:a || b || c
PsiBinaryExpression:a || b
PsiReferenceExpression:a
PsiReferenceParameterList
<empty list>
PsiIdentifier:a('a')
PsiWhiteSpace(' ')
PsiJavaToken:OROR('||')
PsiWhiteSpace(' ')
PsiReferenceExpression:b
PsiReferenceParameterList
<empty list>
PsiIdentifier:b('b')
PsiWhiteSpace(' ')
PsiJavaToken:OROR('||')
PsiWhiteSpace(' ')
PsiReferenceExpression:c
PsiReferenceParameterList
<empty list>
PsiIdentifier:c('c')
@@ -0,0 +1,10 @@
PsiJavaFile:CondOr1.java
PsiBinaryExpression:a ||
PsiReferenceExpression:a
PsiReferenceParameterList
<empty list>
PsiIdentifier:a('a')
PsiWhiteSpace(' ')
PsiJavaToken:OROR('||')
PsiErrorElement:Expression expected
<empty list>
@@ -0,0 +1,14 @@
PsiJavaFile:ExprList0.java
PsiMethodCallExpression:f(1,2)
PsiReferenceExpression:f
PsiReferenceParameterList
<empty list>
PsiIdentifier:f('f')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiJavaToken:COMMA(',')
PsiLiteralExpression:2
PsiJavaToken:INTEGER_LITERAL('2')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,10 @@
PsiJavaFile:ExprList1.java
PsiMethodCallExpression:f(
PsiReferenceExpression:f
PsiReferenceParameterList
<empty list>
PsiIdentifier:f('f')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiErrorElement:')' expected
<empty list>
@@ -0,0 +1,12 @@
PsiJavaFile:ExprList2.java
PsiMethodCallExpression:f(1
PsiReferenceExpression:f
PsiReferenceParameterList
<empty list>
PsiIdentifier:f('f')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiErrorElement:')' expected
<empty list>
@@ -0,0 +1,17 @@
PsiJavaFile:ExprList3.java
PsiMethodCallExpression:f(1,
PsiReferenceExpression:f
PsiReferenceParameterList
<empty list>
PsiIdentifier:f('f')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiJavaToken:COMMA(',')
PsiErrorElement:Expression expected
<empty list>
PsiExpression(empty)
<empty list>
PsiErrorElement:')' expected
<empty list>
@@ -0,0 +1,16 @@
PsiJavaFile:ExprList4.java
PsiMethodCallExpression:f(1,)
PsiReferenceExpression:f
PsiReferenceParameterList
<empty list>
PsiIdentifier:f('f')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiJavaToken:COMMA(',')
PsiErrorElement:Expression expected
<empty list>
PsiExpression(empty)
<empty list>
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,19 @@
PsiJavaFile:ExprList5.java
PsiMethodCallExpression:f(1,,2)
PsiReferenceExpression:f
PsiReferenceParameterList
<empty list>
PsiIdentifier:f('f')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiJavaToken:COMMA(',')
PsiErrorElement:Expression expected
<empty list>
PsiExpression(empty)
<empty list>
PsiJavaToken:COMMA(',')
PsiLiteralExpression:2
PsiJavaToken:INTEGER_LITERAL('2')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,16 @@
PsiJavaFile:ExprList6.java
PsiMethodCallExpression:f(,2)
PsiReferenceExpression:f
PsiReferenceParameterList
<empty list>
PsiIdentifier:f('f')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiErrorElement:Expression expected
<empty list>
PsiExpression(empty)
<empty list>
PsiJavaToken:COMMA(',')
PsiLiteralExpression:2
PsiJavaToken:INTEGER_LITERAL('2')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,17 @@
PsiJavaFile:GE.java
PsiAssignmentExpression:x >>>= 8 >> 2
PsiReferenceExpression:x
PsiReferenceParameterList
<empty list>
PsiIdentifier:x('x')
PsiWhiteSpace(' ')
PsiJavaToken:GTGTGTEQ('>>>=')
PsiWhiteSpace(' ')
PsiBinaryExpression:8 >> 2
PsiLiteralExpression:8
PsiJavaToken:INTEGER_LITERAL('8')
PsiWhiteSpace(' ')
PsiJavaToken:GTGT('>>')
PsiWhiteSpace(' ')
PsiLiteralExpression:2
PsiJavaToken:INTEGER_LITERAL('2')
@@ -0,0 +1,24 @@
PsiJavaFile:IllegalWildcard.java
PsiConditionalExpression:this.<?
PsiReferenceExpression:this.<
PsiThisExpression:this
PsiReferenceParameterList
<empty list>
PsiKeyword:this('this')
PsiJavaToken:DOT('.')
PsiReferenceParameterList
PsiJavaToken:LT('<')
PsiErrorElement:Identifier expected
<empty list>
PsiErrorElement:'>' or ',' expected.
<empty list>
PsiErrorElement:Identifier expected
<empty list>
PsiJavaToken:QUEST('?')
PsiErrorElement:Expression expected
<empty list>
PsiErrorElement:Unparsed tokens
PsiJavaToken:GT('>')
PsiIdentifier:foo('foo')
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,26 @@
PsiJavaFile:IncompleteCast.java
PsiMethodCallExpression:f((ArrayList<String>) )
PsiReferenceExpression:f
PsiReferenceParameterList
<empty list>
PsiIdentifier:f('f')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiTypeCastExpression:(ArrayList<String>)
PsiJavaToken:LPARENTH('(')
PsiTypeElement:ArrayList<String>
PsiJavaCodeReferenceElement:ArrayList<String>
PsiIdentifier:ArrayList('ArrayList')
PsiReferenceParameterList
PsiJavaToken:LT('<')
PsiTypeElement:String
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
PsiJavaToken:GT('>')
PsiJavaToken:RPARENTH(')')
PsiErrorElement:Expression expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,14 @@
PsiJavaFile:InstanceOf0.java
PsiInstanceofExpression:a instanceof String
PsiReferenceExpression:a
PsiReferenceParameterList
<empty list>
PsiIdentifier:a('a')
PsiWhiteSpace(' ')
PsiKeyword:instanceof('instanceof')
PsiWhiteSpace(' ')
PsiTypeElement:String
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
@@ -0,0 +1,10 @@
PsiJavaFile:InstanceOf1.java
PsiInstanceofExpression:a instanceof
PsiReferenceExpression:a
PsiReferenceParameterList
<empty list>
PsiIdentifier:a('a')
PsiWhiteSpace(' ')
PsiKeyword:instanceof('instanceof')
PsiErrorElement:Type expected
<empty list>
@@ -0,0 +1,13 @@
PsiJavaFile:New0.java
PsiNewExpression:new A()
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:A
PsiIdentifier:A('A')
PsiReferenceParameterList
<empty list>
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,16 @@
PsiJavaFile:New1.java
PsiNewExpression:new A[1][]
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:A
PsiIdentifier:A('A')
PsiReferenceParameterList
<empty list>
PsiJavaToken:LBRACKET('[')
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiJavaToken:RBRACKET(']')
PsiJavaToken:LBRACKET('[')
PsiJavaToken:RBRACKET(']')
@@ -0,0 +1,12 @@
PsiJavaFile:New10.java
PsiNewExpression:new int
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiKeyword:int('int')
PsiErrorElement:'[' expected
<empty list>
PsiErrorElement:Unparsed tokens
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,15 @@
PsiJavaFile:New11.java
PsiNewExpression:new String[0
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
PsiJavaToken:LBRACKET('[')
PsiLiteralExpression:0
PsiJavaToken:INTEGER_LITERAL('0')
PsiErrorElement:']' expected
<empty list>
@@ -0,0 +1,15 @@
PsiJavaFile:New12.java
PsiNewExpression:new int[1][2]
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiKeyword:int('int')
PsiJavaToken:LBRACKET('[')
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiJavaToken:RBRACKET(']')
PsiJavaToken:LBRACKET('[')
PsiLiteralExpression:2
PsiJavaToken:INTEGER_LITERAL('2')
PsiJavaToken:RBRACKET(']')
@@ -0,0 +1,19 @@
PsiJavaFile:New13.java
PsiNewExpression:new int[1][][
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiKeyword:int('int')
PsiJavaToken:LBRACKET('[')
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiJavaToken:RBRACKET(']')
PsiJavaToken:LBRACKET('[')
PsiJavaToken:RBRACKET(']')
PsiJavaToken:LBRACKET('[')
PsiErrorElement:']' expected
<empty list>
PsiErrorElement:Unparsed tokens
PsiJavaToken:INTEGER_LITERAL('2')
PsiJavaToken:RBRACKET(']')
@@ -0,0 +1,18 @@
PsiJavaFile:New14.java
PsiNewExpression:Q.new A()
PsiReferenceExpression:Q
PsiReferenceParameterList
<empty list>
PsiIdentifier:Q('Q')
PsiJavaToken:DOT('.')
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:A
PsiIdentifier:A('A')
PsiReferenceParameterList
<empty list>
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,14 @@
PsiJavaFile:New2.java
PsiNewExpression:new A[]
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:A
PsiIdentifier:A('A')
PsiReferenceParameterList
<empty list>
PsiJavaToken:LBRACKET('[')
PsiJavaToken:RBRACKET(']')
PsiErrorElement:Array initializer expected
<empty list>
@@ -0,0 +1,18 @@
PsiJavaFile:New3.java
PsiNewExpression:new A[][
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:A
PsiIdentifier:A('A')
PsiReferenceParameterList
<empty list>
PsiJavaToken:LBRACKET('[')
PsiJavaToken:RBRACKET(']')
PsiJavaToken:LBRACKET('[')
PsiErrorElement:']' expected
<empty list>
PsiErrorElement:Unparsed tokens
PsiJavaToken:INTEGER_LITERAL('1')
PsiJavaToken:RBRACKET(']')
@@ -0,0 +1,19 @@
PsiJavaFile:New4.java
PsiNewExpression:new A[][]{null}
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:A
PsiIdentifier:A('A')
PsiReferenceParameterList
<empty list>
PsiJavaToken:LBRACKET('[')
PsiJavaToken:RBRACKET(']')
PsiJavaToken:LBRACKET('[')
PsiJavaToken:RBRACKET(']')
PsiArrayInitializerExpression:{null}
PsiJavaToken:LBRACE('{')
PsiLiteralExpression:null
PsiJavaToken:NULL_KEYWORD('null')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,18 @@
PsiJavaFile:New5.java
PsiNewExpression:new A[1]
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:A
PsiIdentifier:A('A')
PsiReferenceParameterList
<empty list>
PsiJavaToken:LBRACKET('[')
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiJavaToken:RBRACKET(']')
PsiErrorElement:Unparsed tokens
PsiJavaToken:LBRACE('{')
PsiJavaToken:NULL_KEYWORD('null')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,7 @@
PsiJavaFile:New6.java
PsiNewExpression:new
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiErrorElement:Identifier expected
<empty list>
@@ -0,0 +1,12 @@
PsiJavaFile:New7.java
PsiNewExpression:new A
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:A
PsiIdentifier:A('A')
PsiReferenceParameterList
<empty list>
PsiErrorElement:'(' or '[' expected
<empty list>
@@ -0,0 +1,13 @@
PsiJavaFile:New8.java
PsiNewExpression:new A[
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:A
PsiIdentifier:A('A')
PsiReferenceParameterList
<empty list>
PsiJavaToken:LBRACKET('[')
PsiErrorElement:']' expected
<empty list>
@@ -0,0 +1,9 @@
PsiJavaFile:New9.java
PsiNewExpression:new int
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiKeyword:int('int')
PsiErrorElement:'[' expected
<empty list>
@@ -0,0 +1,15 @@
PsiJavaFile:NewInExprList.java
PsiMethodCallExpression:call(new)
PsiReferenceExpression:call
PsiReferenceParameterList
<empty list>
PsiIdentifier:call('call')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiNewExpression:new
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiErrorElement:Identifier expected
<empty list>
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,9 @@
PsiJavaFile:Not0.java
PsiPrefixExpression:!!a
PsiJavaToken:EXCL('!')
PsiPrefixExpression:!a
PsiJavaToken:EXCL('!')
PsiReferenceExpression:a
PsiReferenceParameterList
<empty list>
PsiIdentifier:a('a')
@@ -0,0 +1,5 @@
PsiJavaFile:Not1.java
PsiPrefixExpression:!
PsiJavaToken:EXCL('!')
PsiErrorElement:Expression expected
<empty list>
@@ -0,0 +1,21 @@
PsiJavaFile:Or0.java
PsiBinaryExpression:a | b | c
PsiBinaryExpression:a | b
PsiReferenceExpression:a
PsiReferenceParameterList
<empty list>
PsiIdentifier:a('a')
PsiWhiteSpace(' ')
PsiJavaToken:OR('|')
PsiWhiteSpace(' ')
PsiReferenceExpression:b
PsiReferenceParameterList
<empty list>
PsiIdentifier:b('b')
PsiWhiteSpace(' ')
PsiJavaToken:OR('|')
PsiWhiteSpace(' ')
PsiReferenceExpression:c
PsiReferenceParameterList
<empty list>
PsiIdentifier:c('c')
@@ -0,0 +1,10 @@
PsiJavaFile:Or1.java
PsiBinaryExpression:a |
PsiReferenceExpression:a
PsiReferenceParameterList
<empty list>
PsiIdentifier:a('a')
PsiWhiteSpace(' ')
PsiJavaToken:OR('|')
PsiErrorElement:Expression expected
<empty list>
@@ -0,0 +1,8 @@
PsiJavaFile:Parenth0.java
PsiParenthesizedExpression:(c)
PsiJavaToken:LPARENTH('(')
PsiReferenceExpression:c
PsiReferenceParameterList
<empty list>
PsiIdentifier:c('c')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,15 @@
PsiJavaFile:Parenth1.java
PsiPostfixExpression:(this).f--
PsiReferenceExpression:(this).f
PsiParenthesizedExpression:(this)
PsiJavaToken:LPARENTH('(')
PsiThisExpression:this
PsiReferenceParameterList
<empty list>
PsiKeyword:this('this')
PsiJavaToken:RPARENTH(')')
PsiJavaToken:DOT('.')
PsiReferenceParameterList
<empty list>
PsiIdentifier:f('f')
PsiJavaToken:MINUSMINUS('--')
@@ -0,0 +1,22 @@
PsiJavaFile:PinesInReferenceExpression0.java
PsiMethodCallExpression:Collections.<String>sort(null)
PsiReferenceExpression:Collections.<String>sort
PsiReferenceExpression:Collections
PsiReferenceParameterList
<empty list>
PsiIdentifier:Collections('Collections')
PsiJavaToken:DOT('.')
PsiReferenceParameterList
PsiJavaToken:LT('<')
PsiTypeElement:String
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
PsiJavaToken:GT('>')
PsiIdentifier:sort('sort')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiLiteralExpression:null
PsiJavaToken:NULL_KEYWORD('null')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,22 @@
PsiJavaFile:PinesInReferenceExpression1.java
PsiMethodCallExpression:this.<String>sort(null)
PsiReferenceExpression:this.<String>sort
PsiThisExpression:this
PsiReferenceParameterList
<empty list>
PsiKeyword:this('this')
PsiJavaToken:DOT('.')
PsiReferenceParameterList
PsiJavaToken:LT('<')
PsiTypeElement:String
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
PsiJavaToken:GT('>')
PsiIdentifier:sort('sort')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiLiteralExpression:null
PsiJavaToken:NULL_KEYWORD('null')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,6 @@
PsiJavaFile:PrimitiveClassObjectAccess.java
PsiClassObjectAccessExpression:int.class
PsiTypeElement:int
PsiKeyword:int('int')
PsiJavaToken:DOT('.')
PsiKeyword:class('class')
@@ -0,0 +1,22 @@
PsiJavaFile:QualifiedSuperMethodCall0.java
PsiMethodCallExpression:new D().super(0)
PsiReferenceExpression:new D().super
PsiNewExpression:new D()
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:D
PsiIdentifier:D('D')
PsiReferenceParameterList
<empty list>
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiJavaToken:DOT('.')
PsiKeyword:super('super')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiLiteralExpression:0
PsiJavaToken:INTEGER_LITERAL('0')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,14 @@
PsiJavaFile:QualifiedSuperMethodCall1.java
PsiMethodCallExpression:d.super(0)
PsiReferenceExpression:d.super
PsiReferenceExpression:d
PsiReferenceParameterList
<empty list>
PsiIdentifier:d('d')
PsiJavaToken:DOT('.')
PsiKeyword:super('super')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiLiteralExpression:0
PsiJavaToken:INTEGER_LITERAL('0')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,11 @@
PsiJavaFile:ShiftRight.java
PsiAssignmentExpression:x >>= 2
PsiReferenceExpression:x
PsiReferenceParameterList
<empty list>
PsiIdentifier:x('x')
PsiWhiteSpace(' ')
PsiJavaToken:GTGTEQ('>>=')
PsiWhiteSpace(' ')
PsiLiteralExpression:2
PsiJavaToken:INTEGER_LITERAL('2')
@@ -0,0 +1,9 @@
PsiJavaFile:SuperMethodCallTypeParameterList.java
PsiMethodCallExpression:super()
PsiReferenceExpression:super
PsiReferenceParameterList
<empty list>
PsiKeyword:super('super')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,5 @@
PsiJavaFile:Reference0.java
PsiJavaCodeReferenceElement:a
PsiIdentifier:a('a')
PsiReferenceParameterList
<empty list>
@@ -0,0 +1,9 @@
PsiJavaFile:Reference1.java
PsiJavaCodeReferenceElement:a.
PsiJavaCodeReferenceElement:a
PsiIdentifier:a('a')
PsiReferenceParameterList
<empty list>
PsiJavaToken:DOT('.')
PsiErrorElement:Identifier expected
<empty list>
@@ -0,0 +1,10 @@
PsiJavaFile:Reference2.java
PsiJavaCodeReferenceElement:a.b
PsiJavaCodeReferenceElement:a
PsiIdentifier:a('a')
PsiReferenceParameterList
<empty list>
PsiJavaToken:DOT('.')
PsiIdentifier:b('b')
PsiReferenceParameterList
<empty list>
@@ -0,0 +1,3 @@
PsiJavaFile:Type0.java
PsiTypeElement:int
PsiKeyword:int('int')
@@ -0,0 +1,11 @@
PsiJavaFile:Type1.java
PsiTypeElement:a.b
PsiJavaCodeReferenceElement:a.b
PsiJavaCodeReferenceElement:a
PsiIdentifier:a('a')
PsiReferenceParameterList
<empty list>
PsiJavaToken:DOT('.')
PsiIdentifier:b('b')
PsiReferenceParameterList
<empty list>
@@ -0,0 +1,6 @@
PsiJavaFile:Type2.java
PsiTypeElement:int[]
PsiTypeElement:int
PsiKeyword:int('int')
PsiJavaToken:LBRACKET('[')
PsiJavaToken:RBRACKET(']')
@@ -0,0 +1,9 @@
PsiJavaFile:Type3.java
PsiTypeElement:int[]
PsiTypeElement:int
PsiKeyword:int('int')
PsiJavaToken:LBRACKET('[')
PsiJavaToken:RBRACKET(']')
PsiJavaToken:LBRACKET('[')
PsiErrorElement:']' expected
<empty list>
@@ -0,0 +1,24 @@
PsiJavaFile:Type4.java
PsiTypeElement:Map<String,List<String>>
PsiJavaCodeReferenceElement:Map<String,List<String>>
PsiIdentifier:Map('Map')
PsiReferenceParameterList
PsiJavaToken:LT('<')
PsiTypeElement:String
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
PsiJavaToken:COMMA(',')
PsiTypeElement:List<String>
PsiJavaCodeReferenceElement:List<String>
PsiIdentifier:List('List')
PsiReferenceParameterList
PsiJavaToken:LT('<')
PsiTypeElement:String
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
PsiJavaToken:GT('>')
PsiJavaToken:GT('>')
@@ -0,0 +1,8 @@
PsiJavaFile:TypeParams0.java
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:T
PsiIdentifier:T('T')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiJavaToken:GT('>')
@@ -0,0 +1,14 @@
PsiJavaFile:TypeParams1.java
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:T
PsiIdentifier:T('T')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiTypeParameter:U
PsiIdentifier:U('U')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiJavaToken:GT('>')
@@ -0,0 +1,9 @@
PsiJavaFile:TypeParams2.java
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:T
PsiIdentifier:T('T')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiErrorElement:'>' expected.
<empty list>
@@ -0,0 +1,11 @@
PsiJavaFile:TypeParams3.java
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:T
PsiIdentifier:T('T')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiWhiteSpace(' ')
PsiErrorElement:Unexpected identifier
PsiIdentifier:hack('hack')
PsiJavaToken:GT('>')
@@ -0,0 +1,12 @@
PsiJavaFile:TypeParams4.java
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:T
PsiIdentifier:T('T')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiErrorElement:'>' expected.
<empty list>
PsiWhiteSpace(' ')
PsiErrorElement:Unparsed tokens
PsiIdentifier:hack('hack')
@@ -0,0 +1,27 @@
PsiJavaFile:TypeParams5.java
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:T
PsiIdentifier:T('T')
PsiWhiteSpace(' ')
PsiKeyword:extends('extends')
PsiWhiteSpace(' ')
PsiElement(EXTENDS_BOUND_LIST)
PsiJavaCodeReferenceElement:X
PsiIdentifier:X('X')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:AND('&')
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:Y<Z>
PsiIdentifier:Y('Y')
PsiReferenceParameterList
PsiJavaToken:LT('<')
PsiTypeElement:Z
PsiJavaCodeReferenceElement:Z
PsiIdentifier:Z('Z')
PsiReferenceParameterList
<empty list>
PsiJavaToken:GT('>')
PsiJavaToken:GT('>')
@@ -0,0 +1,15 @@
PsiJavaFile:TypeParams6.java
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:T
PsiIdentifier:T('T')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiErrorElement:'>' expected.
<empty list>
PsiWhiteSpace(' ')
PsiErrorElement:Unparsed tokens
PsiIdentifier:supers('supers')
PsiWhiteSpace(' ')
PsiIdentifier:X('X')
PsiJavaToken:GT('>')
@@ -0,0 +1,20 @@
PsiJavaFile:TypeParams7.java
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:T
PsiIdentifier:T('T')
PsiWhiteSpace(' ')
PsiKeyword:extends('extends')
PsiWhiteSpace(' ')
PsiElement(EXTENDS_BOUND_LIST)
PsiJavaCodeReferenceElement:X
PsiIdentifier:X('X')
PsiReferenceParameterList
<empty list>
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiTypeParameter:Y
PsiIdentifier:Y('Y')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiJavaToken:GT('>')
@@ -1,6 +1,12 @@
package com.intellij;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.impl.PsiBuilderImpl;
import com.intellij.lang.java.parser.JavaParserUtil;
import com.intellij.lexer.JavaLexer;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.JavaTokenType;
/**
* @author yole
@@ -13,4 +19,12 @@ public class JavaTestUtil {
public static String getJavaTestDataPath() {
return PathManagerEx.getTestDataPath();
}
public static PsiBuilder getJavaBuilder(final String source) {
final LanguageLevel languageLevel = LanguageLevel.HIGHEST;
final JavaLexer lexer = new JavaLexer(languageLevel);
final PsiBuilder builder = new PsiBuilderImpl(lexer, JavaTokenType.WHITESPACE_BIT_SET, JavaTokenType.COMMENT_BIT_SET, source);
JavaParserUtil.setLanguageLevel(builder, languageLevel);
return builder;
}
}
@@ -0,0 +1,66 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.java.parser;
import com.intellij.lang.PsiBuilder;
import com.intellij.psi.impl.DebugUtil;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.testFramework.IdeaTestCase;
import com.intellij.testFramework.ParsingTestCase;
import org.jetbrains.annotations.NonNls;
import java.io.IOException;
import static com.intellij.JavaTestUtil.getJavaBuilder;
public abstract class JavaParsingTestCase extends ParsingTestCase {
@SuppressWarnings({"JUnitTestCaseWithNonTrivialConstructors"})
public JavaParsingTestCase(@NonNls final String dataPath) {
super(dataPath, "java");
IdeaTestCase.initPlatformPrefix();
}
protected interface Parser {
void parse(PsiBuilder builder);
}
protected void doParserTest(final String text, final Parser parser) {
final String name = getTestName(false);
final PsiBuilder builder = getJavaBuilder(text);
final PsiBuilder.Marker root = builder.mark();
parser.parse(builder);
if (builder.getTokenType() != null) {
final PsiBuilder.Marker unparsed = builder.mark();
while (builder.getTokenType() != null) builder.advanceLexer();
unparsed.error("Unparsed tokens");
}
root.done(JavaElementType.JAVA_FILE);
final String raw = DebugUtil.treeToString(builder.getTreeBuilt(), false);
final String tree = raw.replaceFirst("com.intellij.psi.util.PsiUtilBase\\S+", "PsiJavaFile:" + name + ".java");
try {
checkResult(name + ".txt", tree);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,47 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.java.parser.partial;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.java.parser.DeclarationParser;
import com.intellij.lang.java.parser.JavaParsingTestCase;
public class AnnotationParserTest extends JavaParsingTestCase {
public AnnotationParserTest() {
super("parser-partial/annotations");
}
public void testMarker() { doParserTest("@Preliminary"); }
public void testSimple0() { doParserTest("@Copyright(\"bla-bla-bla\")"); }
public void testSimple1() { doParserTest("@Copyright(treatedAsValue)"); }
public void testComplex() { doParserTest("@Author(first=\"Eugene\", second=\"Wampirchik\")"); }
public void testMultiple() { doParserTest("@Preliminary @Other(name=value)"); }
public void testArray() { doParserTest("@Endorsers({\"Children\", \"Unscrupulous dentists\"})"); }
public void testNested() { doParserTest("@Author(@Name(first=\"Eugene\", second=\"Wampirchik\"))"); }
public void testQualifiedAnnotation() { doParserTest("@org.jetbrains.annotations.Nullable"); }
public void testParameterizedAnnotation () { doParserTest("@Nullable<T>"); }
public void testFirstNameMissed() { doParserTest("@Anno(value1, param2=value2)"); }
private void doParserTest(final String text) {
doParserTest(text, new Parser() {
public void parse(final PsiBuilder builder) {
DeclarationParser.parseAnnotations(builder);
}
});
}
}
@@ -0,0 +1,110 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.java.parser.partial;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.java.parser.ExpressionParser;
import com.intellij.lang.java.parser.JavaParsingTestCase;
public class ExpressionParserTest extends JavaParsingTestCase {
public ExpressionParserTest() {
super("parser-partial/expressions");
}
public void testAssignment0() { doParserTest("a = 0"); }
public void testAssignment1() { doParserTest("a ="); }
public void testCond0() { doParserTest("cond ? true : false"); }
public void testCond1() { doParserTest("cond ?"); }
public void testCond2() { doParserTest("cond ? true"); }
public void testCond3() { doParserTest("cond ? true :"); }
public void testCondOr0() { doParserTest("a || b || c"); }
public void testCondOr1() { doParserTest("a ||"); }
public void testOr0() { doParserTest("a | b | c"); }
public void testOr1() { doParserTest("a |"); }
public void testInstanceOf0() { doParserTest("a instanceof String"); }
public void testInstanceOf1() { doParserTest("a instanceof"); }
public void testNot0() { doParserTest("!!a"); }
public void testNot1() { doParserTest("!"); }
public void testCast() { doParserTest("(Type)var"); }
public void testParenth0() { doParserTest("(c)"); }
public void testParenth1() { doParserTest("(this).f--"); }
public void testNewInExprList() { doParserTest("call(new)"); }
public void testNew0() { doParserTest("new A()"); }
public void testNew1() { doParserTest("new A[1][]"); }
public void testNew2() { doParserTest("new A[]"); }
public void testNew3() { doParserTest("new A[][1]"); }
public void testNew4() { doParserTest("new A[][]{null}"); }
public void testNew5() { doParserTest("new A[1]{null}"); }
public void testNew6() { doParserTest("new"); }
public void testNew7() { doParserTest("new A"); }
public void testNew8() { doParserTest("new A["); }
public void testNew9() { doParserTest("new int"); }
public void testNew10() { doParserTest("new int()"); }
public void testNew11() { doParserTest("new String[0"); }
public void testNew12() { doParserTest("new int[1][2]"); }
public void testNew13() { doParserTest("new int[1][][2]"); }
public void testNew14() { doParserTest("Q.new A()"); }
public void testExprList0() { doParserTest("f(1,2)"); }
public void testExprList1() { doParserTest("f("); }
public void testExprList2() { doParserTest("f(1"); }
public void testExprList3() { doParserTest("f(1,"); }
public void testExprList4() { doParserTest("f(1,)"); }
public void testExprList5() { doParserTest("f(1,,2)"); }
public void testExprList6() { doParserTest("f(,2)"); }
public void testArrayInitializer0() { doParserTest("{ }"); }
public void testArrayInitializer1() { doParserTest("{ 1 }"); }
public void testArrayInitializer2() { doParserTest("{ 1, }"); }
public void testArrayInitializer3() { doParserTest("{ 1,2 }"); }
public void testArrayInitializer4() { doParserTest("{ 1 2 }"); }
public void testArrayInitializer5() { doParserTest("{ { }"); }
public void testArrayInitializer6() { doParserTest("{ , }"); }
public void testArrayInitializer7() { doParserTest("{ , , 7 }"); }
public void testPinesInReferenceExpression0() { doParserTest("Collections.<String>sort(null)"); }
public void testPinesInReferenceExpression1() { doParserTest("this.<String>sort(null)"); }
public void testGE() { doParserTest("x >>>= 8 >> 2"); }
public void testIncompleteCast() { doParserTest("f((ArrayList<String>) )"); }
public void testShiftRight() { doParserTest("x >>= 2"); }
public void testIllegalWildcard() { doParserTest("this.<?>foo()"); }
public void testQualifiedSuperMethodCall0() { doParserTest("new D().super(0)"); }
public void testQualifiedSuperMethodCall1() { doParserTest("d.super(0)"); }
public void testSuperMethodCallTypeParameterList() { doParserTest("super()"); }
public void testPrimitiveClassObjectAccess() { doParserTest("int.class"); }
private void doParserTest(final String text) {
doParserTest(text, new Parser() {
public void parse(final PsiBuilder builder) {
ExpressionParser.parse(builder);
}
});
}
}
@@ -0,0 +1,70 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.java.parser.partial;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.java.parser.JavaParsingTestCase;
import com.intellij.lang.java.parser.ReferenceParser;
public class ReferenceParserTest extends JavaParsingTestCase {
public ReferenceParserTest() {
super("parser-partial/references");
}
public void testReference0() { doRefParserTest("a", false); }
public void testReference1() { doRefParserTest("a.", true); }
public void testReference2() { doRefParserTest("a.b", false); }
public void testType0() { doTypeParserTest("int", false); }
public void testType1() { doTypeParserTest("a.b", false); }
public void testType2() { doTypeParserTest("int[]", false); }
public void testType3() { doTypeParserTest("int[][", false); }
public void testType4() { doTypeParserTest("Map<String,List<String>>", false); }
public void testTypeParams0() { doTypeParamsParserTest("<T>"); }
public void testTypeParams1() { doTypeParamsParserTest("<T, U>"); }
public void testTypeParams2() { doTypeParamsParserTest("<T"); }
public void testTypeParams3() { doTypeParamsParserTest("<T hack>"); }
public void testTypeParams4() { doTypeParamsParserTest("<T hack"); }
public void testTypeParams5() { doTypeParamsParserTest("<T extends X & Y<Z>>"); }
public void testTypeParams6() { doTypeParamsParserTest("<T supers X>"); }
public void testTypeParams7() { doTypeParamsParserTest("<T extends X, Y>"); }
private void doRefParserTest(final String text, final boolean incomplete) {
doParserTest(text, new Parser() {
public void parse(final PsiBuilder builder) {
ReferenceParser.parseJavaCodeReference(builder, incomplete, false, false);
}
});
}
private void doTypeParserTest(final String text, final boolean incomplete) {
doParserTest(text, new Parser() {
public void parse(final PsiBuilder builder) {
ReferenceParser.parseType(builder, incomplete, false);
}
});
}
private void doTypeParamsParserTest(final String text) {
doParserTest(text, new Parser() {
public void parse(final PsiBuilder builder) {
ReferenceParser.parseTypeParameters(builder);
}
});
}
}
@@ -20,7 +20,19 @@ import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NonNls;
public class IJavaElementType extends IElementType {
private final boolean myLeftBound;
public IJavaElementType(@NonNls String debugName) {
this(debugName, false);
}
public IJavaElementType(@NonNls final String debugName, final boolean leftBound) {
super(debugName, StdFileTypes.JAVA != null ? StdFileTypes.JAVA.getLanguage() : null);
myLeftBound = leftBound;
}
@Override
public boolean isLeftBound() {
return myLeftBound;
}
}
@@ -0,0 +1,120 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.Nullable;
public class PsiBuilderUtil {
private PsiBuilderUtil() { }
/**
* Returns type of next token.
*
* @param builder PSI builder to operate on.
* @return type of next token or null, if the builder is at the end of token stream
*/
@Nullable
public static IElementType nextTokenType(final PsiBuilder builder) {
if (builder.getTokenType() == null) return null;
final PsiBuilder.Marker sp = builder.mark();
builder.advanceLexer();
final IElementType result = builder.getTokenType();
sp.rollbackTo();
return result;
}
/**
* Checks if tokens in token stream form expected sequence.
*
* @param builder PSI builder to operate on.
* @param tokenTypes expected elements.
* @return true if tokens form expected sequence, false otherwise
*/
public static boolean lookAhead(final PsiBuilder builder, final IElementType... tokenTypes) {
if (tokenTypes.length == 0) return true;
if (!tokenTypes[0].equals(builder.getTokenType())) return false;
if (tokenTypes.length == 1) return true;
final PsiBuilder.Marker rb = builder.mark();
builder.advanceLexer();
int i = 1;
while (!builder.eof() && i < tokenTypes.length && tokenTypes[i].equals(builder.getTokenType())) {
builder.advanceLexer();
i++;
}
rb.rollbackTo();
return i == tokenTypes.length;
}
/**
* Advances lexer by given number of tokens (but not beyond the end of token stream).
*
* @param builder PSI builder to operate on.
* @param count number of tokens to skip.
*/
public static void advance(final PsiBuilder builder, final int count) {
for (int i=0; i<count && !builder.eof(); i++) {
builder.getTokenType();
builder.advanceLexer();
}
}
/**
* Advances lexer if current token is of expected type, does nothing otherwise.
*
* @param builder PSI builder to operate on.
* @param expectedType expected token.
* @return true if token matches, false otherwise.
*/
public static boolean expect(final PsiBuilder builder, final IElementType expectedType) {
if (builder.getTokenType() == expectedType) {
builder.advanceLexer();
return true;
}
return false;
}
/**
* Advances lexer if current token is of expected type, does nothing otherwise.
*
* @param builder PSI builder to operate on.
* @param expectedTypes expected token types.
* @return true if token matches, false otherwise.
*/
public static boolean expect(final PsiBuilder builder, final TokenSet expectedTypes) {
if (expectedTypes.contains(builder.getTokenType())) {
builder.advanceLexer();
return true;
}
return false;
}
/**
* Release group of allocated markers.
*
* @param markers markers to drop.
*/
public static void drop(final PsiBuilder.Marker... markers) {
for (PsiBuilder.Marker marker : markers) {
marker.drop();
}
}
}