diff --git a/java/java-psi-impl/src/com/intellij/lang/java/parser/DeclarationParser.java b/java/java-psi-impl/src/com/intellij/lang/java/parser/DeclarationParser.java index 54e493126c1c..36d024726bbf 100644 --- a/java/java-psi-impl/src/com/intellij/lang/java/parser/DeclarationParser.java +++ b/java/java-psi-impl/src/com/intellij/lang/java/parser/DeclarationParser.java @@ -46,6 +46,8 @@ public class DeclarationParser { JavaTokenType.IDENTIFIER, JavaTokenType.COMMA, JavaTokenType.THROWS_KEYWORD); private static final TokenSet PARAM_LIST_STOPPERS = TokenSet.create( JavaTokenType.RPARENTH, JavaTokenType.LBRACE, JavaTokenType.ARROW); + private static final TokenSet TYPE_START = TokenSet.orSet( + ElementType.PRIMITIVE_TYPE_BIT_SET, TokenSet.create(JavaTokenType.IDENTIFIER, JavaTokenType.AT)); private static final String WHITESPACES = "\n\r \t"; private static final String LINE_ENDS = "\n\r"; @@ -278,56 +280,64 @@ public class DeclarationParser { return modList; } - PsiBuilder.Marker type; - if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(builder.getTokenType())) { - type = parseTypeNotNull(builder); - } - else if (builder.getTokenType() == JavaTokenType.IDENTIFIER /*|| builder.getTokenType() == JavaTokenType.AT*/) { - PsiBuilder.Marker idPos = builder.mark(); - type = parseTypeNotNull(builder); - if (builder.getTokenType() == JavaTokenType.LPARENTH) { // constructor - if (context == Context.CODE_BLOCK) { - declaration.rollbackTo(); - return null; - } - idPos.rollbackTo(); - if (typeParams == null) { - emptyElement(builder, JavaElementType.TYPE_PARAMETER_LIST); - } - builder.advanceLexer(); - if (builder.getTokenType() != JavaTokenType.LPARENTH) { - declaration.rollbackTo(); - return null; - } - return parseMethodFromLeftParenth(builder, declaration, false, true); - } - idPos.drop(); - } - else if (builder.getTokenType() == JavaTokenType.LBRACE) { + if (builder.getTokenType() == JavaTokenType.LBRACE) { if (context == Context.CODE_BLOCK) { error(builder, JavaErrorMessages.message("expected.identifier.or.type"), typeParams); declaration.drop(); return modList; } - final PsiBuilder.Marker codeBlock = myParser.getStatementParser().parseCodeBlock(builder); + PsiBuilder.Marker codeBlock = myParser.getStatementParser().parseCodeBlock(builder); assert codeBlock != null : builder.getOriginalText(); if (typeParams != null) { - final PsiBuilder.Marker error = typeParams.precede(); + PsiBuilder.Marker error = typeParams.precede(); error.errorBefore(JavaErrorMessages.message("unexpected.token"), codeBlock); } + done(declaration, JavaElementType.CLASS_INITIALIZER); return declaration; } - else { - final PsiBuilder.Marker error; - if (typeParams != null) { - error = typeParams.precede(); + + PsiBuilder.Marker type = null; + + if (TYPE_START.contains(builder.getTokenType())) { + PsiBuilder.Marker pos = builder.mark(); + + type = myParser.getReferenceParser().parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD); + + if (type == null) { + pos.rollbackTo(); + } + else if (builder.getTokenType() == JavaTokenType.LPARENTH) { // constructor + if (context == Context.CODE_BLOCK) { + declaration.rollbackTo(); + return null; + } + + pos.rollbackTo(); + + if (typeParams == null) { + emptyElement(builder, JavaElementType.TYPE_PARAMETER_LIST); + } + parseAnnotations(builder); + builder.advanceLexer(); + + if (builder.getTokenType() == JavaTokenType.LPARENTH) { + return parseMethodFromLeftParenth(builder, declaration, false, true); + } + else { + declaration.rollbackTo(); + return null; + } } else { - error = builder.mark(); + pos.drop(); } + } + + if (type == null) { + PsiBuilder.Marker error = typeParams != null ? typeParams.precede() : builder.mark(); error.error(JavaErrorMessages.message("expected.identifier.or.type")); declaration.drop(); return modList; @@ -363,13 +373,6 @@ public class DeclarationParser { return parseFieldOrLocalVariable(builder, declaration, declarationStart, context); } - @NotNull - private PsiBuilder.Marker parseTypeNotNull(final PsiBuilder builder) { - final PsiBuilder.Marker type = myParser.getReferenceParser().parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD); - assert type != null : builder.getOriginalText(); - return type; - } - @NotNull public Pair parseModifierList(final PsiBuilder builder) { return parseModifierList(builder, ElementType.MODIFIER_BIT_SET); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodElement.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodElement.java index 31fb4bca8833..1edd7cbaec76 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodElement.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,14 +41,15 @@ public class MethodElement extends CompositeElement implements Constants { @Override public int getTextOffset() { - return findChildByRole(ChildRole.NAME).getStartOffset(); + ASTNode name = findChildByType(IDENTIFIER); + return name != null ? name.getStartOffset() : this.getStartOffset(); } @Override public TreeElement addInternal(TreeElement first, ASTNode last, ASTNode anchor, Boolean before) { - if (first == last && first.getElementType() == JavaElementType.CODE_BLOCK){ - ASTNode semicolon = findChildByRole(ChildRole.CLOSING_SEMICOLON); - if (semicolon != null){ + if (first == last && first.getElementType() == JavaElementType.CODE_BLOCK) { + ASTNode semicolon = TreeUtil.findChildBackward(this, SEMICOLON); + if (semicolon != null) { deleteChildInternal(semicolon); } } @@ -64,7 +65,7 @@ public class MethodElement extends CompositeElement implements Constants { @Override public void deleteChildInternal(@NotNull ASTNode child) { - if (child.getElementType() == CODE_BLOCK){ + if (child.getElementType() == CODE_BLOCK) { final ASTNode prevWS = TreeUtil.prevLeaf(child); if (prevWS != null && prevWS.getElementType() == TokenType.WHITE_SPACE) { removeChild(prevWS); @@ -80,9 +81,9 @@ public class MethodElement extends CompositeElement implements Constants { } @Override - public ASTNode findChildByRole(int role){ + public ASTNode findChildByRole(int role) { LOG.assertTrue(ChildRole.isUnique(role)); - switch(role){ + switch (role) { default: return null; @@ -161,5 +162,4 @@ public class MethodElement extends CompositeElement implements Constants { protected boolean isVisibilitySupported() { return true; } - } diff --git a/java/java-tests/testData/psi/parser-full/annotationParsing/annotation/Errors.java b/java/java-tests/testData/psi/parser-full/annotationParsing/annotation/Errors.java index 200c37e7fa32..4e90d08eb3ea 100644 --- a/java/java-tests/testData/psi/parser-full/annotationParsing/annotation/Errors.java +++ b/java/java-tests/testData/psi/parser-full/annotationParsing/annotation/Errors.java @@ -1,2 +1,8 @@ @Ann(0) class D { + + @EJB + Runnable myMissingEjbRef; + + public @SafeVarargs + static void m(); } \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-full/annotationParsing/annotation/Errors.txt b/java/java-tests/testData/psi/parser-full/annotationParsing/annotation/Errors.txt index 9f1efdb6d2e4..678025fdf06a 100644 --- a/java/java-tests/testData/psi/parser-full/annotationParsing/annotation/Errors.txt +++ b/java/java-tests/testData/psi/parser-full/annotationParsing/annotation/Errors.txt @@ -69,5 +69,96 @@ PsiJavaFile:Errors.java PsiWhiteSpace(' ') PsiJavaToken:LBRACE('{') + PsiWhiteSpace('\n\n ') + PsiModifierList: + + PsiErrorElement:Identifier or type expected + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:error + PsiIdentifier:error('error') + PsiElement(EXTENDS_BOUND_LIST) + + PsiJavaToken:GT('>') + PsiModifierList:@EJB + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:EJB + PsiIdentifier:EJB('EJB') + PsiReferenceParameterList + + PsiAnnotationParameterList + + PsiErrorElement:Identifier or type expected + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiErrorElement:Type parameter expected + + PsiErrorElement:'>' expected. + + PsiErrorElement:Unexpected token + PsiJavaToken:DIV('/') + PsiModifierList: + + PsiTypeElement:error + PsiJavaCodeReferenceElement:error + PsiIdentifier:error('error') + PsiReferenceParameterList + + PsiErrorElement:Identifier expected + + PsiErrorElement:Unexpected token + PsiJavaToken:GT('>') + PsiWhiteSpace('\n ') + PsiField:myMissingEjbRef + PsiModifierList: + + PsiTypeElement:Runnable + PsiJavaCodeReferenceElement:Runnable + PsiIdentifier:Runnable('Runnable') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:myMissingEjbRef('myMissingEjbRef') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace('\n\n ') + PsiModifierList:public + PsiKeyword:public('public') + PsiWhiteSpace(' ') + PsiErrorElement:Identifier or type expected + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:T + PsiIdentifier:T('T') + PsiElement(EXTENDS_BOUND_LIST) + + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiMethod:m + PsiModifierList:@SafeVarargs + static + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:SafeVarargs + PsiIdentifier:SafeVarargs('SafeVarargs') + PsiReferenceParameterList + + PsiAnnotationParameterList + + PsiWhiteSpace('\n ') + PsiKeyword:static('static') + PsiTypeParameterList + + PsiWhiteSpace(' ') + PsiTypeElement:void + PsiKeyword:void('void') + PsiWhiteSpace(' ') + PsiIdentifier:m('m') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') PsiWhiteSpace('\n') PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-full/annotationParsing/annotation/TypeAnnotations.java b/java/java-tests/testData/psi/parser-full/annotationParsing/annotation/TypeAnnotations.java index 208e34387c56..de61404de20d 100644 --- a/java/java-tests/testData/psi/parser-full/annotationParsing/annotation/TypeAnnotations.java +++ b/java/java-tests/testData/psi/parser-full/annotationParsing/annotation/TypeAnnotations.java @@ -47,9 +47,10 @@ class SpecSamples { try (@A Reader r = new @B FileReader("/dev/zero"); @A Writer w = new @B FileWriter("/dev/null")) { } } - //interface TestClass { - // @Nullable List test(); - //} + interface TestClass { + @Nullable List test(); + @Positive int test(T t); + } // // 2. An annotation on a wildcard type argument appears before the wildcard ... @@ -76,7 +77,7 @@ class SpecSamples { // @Immutable SpecSamples() { } - // @Immutable SpecSamples(T t) { } + @Immutable SpecSamples(T t) { } // // todo [r.sh] 5. It is permitted to explicitly declare the method receiver as the first formal parameter ... diff --git a/java/java-tests/testData/psi/parser-full/annotationParsing/annotation/TypeAnnotations.txt b/java/java-tests/testData/psi/parser-full/annotationParsing/annotation/TypeAnnotations.txt index d1a8022925f3..0cc33a82fa2c 100644 --- a/java/java-tests/testData/psi/parser-full/annotationParsing/annotation/TypeAnnotations.txt +++ b/java/java-tests/testData/psi/parser-full/annotationParsing/annotation/TypeAnnotations.txt @@ -1045,11 +1045,103 @@ PsiJavaFile:TypeAnnotations.java PsiWhiteSpace('\n ') PsiJavaToken:RBRACE('}') PsiWhiteSpace('\n\n ') - PsiComment(END_OF_LINE_COMMENT)('//interface TestClass {') - PsiWhiteSpace('\n ') - PsiComment(END_OF_LINE_COMMENT)('// @Nullable List test();') - PsiWhiteSpace('\n ') - PsiComment(END_OF_LINE_COMMENT)('//}') + PsiClass:TestClass + PsiModifierList: + + PsiKeyword:interface('interface') + PsiWhiteSpace(' ') + PsiIdentifier:TestClass('TestClass') + PsiTypeParameterList + + PsiReferenceList + + PsiReferenceList + + PsiWhiteSpace(' ') + PsiJavaToken:LBRACE('{') + PsiWhiteSpace('\n ') + PsiMethod:test + PsiModifierList: + + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:T + PsiIdentifier:T('T') + PsiElement(EXTENDS_BOUND_LIST) + + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiTypeElement:@Nullable List + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Nullable + PsiIdentifier:Nullable('Nullable') + PsiReferenceParameterList + + PsiAnnotationParameterList + + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:List + PsiIdentifier:List('List') + PsiReferenceParameterList + PsiJavaToken:LT('<') + PsiTypeElement:T + PsiJavaCodeReferenceElement:T + PsiIdentifier:T('T') + PsiReferenceParameterList + + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiIdentifier:test('test') + PsiParameterList:() + PsiJavaToken:LPARENTH('(') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace('\n ') + PsiMethod:test + PsiModifierList: + + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:T + PsiIdentifier:T('T') + PsiElement(EXTENDS_BOUND_LIST) + + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiTypeElement:@Positive int + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Positive + PsiIdentifier:Positive('Positive') + PsiReferenceParameterList + + PsiAnnotationParameterList + + PsiWhiteSpace(' ') + PsiKeyword:int('int') + PsiWhiteSpace(' ') + PsiIdentifier:test('test') + PsiParameterList:(T t) + PsiJavaToken:LPARENTH('(') + PsiParameter:t + PsiModifierList: + + PsiTypeElement:T + PsiJavaCodeReferenceElement:T + PsiIdentifier:T('T') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:t('t') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace('\n ') + PsiJavaToken:RBRACE('}') PsiWhiteSpace('\n\n ') PsiComment(END_OF_LINE_COMMENT)('//') PsiWhiteSpace('\n ') @@ -1492,7 +1584,47 @@ PsiJavaFile:TypeAnnotations.java PsiWhiteSpace(' ') PsiJavaToken:RBRACE('}') PsiWhiteSpace('\n ') - PsiComment(END_OF_LINE_COMMENT)('// @Immutable SpecSamples(T t) { }') + PsiMethod:SpecSamples + PsiModifierList: + + PsiTypeParameterList + PsiJavaToken:LT('<') + PsiTypeParameter:T + PsiIdentifier:T('T') + PsiElement(EXTENDS_BOUND_LIST) + + PsiJavaToken:GT('>') + PsiWhiteSpace(' ') + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Immutable + PsiIdentifier:Immutable('Immutable') + PsiReferenceParameterList + + PsiAnnotationParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:SpecSamples('SpecSamples') + PsiParameterList:(T t) + PsiJavaToken:LPARENTH('(') + PsiParameter:t + PsiModifierList: + + PsiTypeElement:T + PsiJavaCodeReferenceElement:T + PsiIdentifier:T('T') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:t('t') + PsiJavaToken:RPARENTH(')') + PsiReferenceList + + PsiWhiteSpace(' ') + PsiCodeBlock + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') PsiWhiteSpace('\n\n ') PsiComment(END_OF_LINE_COMMENT)('//') PsiWhiteSpace('\n ')