Validate getters marked as nullable on parse error only return null if there's a parse error.

This commit is contained in:
Maxim Shafirov
2011-01-11 02:57:10 +03:00
parent 6cf565dcf5
commit 7ac9173d14
25 changed files with 83 additions and 46 deletions
@@ -108,6 +108,7 @@ public interface JetNodeTypes {
JetNodeType DOT_QIALIFIED_EXPRESSION = new JetNodeType("DOT_QIALIFIED_EXPRESSION", JetDotQualifiedExpression.class); JetNodeType DOT_QIALIFIED_EXPRESSION = new JetNodeType("DOT_QIALIFIED_EXPRESSION", JetDotQualifiedExpression.class);
JetNodeType HASH_QIALIFIED_EXPRESSION = new JetNodeType("HASH_QIALIFIED_EXPRESSION", JetHashQualifiedExpression.class); JetNodeType HASH_QIALIFIED_EXPRESSION = new JetNodeType("HASH_QIALIFIED_EXPRESSION", JetHashQualifiedExpression.class);
JetNodeType SAFE_ACCESS_EXPRESSION = new JetNodeType("SAFE_ACCESS_EXPRESSION", JetSafeQualifiedExpression.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_BLOCK = new JetNodeType("MATCH_BLOCK", JetMatchBlock.class);
JetNodeType MATCH_ENTRY = new JetNodeType("MATCH_ENTRY"); JetNodeType MATCH_ENTRY = new JetNodeType("MATCH_ENTRY");
JetNodeType PATTERN = new JetNodeType("PATTERN"); JetNodeType PATTERN = new JetNodeType("PATTERN");
@@ -856,8 +856,14 @@ public class JetExpressionParsing extends AbstractJetParsing {
*/ */
private void parseControlStructureBody() { private void parseControlStructureBody() {
PsiBuilder.Marker body = mark(); PsiBuilder.Marker body = mark();
if (!at(SEMICOLON)) if (at(SEMICOLON)) {
PsiBuilder.Marker mark = mark();
advance();
mark.done(EMPTY_EXPRESSION);
}
else {
parseExpression(); parseExpression();
}
body.done(BODY); body.done(BODY);
} }
@@ -17,7 +17,7 @@ public class JetArgument extends JetElement {
visitor.visitArgument(this); visitor.visitArgument(this);
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetExpression getArgumentExpression() { public JetExpression getArgumentExpression() {
return findChildByClass(JetExpression.class); return findChildByClass(JetExpression.class);
} }
@@ -21,9 +21,9 @@ public class JetAttribute extends JetElement {
visitor.visitAttribute(this); visitor.visitAttribute(this);
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetTypeReference getTypeReference() { public JetUserType getTypeReference() {
return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE); return (JetUserType) findChildByType(JetNodeTypes.USER_TYPE);
} }
@Nullable @Nullable
@@ -27,7 +27,7 @@ public class JetBinaryExpression extends JetExpression {
return left; return left;
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetExpression getRight() { public JetExpression getRight() {
ASTNode node = getOperationTokenNode(); ASTNode node = getOperationTokenNode();
while (node != null) { while (node != null) {
@@ -27,7 +27,7 @@ public class JetBinaryExpressionWithTypeRHS extends JetExpression {
return left; return left;
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetTypeReference getRight() { public JetTypeReference getRight() {
ASTNode node = getOperationTokenNode(); ASTNode node = getOperationTokenNode();
while (node != null) { while (node != null) {
@@ -20,12 +20,12 @@ public class JetCatchSection extends JetElement {
visitor.visitCatchSection(this); visitor.visitCatchSection(this);
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetParameterList getParameterList() { public JetParameterList getParameterList() {
return (JetParameterList) findChildByType(JetNodeTypes.VALUE_PARAMETER_LIST); return (JetParameterList) findChildByType(JetNodeTypes.VALUE_PARAMETER_LIST);
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetParameter getCatchParameter() { public JetParameter getCatchParameter() {
JetParameterList list = getParameterList(); JetParameterList list = getParameterList();
if (list == null) return null; if (list == null) return null;
@@ -34,7 +34,7 @@ public class JetCatchSection extends JetElement {
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetExpression getCatchBody() { public JetExpression getCatchBody() {
return findChildByClass(JetExpression.class); return findChildByClass(JetExpression.class);
} }
@@ -21,7 +21,7 @@ public class JetConstructor extends JetDeclaration {
visitor.visitConstructor(this); visitor.visitConstructor(this);
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetParameterList getParameterList() { public JetParameterList getParameterList() {
return (JetParameterList) findChildByType(JetNodeTypes.VALUE_PARAMETER_LIST); return (JetParameterList) findChildByType(JetNodeTypes.VALUE_PARAMETER_LIST);
} }
@@ -21,7 +21,7 @@ public class JetDecomposer extends JetNamedDeclaration {
visitor.visitDecomposer(this); visitor.visitDecomposer(this);
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetDecomposerPropertyList getPropertyList() { public JetDecomposerPropertyList getPropertyList() {
return (JetDecomposerPropertyList) findChildByType(JetNodeTypes.DECOMPOSER_PROPERTY_LIST); return (JetDecomposerPropertyList) findChildByType(JetNodeTypes.DECOMPOSER_PROPERTY_LIST);
} }
@@ -18,12 +18,12 @@ public class JetDoWhileExpression extends JetExpression {
visitor.visitDoWhileExpression(this); visitor.visitDoWhileExpression(this);
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetExpression getCondition() { public JetExpression getCondition() {
return findExpressionUnder(JetNodeTypes.CONDITION); return findExpressionUnder(JetNodeTypes.CONDITION);
} }
@Nullable(IF_NOT_PARSED) @Nullable
public JetExpression getBody() { public JetExpression getBody() {
return findExpressionUnder(JetNodeTypes.BODY); return findExpressionUnder(JetNodeTypes.BODY);
} }
@@ -7,6 +7,11 @@ import com.intellij.psi.PsiElementVisitor;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.JetLanguage; 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 * @author max
*/ */
@@ -15,7 +20,12 @@ public class JetElement extends ASTWrapperPsiElement {
super(node); 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 @NotNull
@Override @Override
@@ -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);
}
}
@@ -29,7 +29,7 @@ public class JetExtension extends JetTypeParameterListOwner {
return body.getDeclarations(); return body.getDeclarations();
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetTypeReference getTargetTypeRef() { public JetTypeReference getTargetTypeRef() {
return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE); return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE);
} }
@@ -24,7 +24,7 @@ public class JetFunction extends JetTypeParameterListOwner {
visitor.visitFunction(this); visitor.visitFunction(this);
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetParameterList getParameterList() { public JetParameterList getParameterList() {
return (JetParameterList) findChildByType(JetNodeTypes.VALUE_PARAMETER_LIST); return (JetParameterList) findChildByType(JetNodeTypes.VALUE_PARAMETER_LIST);
} }
@@ -18,12 +18,12 @@ public class JetIfExpression extends JetExpression {
visitor.visitIfExpression(this); visitor.visitIfExpression(this);
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetExpression getCondition() { public JetExpression getCondition() {
return findExpressionUnder(JetNodeTypes.CONDITION); return findExpressionUnder(JetNodeTypes.CONDITION);
} }
@Nullable(IF_NOT_PARSED) @Nullable
public JetExpression getThen() { public JetExpression getThen() {
return findExpressionUnder(JetNodeTypes.THEN); return findExpressionUnder(JetNodeTypes.THEN);
} }
@@ -25,7 +25,7 @@ public class JetMatchExpression extends JetExpression {
return left; return left;
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetMatchBlock getMatchBlock() { public JetMatchBlock getMatchBlock() {
return (JetMatchBlock) findChildByType(JetNodeTypes.MATCH_BLOCK); return (JetMatchBlock) findChildByType(JetNodeTypes.MATCH_BLOCK);
} }
@@ -21,7 +21,7 @@ public class JetNewExpression extends JetExpression {
visitor.visitNewExpression(this); visitor.visitNewExpression(this);
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetTypeReference getTypeReference() { public JetTypeReference getTypeReference() {
return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE); return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE);
} }
@@ -22,7 +22,7 @@ public abstract class JetQualifiedExpression extends JetExpression {
return left; return left;
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetExpression getSelectorExpression() { public JetExpression getSelectorExpression() {
ASTNode node = getOperationTokenNode(); ASTNode node = getOperationTokenNode();
while (node != null) { while (node != null) {
@@ -17,7 +17,7 @@ public class JetThrowExpression extends JetExpression {
visitor.visitThrowExpression(this); visitor.visitThrowExpression(this);
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetExpression getThrownExpression() { public JetExpression getThrownExpression() {
return findChildByClass(JetExpression.class); return findChildByClass(JetExpression.class);
} }
@@ -25,7 +25,7 @@ public class JetTypeConstraint extends JetElement {
findChildByType(JetTokens.OBJECT_KEYWORD) != null; findChildByType(JetTokens.OBJECT_KEYWORD) != null;
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetTypeReference getSubjectTypeReference() { public JetTypeReference getSubjectTypeReference() {
ASTNode node = getNode().getFirstChildNode(); ASTNode node = getNode().getFirstChildNode();
while (node != null) { while (node != null) {
@@ -38,7 +38,7 @@ public class JetTypeConstraint extends JetElement {
return null; return null;
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetTypeReference getExtendsTypeReference() { public JetTypeReference getExtendsTypeReference() {
boolean passedColon = false; boolean passedColon = false;
ASTNode node = getNode().getFirstChildNode(); ASTNode node = getNode().getFirstChildNode();
@@ -18,7 +18,7 @@ public class JetTypedef extends JetTypeParameterListOwner {
visitor.visitTypedef(this); visitor.visitTypedef(this);
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetTypeReference getTypeReference() { public JetTypeReference getTypeReference() {
return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE); return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE);
} }
@@ -325,4 +325,8 @@ public class JetVisitor extends PsiElementVisitor {
public void visitMatchBlock(JetMatchBlock block) { public void visitMatchBlock(JetMatchBlock block) {
visitJetElement(block); visitJetElement(block);
} }
public void visitEmptyExpression(JetEmptyExpression expression) {
visitExpression(expression);
}
} }
@@ -18,12 +18,12 @@ public class JetWhileExpression extends JetExpression {
visitor.visitWhileExpression(this); visitor.visitWhileExpression(this);
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetExpression getCondition() { public JetExpression getCondition() {
return findExpressionUnder(JetNodeTypes.CONDITION); return findExpressionUnder(JetNodeTypes.CONDITION);
} }
@Nullable(IF_NOT_PARSED) @Nullable @IfNotParsed
public JetExpression getBody() { public JetExpression getBody() {
return findExpressionUnder(JetNodeTypes.BODY); return findExpressionUnder(JetNodeTypes.BODY);
} }
+4 -4
View File
@@ -642,8 +642,8 @@ JetFile: ControlStructures.jet
PsiElement(IDENTIFIER)('b') PsiElement(IDENTIFIER)('b')
PsiElement(RPAR)(')') PsiElement(RPAR)(')')
BODY BODY
<empty list> EMPTY_EXPRESSION
PsiElement(SEMICOLON)(';') PsiElement(SEMICOLON)(';')
PsiWhiteSpace('\n ') PsiWhiteSpace('\n ')
REFERENCE_EXPRESSION REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('b') PsiElement(IDENTIFIER)('b')
@@ -707,8 +707,8 @@ JetFile: ControlStructures.jet
PsiElement(IDENTIFIER)('b') PsiElement(IDENTIFIER)('b')
PsiElement(RPAR)(')') PsiElement(RPAR)(')')
BODY BODY
<empty list> EMPTY_EXPRESSION
PsiElement(SEMICOLON)(';') PsiElement(SEMICOLON)(';')
PsiWhiteSpace('\n ') PsiWhiteSpace('\n ')
REFERENCE_EXPRESSION REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('b') PsiElement(IDENTIFIER)('b')
@@ -10,15 +10,14 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.testFramework.ParsingTestCase; import com.intellij.testFramework.ParsingTestCase;
import junit.framework.TestSuite; import junit.framework.TestSuite;
import org.jetbrains.annotations.NonNls; 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.JetElement;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetVisitor; import org.jetbrains.jet.lang.psi.JetVisitor;
import java.io.File; import java.io.File;
import java.io.FileFilter; import java.io.FileFilter;
import java.io.FilenameFilter; import java.io.FilenameFilter;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@@ -61,17 +60,6 @@ public class JetParsingTest extends ParsingTestCase {
throw new RuntimeException(throwable); 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); super.checkResult(targetDataName, file);
@@ -85,7 +73,17 @@ public class JetParsingTest extends ParsingTestCase {
Class<?> declaringClass = method.getDeclaringClass(); Class<?> declaringClass = method.getDeclaringClass();
if (!declaringClass.getName().startsWith("org.jetbrains.jet")) continue; 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));
}
}
}
} }
} }