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 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");
@@ -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);
}
@@ -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);
}
@@ -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
@@ -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) {
@@ -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) {
@@ -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);
}
@@ -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);
}
@@ -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);
}
@@ -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);
}
@@ -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
@@ -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();
}
@Nullable(IF_NOT_PARSED)
@Nullable @IfNotParsed
public JetTypeReference getTargetTypeRef() {
return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE);
}
@@ -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);
}
@@ -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);
}
@@ -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);
}
@@ -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);
}
@@ -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) {
@@ -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);
}
@@ -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();
@@ -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);
}
@@ -325,4 +325,8 @@ public class JetVisitor extends PsiElementVisitor {
public void visitMatchBlock(JetMatchBlock block) {
visitJetElement(block);
}
public void visitEmptyExpression(JetEmptyExpression expression) {
visitExpression(expression);
}
}
@@ -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);
}
+4 -4
View File
@@ -642,8 +642,8 @@ JetFile: ControlStructures.jet
PsiElement(IDENTIFIER)('b')
PsiElement(RPAR)(')')
BODY
<empty list>
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
<empty list>
PsiElement(SEMICOLON)(';')
EMPTY_EXPRESSION
PsiElement(SEMICOLON)(';')
PsiWhiteSpace('\n ')
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('b')
@@ -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));
}
}
}
}
}