diff --git a/idea/src/org/jetbrains/jet/JetNodeTypes.java b/idea/src/org/jetbrains/jet/JetNodeTypes.java index 052dec313e7..9bcb075f802 100644 --- a/idea/src/org/jetbrains/jet/JetNodeTypes.java +++ b/idea/src/org/jetbrains/jet/JetNodeTypes.java @@ -108,6 +108,7 @@ public interface JetNodeTypes { JetNodeType DOT_QIALIFIED_EXPRESSION = new JetNodeType("DOT_QIALIFIED_EXPRESSION", JetDotQualifiedExpression.class); JetNodeType HASH_QIALIFIED_EXPRESSION = new JetNodeType("HASH_QIALIFIED_EXPRESSION", JetHashQualifiedExpression.class); JetNodeType SAFE_ACCESS_EXPRESSION = new JetNodeType("SAFE_ACCESS_EXPRESSION", JetSafeQualifiedExpression.class); + JetNodeType EMPTY_EXPRESSION = new JetNodeType("EMPTY_EXPRESSION", JetEmptyExpression.class); JetNodeType MATCH_BLOCK = new JetNodeType("MATCH_BLOCK", JetMatchBlock.class); JetNodeType MATCH_ENTRY = new JetNodeType("MATCH_ENTRY"); JetNodeType PATTERN = new JetNodeType("PATTERN"); diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java index 40817fedde5..fd62c4fff05 100644 --- a/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java +++ b/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java @@ -856,8 +856,14 @@ public class JetExpressionParsing extends AbstractJetParsing { */ private void parseControlStructureBody() { PsiBuilder.Marker body = mark(); - if (!at(SEMICOLON)) + if (at(SEMICOLON)) { + PsiBuilder.Marker mark = mark(); + advance(); + mark.done(EMPTY_EXPRESSION); + } + else { parseExpression(); + } body.done(BODY); } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetArgument.java b/idea/src/org/jetbrains/jet/lang/psi/JetArgument.java index 9d4bf669d36..a66ae80d56f 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetArgument.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetArgument.java @@ -17,7 +17,7 @@ public class JetArgument extends JetElement { visitor.visitArgument(this); } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetExpression getArgumentExpression() { return findChildByClass(JetExpression.class); } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetAttribute.java b/idea/src/org/jetbrains/jet/lang/psi/JetAttribute.java index b3dd2d19b96..2e756105762 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetAttribute.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetAttribute.java @@ -21,9 +21,9 @@ public class JetAttribute extends JetElement { visitor.visitAttribute(this); } - @Nullable(IF_NOT_PARSED) - public JetTypeReference getTypeReference() { - return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE); + @Nullable @IfNotParsed + public JetUserType getTypeReference() { + return (JetUserType) findChildByType(JetNodeTypes.USER_TYPE); } @Nullable diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetBinaryExpression.java b/idea/src/org/jetbrains/jet/lang/psi/JetBinaryExpression.java index b18da975842..70fd8a3742b 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetBinaryExpression.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetBinaryExpression.java @@ -27,7 +27,7 @@ public class JetBinaryExpression extends JetExpression { return left; } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetExpression getRight() { ASTNode node = getOperationTokenNode(); while (node != null) { diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetBinaryExpressionWithTypeRHS.java b/idea/src/org/jetbrains/jet/lang/psi/JetBinaryExpressionWithTypeRHS.java index dc2e5416e90..ec0a2dbd041 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetBinaryExpressionWithTypeRHS.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetBinaryExpressionWithTypeRHS.java @@ -27,7 +27,7 @@ public class JetBinaryExpressionWithTypeRHS extends JetExpression { return left; } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetTypeReference getRight() { ASTNode node = getOperationTokenNode(); while (node != null) { diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetCatchSection.java b/idea/src/org/jetbrains/jet/lang/psi/JetCatchSection.java index 9ae812262f1..f4de230cdc3 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetCatchSection.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetCatchSection.java @@ -20,12 +20,12 @@ public class JetCatchSection extends JetElement { visitor.visitCatchSection(this); } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetParameterList getParameterList() { return (JetParameterList) findChildByType(JetNodeTypes.VALUE_PARAMETER_LIST); } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetParameter getCatchParameter() { JetParameterList list = getParameterList(); if (list == null) return null; @@ -34,7 +34,7 @@ public class JetCatchSection extends JetElement { } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetExpression getCatchBody() { return findChildByClass(JetExpression.class); } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetConstructor.java b/idea/src/org/jetbrains/jet/lang/psi/JetConstructor.java index f1d12827dd8..88ef96e8bb5 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetConstructor.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetConstructor.java @@ -21,7 +21,7 @@ public class JetConstructor extends JetDeclaration { visitor.visitConstructor(this); } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetParameterList getParameterList() { return (JetParameterList) findChildByType(JetNodeTypes.VALUE_PARAMETER_LIST); } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetDecomposer.java b/idea/src/org/jetbrains/jet/lang/psi/JetDecomposer.java index 7d87d4ed22b..1bea6ac6912 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetDecomposer.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetDecomposer.java @@ -21,7 +21,7 @@ public class JetDecomposer extends JetNamedDeclaration { visitor.visitDecomposer(this); } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetDecomposerPropertyList getPropertyList() { return (JetDecomposerPropertyList) findChildByType(JetNodeTypes.DECOMPOSER_PROPERTY_LIST); } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetDoWhileExpression.java b/idea/src/org/jetbrains/jet/lang/psi/JetDoWhileExpression.java index 5263b926911..153b429aed4 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetDoWhileExpression.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetDoWhileExpression.java @@ -18,12 +18,12 @@ public class JetDoWhileExpression extends JetExpression { visitor.visitDoWhileExpression(this); } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetExpression getCondition() { return findExpressionUnder(JetNodeTypes.CONDITION); } - @Nullable(IF_NOT_PARSED) + @Nullable public JetExpression getBody() { return findExpressionUnder(JetNodeTypes.BODY); } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetElement.java b/idea/src/org/jetbrains/jet/lang/psi/JetElement.java index 8ec901ce218..692e34a21c2 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetElement.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetElement.java @@ -7,6 +7,11 @@ import com.intellij.psi.PsiElementVisitor; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.JetLanguage; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + /** * @author max */ @@ -15,7 +20,12 @@ public class JetElement extends ASTWrapperPsiElement { super(node); } - protected static final String IF_NOT_PARSED = "Returns null if has parsing error"; + /** + * Comes along with @Nullable to indicate null is only possible if parsing error present + */ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD}) + public static @interface IfNotParsed {} @NotNull @Override diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetEmptyExpression.java b/idea/src/org/jetbrains/jet/lang/psi/JetEmptyExpression.java new file mode 100644 index 00000000000..10de8856ffb --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/psi/JetEmptyExpression.java @@ -0,0 +1,18 @@ +package org.jetbrains.jet.lang.psi; + +import com.intellij.lang.ASTNode; +import org.jetbrains.annotations.NotNull; + +/** + * @author max + */ +public class JetEmptyExpression extends JetExpression { + public JetEmptyExpression(@NotNull ASTNode node) { + super(node); + } + + @Override + public void accept(JetVisitor visitor) { + visitor.visitEmptyExpression(this); + } +} diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetExtension.java b/idea/src/org/jetbrains/jet/lang/psi/JetExtension.java index 9ccf90dba1e..d931b077191 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetExtension.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetExtension.java @@ -29,7 +29,7 @@ public class JetExtension extends JetTypeParameterListOwner { return body.getDeclarations(); } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetTypeReference getTargetTypeRef() { return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE); } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetFunction.java b/idea/src/org/jetbrains/jet/lang/psi/JetFunction.java index 9fc2de3727d..a7b113d5cc1 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetFunction.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetFunction.java @@ -24,7 +24,7 @@ public class JetFunction extends JetTypeParameterListOwner { visitor.visitFunction(this); } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetParameterList getParameterList() { return (JetParameterList) findChildByType(JetNodeTypes.VALUE_PARAMETER_LIST); } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetIfExpression.java b/idea/src/org/jetbrains/jet/lang/psi/JetIfExpression.java index 190663f8a9d..d9bed419521 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetIfExpression.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetIfExpression.java @@ -18,12 +18,12 @@ public class JetIfExpression extends JetExpression { visitor.visitIfExpression(this); } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetExpression getCondition() { return findExpressionUnder(JetNodeTypes.CONDITION); } - @Nullable(IF_NOT_PARSED) + @Nullable public JetExpression getThen() { return findExpressionUnder(JetNodeTypes.THEN); } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetMatchExpression.java b/idea/src/org/jetbrains/jet/lang/psi/JetMatchExpression.java index d5ee2bb03a5..3667969103c 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetMatchExpression.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetMatchExpression.java @@ -25,7 +25,7 @@ public class JetMatchExpression extends JetExpression { return left; } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetMatchBlock getMatchBlock() { return (JetMatchBlock) findChildByType(JetNodeTypes.MATCH_BLOCK); } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetNewExpression.java b/idea/src/org/jetbrains/jet/lang/psi/JetNewExpression.java index 40e6bad4d0f..3b84c048c7f 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetNewExpression.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetNewExpression.java @@ -21,7 +21,7 @@ public class JetNewExpression extends JetExpression { visitor.visitNewExpression(this); } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetTypeReference getTypeReference() { return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE); } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetQualifiedExpression.java b/idea/src/org/jetbrains/jet/lang/psi/JetQualifiedExpression.java index 8f21266e085..1ad7ed9fa99 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetQualifiedExpression.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetQualifiedExpression.java @@ -22,7 +22,7 @@ public abstract class JetQualifiedExpression extends JetExpression { return left; } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetExpression getSelectorExpression() { ASTNode node = getOperationTokenNode(); while (node != null) { diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetThrowExpression.java b/idea/src/org/jetbrains/jet/lang/psi/JetThrowExpression.java index c66a2e1d825..4f61ea81d0e 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetThrowExpression.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetThrowExpression.java @@ -17,7 +17,7 @@ public class JetThrowExpression extends JetExpression { visitor.visitThrowExpression(this); } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetExpression getThrownExpression() { return findChildByClass(JetExpression.class); } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetTypeConstraint.java b/idea/src/org/jetbrains/jet/lang/psi/JetTypeConstraint.java index e18fad3bde8..6a1567075e5 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetTypeConstraint.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetTypeConstraint.java @@ -25,7 +25,7 @@ public class JetTypeConstraint extends JetElement { findChildByType(JetTokens.OBJECT_KEYWORD) != null; } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetTypeReference getSubjectTypeReference() { ASTNode node = getNode().getFirstChildNode(); while (node != null) { @@ -38,7 +38,7 @@ public class JetTypeConstraint extends JetElement { return null; } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetTypeReference getExtendsTypeReference() { boolean passedColon = false; ASTNode node = getNode().getFirstChildNode(); diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetTypedef.java b/idea/src/org/jetbrains/jet/lang/psi/JetTypedef.java index bf7838e6164..e738af0bd11 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetTypedef.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetTypedef.java @@ -18,7 +18,7 @@ public class JetTypedef extends JetTypeParameterListOwner { visitor.visitTypedef(this); } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetTypeReference getTypeReference() { return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE); } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetVisitor.java b/idea/src/org/jetbrains/jet/lang/psi/JetVisitor.java index 76fe7a5afe3..622280009e7 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetVisitor.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetVisitor.java @@ -325,4 +325,8 @@ public class JetVisitor extends PsiElementVisitor { public void visitMatchBlock(JetMatchBlock block) { visitJetElement(block); } + + public void visitEmptyExpression(JetEmptyExpression expression) { + visitExpression(expression); + } } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetWhileExpression.java b/idea/src/org/jetbrains/jet/lang/psi/JetWhileExpression.java index 61ab7666661..e6eb44165bc 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetWhileExpression.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetWhileExpression.java @@ -18,12 +18,12 @@ public class JetWhileExpression extends JetExpression { visitor.visitWhileExpression(this); } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetExpression getCondition() { return findExpressionUnder(JetNodeTypes.CONDITION); } - @Nullable(IF_NOT_PARSED) + @Nullable @IfNotParsed public JetExpression getBody() { return findExpressionUnder(JetNodeTypes.BODY); } diff --git a/idea/testData/psi/ControlStructures.txt b/idea/testData/psi/ControlStructures.txt index 8002e61c255..679dd747f83 100644 --- a/idea/testData/psi/ControlStructures.txt +++ b/idea/testData/psi/ControlStructures.txt @@ -642,8 +642,8 @@ JetFile: ControlStructures.jet PsiElement(IDENTIFIER)('b') PsiElement(RPAR)(')') BODY - - PsiElement(SEMICOLON)(';') + EMPTY_EXPRESSION + PsiElement(SEMICOLON)(';') PsiWhiteSpace('\n ') REFERENCE_EXPRESSION PsiElement(IDENTIFIER)('b') @@ -707,8 +707,8 @@ JetFile: ControlStructures.jet PsiElement(IDENTIFIER)('b') PsiElement(RPAR)(')') BODY - - PsiElement(SEMICOLON)(';') + EMPTY_EXPRESSION + PsiElement(SEMICOLON)(';') PsiWhiteSpace('\n ') REFERENCE_EXPRESSION PsiElement(IDENTIFIER)('b') diff --git a/idea/tests/org/jetbrains/jet/parsing/JetParsingTest.java b/idea/tests/org/jetbrains/jet/parsing/JetParsingTest.java index 7cc2b58a512..bd55adda635 100644 --- a/idea/tests/org/jetbrains/jet/parsing/JetParsingTest.java +++ b/idea/tests/org/jetbrains/jet/parsing/JetParsingTest.java @@ -10,15 +10,14 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.testFramework.ParsingTestCase; import junit.framework.TestSuite; import org.jetbrains.annotations.NonNls; -import org.jetbrains.jet.lang.psi.JetBinaryExpression; import org.jetbrains.jet.lang.psi.JetElement; -import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetVisitor; import java.io.File; import java.io.FileFilter; import java.io.FilenameFilter; import java.io.IOException; +import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; @@ -61,17 +60,6 @@ public class JetParsingTest extends ParsingTestCase { throw new RuntimeException(throwable); } } - - @Override - public void visitBinaryExpression(JetBinaryExpression expression) { - super.visitBinaryExpression(expression); - JetExpression right = expression.getRight(); - JetExpression left = expression.getLeft(); - assertNotSame(left, right); - if (right == null) { - assertNotNull("Imcomplete binary operation in parsed OK test", PsiTreeUtil.findChildOfType(expression, PsiErrorElement.class) != null); - } - } }); super.checkResult(targetDataName, file); @@ -85,7 +73,17 @@ public class JetParsingTest extends ParsingTestCase { Class declaringClass = method.getDeclaringClass(); if (!declaringClass.getName().startsWith("org.jetbrains.jet")) continue; - method.invoke(elem); + Object result = method.invoke(elem); + if (result == null) { + for (Annotation annotation : method.getDeclaredAnnotations()) { + if (annotation instanceof JetElement.IfNotParsed) { + assertNotNull( + "Imcomplete operation in parsed OK test, method " + method.getName() + + " in " + declaringClass.getSimpleName() + " returns null. Element text: \n" + elem.getText(), + PsiTreeUtil.findChildOfType(elem, PsiErrorElement.class)); + } + } + } } }