PSI getter fixed: left-hand side of a binary expression can now be null

EA-35976 - IAE: FqNameUnsafe.validateFqName
This commit is contained in:
Andrey Breslav
2013-04-18 15:48:50 +04:00
parent c69e7f059d
commit 140382e280
14 changed files with 246 additions and 31 deletions
@@ -38,11 +38,18 @@ public class JetBinaryExpression extends JetExpressionImpl implements JetOperati
return visitor.visitBinaryExpression(this, data); return visitor.visitBinaryExpression(this, data);
} }
@NotNull @Nullable @IfNotParsed
public JetExpression getLeft() { public JetExpression getLeft() {
JetExpression left = findChildByClass(JetExpression.class); ASTNode node = getOperationReference().getNode().getTreePrev();
assert left != null; while (node != null) {
return left; PsiElement psi = node.getPsi();
if (psi instanceof JetExpression) {
return (JetExpression) psi;
}
node = node.getTreePrev();
}
return null;
} }
@Nullable @IfNotParsed @Nullable @IfNotParsed
@@ -175,9 +175,10 @@ public class TracingStrategyImpl implements TracingStrategy {
Name.identifier(operationReference.getText()) : Name.identifier(operationReference.getText()) :
OperatorConventions.getNameForOperationSymbol((JetToken) operationReference.getReferencedNameElementType()); OperatorConventions.getNameForOperationSymbol((JetToken) operationReference.getReferencedNameElementType());
JetExpression left = binaryExpression.getLeft();
JetExpression right = binaryExpression.getRight(); JetExpression right = binaryExpression.getRight();
if (right != null) { if (left != null && right != null) {
trace.report(UNSAFE_INFIX_CALL.on(reference, binaryExpression.getLeft().getText(), operationString.getName(), right.getText())); trace.report(UNSAFE_INFIX_CALL.on(reference, left.getText(), operationString.getName(), right.getText()));
} }
} }
else { else {
@@ -36,6 +36,7 @@ import org.jetbrains.jet.lang.resolve.calls.context.ExpressionPosition;
import org.jetbrains.jet.lang.resolve.calls.context.ResolutionResultsCache; import org.jetbrains.jet.lang.resolve.calls.context.ResolutionResultsCache;
import org.jetbrains.jet.lang.resolve.calls.context.ResolveMode; import org.jetbrains.jet.lang.resolve.calls.context.ResolveMode;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsUtil; import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsUtil;
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker; import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
import org.jetbrains.jet.lang.resolve.constants.*; import org.jetbrains.jet.lang.resolve.constants.*;
@@ -753,8 +754,13 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
JetExpression right = expression.getRight(); JetExpression right = expression.getRight();
IElementType operationType = operationSign.getReferencedNameElementType(); IElementType operationType = operationSign.getReferencedNameElementType();
JetTypeInfo leftTypeInfo = left != null
? facade.getTypeInfo(left, context)
: JetTypeInfo.create(null, context.dataFlowInfo);
JetType result = null; JetType result = null;
DataFlowInfo dataFlowInfo = context.dataFlowInfo; DataFlowInfo dataFlowInfo = context.dataFlowInfo;
if (operationType == JetTokens.IDENTIFIER) { if (operationType == JetTokens.IDENTIFIER) {
Name referencedName = operationSign.getReferencedNameAsName(); Name referencedName = operationSign.getReferencedNameAsName();
JetTypeInfo typeInfo = getTypeInfoForBinaryCall(context.scope, referencedName, context, expression); JetTypeInfo typeInfo = getTypeInfoForBinaryCall(context.scope, referencedName, context, expression);
@@ -792,10 +798,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
else { else {
JetType booleanType = KotlinBuiltIns.getInstance().getBooleanType(); JetType booleanType = KotlinBuiltIns.getInstance().getBooleanType();
if (OperatorConventions.EQUALS_OPERATIONS.contains(operationType)) { if (OperatorConventions.EQUALS_OPERATIONS.contains(operationType)) {
if (right != null) { if (right != null && left != null) {
ExpressionReceiver receiver = ExpressionTypingUtils.safeGetExpressionReceiver(facade, left, context); ExpressionReceiver receiver = ExpressionTypingUtils.safeGetExpressionReceiver(facade, left, context);
dataFlowInfo = facade.getTypeInfo(left, context).getDataFlowInfo(); dataFlowInfo = leftTypeInfo.getDataFlowInfo();
ExpressionTypingContext contextWithDataFlow = context.replaceDataFlowInfo(dataFlowInfo); ExpressionTypingContext contextWithDataFlow = context.replaceDataFlowInfo(dataFlowInfo);
OverloadResolutionResults<FunctionDescriptor> resolutionResults = resolveFakeCall( OverloadResolutionResults<FunctionDescriptor> resolutionResults = resolveFakeCall(
@@ -830,7 +836,6 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
} }
else if (OperatorConventions.IN_OPERATIONS.contains(operationType)) { else if (OperatorConventions.IN_OPERATIONS.contains(operationType)) {
if (right == null) { if (right == null) {
result = ErrorUtils.createErrorType("No right argument"); // TODO
return JetTypeInfo.create(null, dataFlowInfo); return JetTypeInfo.create(null, dataFlowInfo);
} }
JetTypeInfo typeInfo = checkInExpression(expression, expression.getOperationReference(), left, right, context); JetTypeInfo typeInfo = checkInExpression(expression, expression.getOperationReference(), left, right, context);
@@ -838,7 +843,6 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
result = typeInfo.getType(); result = typeInfo.getType();
} }
else if (OperatorConventions.BOOLEAN_OPERATIONS.containsKey(operationType)) { else if (OperatorConventions.BOOLEAN_OPERATIONS.containsKey(operationType)) {
JetTypeInfo leftTypeInfo = facade.getTypeInfo(left, context);
JetType leftType = leftTypeInfo.getType(); JetType leftType = leftTypeInfo.getType();
dataFlowInfo = leftTypeInfo.getDataFlowInfo(); dataFlowInfo = leftTypeInfo.getDataFlowInfo();
@@ -852,7 +856,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
JetType rightType = right == null JetType rightType = right == null
? null ? null
: facade.getTypeInfo(right, context.replaceDataFlowInfo(flowInfoLeft).replaceScope(rightScope)).getType(); : facade.getTypeInfo(right, context.replaceDataFlowInfo(flowInfoLeft).replaceScope(rightScope)).getType();
if (leftType != null && !isBoolean(leftType)) { if (left != null && leftType != null && !isBoolean(leftType)) {
context.trace.report(TYPE_MISMATCH.on(left, booleanType, leftType)); context.trace.report(TYPE_MISMATCH.on(left, booleanType, leftType));
} }
if (rightType != null && !isBoolean(rightType)) { if (rightType != null && !isBoolean(rightType)) {
@@ -861,11 +865,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
result = booleanType; result = booleanType;
} }
else if (operationType == JetTokens.ELVIS) { else if (operationType == JetTokens.ELVIS) {
JetTypeInfo leftTypeInfo = facade.getTypeInfo(left, context);
JetType leftType = leftTypeInfo.getType(); JetType leftType = leftTypeInfo.getType();
dataFlowInfo = leftTypeInfo.getDataFlowInfo(); dataFlowInfo = leftTypeInfo.getDataFlowInfo();
if (leftType != null) { if (left != null && leftType != null) {
if (isKnownToBeNotNull(left, leftType, context)) { if (isKnownToBeNotNull(left, leftType, context)) {
context.trace.report(USELESS_ELVIS.on(left, leftType)); context.trace.report(USELESS_ELVIS.on(left, leftType));
} }
@@ -918,6 +921,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
private void ensureNonemptyIntersectionOfOperandTypes(JetBinaryExpression expression, ExpressionTypingContext context) { private void ensureNonemptyIntersectionOfOperandTypes(JetBinaryExpression expression, ExpressionTypingContext context) {
JetExpression left = expression.getLeft(); JetExpression left = expression.getLeft();
if (left == null) return;
JetExpression right = expression.getRight(); JetExpression right = expression.getRight();
// TODO : duplicated effort for == and != // TODO : duplicated effort for == and !=
@@ -994,12 +999,20 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
) { ) {
ExpressionTypingContext context = contextWithOldScope.replaceScope(scope); ExpressionTypingContext context = contextWithOldScope.replaceScope(scope);
JetExpression left = binaryExpression.getLeft(); JetExpression left = binaryExpression.getLeft();
DataFlowInfo dataFlowInfo = facade.getTypeInfo(left, context).getDataFlowInfo(); DataFlowInfo dataFlowInfo = context.dataFlowInfo;
if (left != null) {
ExpressionReceiver receiver = safeGetExpressionReceiver(facade, left, context); dataFlowInfo = facade.getTypeInfo(left, context).getDataFlowInfo();
}
ExpressionTypingContext contextWithDataFlow = context.replaceDataFlowInfo(dataFlowInfo); ExpressionTypingContext contextWithDataFlow = context.replaceDataFlowInfo(dataFlowInfo);
OverloadResolutionResults<FunctionDescriptor> resolutionResults =
getResolutionResultsForBinaryCall(scope, name, contextWithDataFlow, binaryExpression, receiver); OverloadResolutionResults<FunctionDescriptor> resolutionResults;
if (left != null) {
ExpressionReceiver receiver = safeGetExpressionReceiver(facade, left, context);
resolutionResults = getResolutionResultsForBinaryCall(scope, name, contextWithDataFlow, binaryExpression, receiver);
}
else {
resolutionResults = OverloadResolutionResultsImpl.nameNotFound();
}
JetExpression right = binaryExpression.getRight(); JetExpression right = binaryExpression.getRight();
if (right != null) { if (right != null) {
@@ -73,6 +73,7 @@ public class DataFlowUtils {
} }
else { else {
JetExpression left = expression.getLeft(); JetExpression left = expression.getLeft();
if (left == null) return;
JetExpression right = expression.getRight(); JetExpression right = expression.getRight();
if (right == null) return; if (right == null) return;
@@ -85,6 +85,7 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetTypeInfo, E
return getTypeInfo(expression, context, this); return getTypeInfo(expression, context, this);
} }
@Override
@NotNull @NotNull
public final JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context, boolean isStatement) { public final JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context, boolean isStatement) {
if (!isStatement) return getTypeInfo(expression, context); if (!isStatement) return getTypeInfo(expression, context);
@@ -208,12 +208,15 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
JetSimpleNameExpression operationSign = expression.getOperationReference(); JetSimpleNameExpression operationSign = expression.getOperationReference();
IElementType operationType = operationSign.getReferencedNameElementType(); IElementType operationType = operationSign.getReferencedNameElementType();
JetTypeInfo leftInfo = facade.getTypeInfo(expression.getLeft(), context); JetExpression leftOperand = expression.getLeft();
JetTypeInfo leftInfo = leftOperand != null
? facade.getTypeInfo(leftOperand, context)
: JetTypeInfo.create(null, context.dataFlowInfo);
JetType leftType = leftInfo.getType(); JetType leftType = leftInfo.getType();
DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo(); DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();
JetExpression right = expression.getRight(); JetExpression right = expression.getRight();
JetExpression left = JetPsiUtil.deparenthesizeWithNoTypeResolution(expression.getLeft()); JetExpression left = leftOperand == null ? null : JetPsiUtil.deparenthesizeWithNoTypeResolution(leftOperand);
if (right == null || left == null) { if (right == null || left == null) {
temporaryBindingTrace.commit(); temporaryBindingTrace.commit();
return JetTypeInfo.create(null, dataFlowInfo); return JetTypeInfo.create(null, dataFlowInfo);
@@ -271,7 +274,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
basic.resolveArrayAccessSetMethod((JetArrayAccessExpression) left, right, contextForResolve, context.trace); basic.resolveArrayAccessSetMethod((JetArrayAccessExpression) left, right, contextForResolve, context.trace);
} }
dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo();
BasicExpressionTypingVisitor.checkLValue(context.trace, expression.getLeft()); BasicExpressionTypingVisitor.checkLValue(context.trace, leftOperand);
} }
temporaryBindingTrace.commit(); temporaryBindingTrace.commit();
return JetTypeInfo.create(checkAssignmentType(type, expression, contextWithExpectedType), dataFlowInfo); return JetTypeInfo.create(checkAssignmentType(type, expression, contextWithExpectedType), dataFlowInfo);
@@ -280,7 +283,8 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
@NotNull @NotNull
protected JetTypeInfo visitAssignment(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) { protected JetTypeInfo visitAssignment(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceScope(scope); ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceScope(scope);
JetExpression left = context.expressionTypingServices.deparenthesize(expression.getLeft(), context); JetExpression leftOperand = expression.getLeft();
JetExpression left = leftOperand == null ? null : context.expressionTypingServices.deparenthesize(leftOperand, context);
JetExpression right = expression.getRight(); JetExpression right = expression.getRight();
if (left instanceof JetArrayAccessExpression) { if (left instanceof JetArrayAccessExpression) {
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left; JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
@@ -290,15 +294,17 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
return JetTypeInfo.create(checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType), return JetTypeInfo.create(checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType),
typeInfo.getDataFlowInfo()); typeInfo.getDataFlowInfo());
} }
JetTypeInfo leftInfo = facade.getTypeInfo(expression.getLeft(), context); JetTypeInfo leftInfo = leftOperand != null
? facade.getTypeInfo(leftOperand, context)
: JetTypeInfo.create(null, context.dataFlowInfo);
JetType leftType = leftInfo.getType(); JetType leftType = leftInfo.getType();
DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo(); DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();
if (right != null) { if (right != null) {
JetTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType)); JetTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType));
dataFlowInfo = rightInfo.getDataFlowInfo(); dataFlowInfo = rightInfo.getDataFlowInfo();
} }
if (leftType != null) { //if leftType == null, some another error has been generated if (leftType != null && leftOperand != null) { //if leftType == null, some other error has been generated
BasicExpressionTypingVisitor.checkLValue(context.trace, expression.getLeft()); BasicExpressionTypingVisitor.checkLValue(context.trace, leftOperand);
} }
return DataFlowUtils.checkStatementType(expression, contextWithExpectedType, dataFlowInfo); return DataFlowUtils.checkStatementType(expression, contextWithExpectedType, dataFlowInfo);
} }
@@ -0,0 +1,15 @@
fun import() {
<!FUNCTION_CALL_EXPECTED!>import<!> <!UNRESOLVED_REFERENCE!>a<!><!SYNTAX!>.<!><!DEBUG_INFO_MISSING_UNRESOLVED!>*<!><!SYNTAX!><!>
}
fun composite() {
val <!UNUSED_VARIABLE!>s<!> = 13+<!SYNTAX!>~<!><!DEBUG_INFO_MISSING_UNRESOLVED!>/<!>12
}
fun html() {
<!SYNTAX!><<!><!FUNCTION_CALL_EXPECTED!>html<!><!UNRESOLVED_REFERENCE!>><!><!SYNTAX!><<!><!DEBUG_INFO_MISSING_UNRESOLVED!>/<!><!FUNCTION_CALL_EXPECTED!>html<!><!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>><!><!SYNTAX!><!>
}
fun html1() {
<!SYNTAX!><<!><!FUNCTION_CALL_EXPECTED!>html<!><!UNRESOLVED_REFERENCE!>><!><!SYNTAX!><<!><!DEBUG_INFO_MISSING_UNRESOLVED!>/<!><!FUNCTION_CALL_EXPECTED!>html<!><!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>><!><!FUNCTION_CALL_EXPECTED!>html<!>
}
@@ -0,0 +1,15 @@
fun import() {
import a.*
}
fun composite() {
val s = 13+~/12
}
fun html() {
<html></html>
}
fun html1() {
<html></html>html
}
@@ -0,0 +1,128 @@
JetFile: AbsentLeftHandSide.kt
NAMESPACE_HEADER
<empty list>
FUN
PsiElement(fun)('fun')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('import')
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BLOCK
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
BINARY_EXPRESSION
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('import')
PsiWhiteSpace(' ')
OPERATION_REFERENCE
PsiElement(IDENTIFIER)('a')
BINARY_EXPRESSION
PsiErrorElement:Expecting an element
PsiElement(DOT)('.')
OPERATION_REFERENCE
PsiElement(MUL)('*')
PsiErrorElement:Expecting an element
<empty list>
PsiWhiteSpace('\n')
PsiElement(RBRACE)('}')
PsiWhiteSpace('\n\n')
FUN
PsiElement(fun)('fun')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('composite')
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BLOCK
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
PROPERTY
PsiElement(val)('val')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('s')
PsiWhiteSpace(' ')
PsiElement(EQ)('=')
PsiWhiteSpace(' ')
BINARY_EXPRESSION
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('13')
OPERATION_REFERENCE
PsiElement(PLUS)('+')
BINARY_EXPRESSION
PsiErrorElement:Expecting an element
PsiElement(BAD_CHARACTER)('~')
OPERATION_REFERENCE
PsiElement(DIV)('/')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('12')
PsiWhiteSpace('\n')
PsiElement(RBRACE)('}')
PsiWhiteSpace('\n\n')
FUN
PsiElement(fun)('fun')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('html')
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BLOCK
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
PsiErrorElement:Expecting an element
PsiElement(LT)('<')
BINARY_EXPRESSION
BINARY_EXPRESSION
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('html')
OPERATION_REFERENCE
PsiElement(GT)('>')
BINARY_EXPRESSION
PsiErrorElement:Expecting an element
PsiElement(LT)('<')
OPERATION_REFERENCE
PsiElement(DIV)('/')
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('html')
OPERATION_REFERENCE
PsiElement(GT)('>')
PsiErrorElement:Expecting an element
<empty list>
PsiWhiteSpace('\n')
PsiElement(RBRACE)('}')
PsiWhiteSpace('\n\n')
FUN
PsiElement(fun)('fun')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('html1')
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BLOCK
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
PsiErrorElement:Expecting an element
PsiElement(LT)('<')
BINARY_EXPRESSION
BINARY_EXPRESSION
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('html')
OPERATION_REFERENCE
PsiElement(GT)('>')
BINARY_EXPRESSION
PsiErrorElement:Expecting an element
PsiElement(LT)('<')
OPERATION_REFERENCE
PsiElement(DIV)('/')
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('html')
OPERATION_REFERENCE
PsiElement(GT)('>')
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('html')
PsiWhiteSpace('\n')
PsiElement(RBRACE)('}')
@@ -33,7 +33,7 @@ import org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve;
@InnerTestClasses({JetDiagnosticsTestGenerated.Tests.class, JetDiagnosticsTestGenerated.Script.class}) @InnerTestClasses({JetDiagnosticsTestGenerated.Tests.class, JetDiagnosticsTestGenerated.Script.class})
public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEagerResolve { public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEagerResolve {
@TestMetadata("compiler/testData/diagnostics/tests") @TestMetadata("compiler/testData/diagnostics/tests")
@InnerTestClasses({Tests.Annotations.class, Tests.BackingField.class, Tests.Cast.class, Tests.CheckArguments.class, Tests.ControlFlowAnalysis.class, Tests.ControlStructures.class, Tests.DataClasses.class, Tests.DataFlow.class, Tests.DataFlowInfoTraversal.class, Tests.DeclarationChecks.class, Tests.Deparenthesize.class, Tests.Enum.class, Tests.Extensions.class, Tests.FunctionLiterals.class, Tests.Generics.class, Tests.IncompleteCode.class, Tests.Inference.class, Tests.Infos.class, Tests.Inner.class, Tests.J_k.class, Tests.Jdk_annotations.class, Tests.Library.class, Tests.NullabilityAndAutoCasts.class, Tests.NullableTypes.class, Tests.Objects.class, Tests.OperatorsOverloading.class, Tests.Overload.class, Tests.Override.class, Tests.Redeclarations.class, Tests.Regressions.class, Tests.Resolve.class, Tests.Scopes.class, Tests.SenselessComparison.class, Tests.Shadowing.class, Tests.SmartCasts.class, Tests.Substitutions.class, Tests.Subtyping.class, Tests.ThisAndSuper.class, Tests.Varargs.class}) @InnerTestClasses({Tests.Annotations.class, Tests.BackingField.class, Tests.Cast.class, Tests.CheckArguments.class, Tests.ControlFlowAnalysis.class, Tests.ControlStructures.class, Tests.DataClasses.class, Tests.DataFlow.class, Tests.DataFlowInfoTraversal.class, Tests.DeclarationChecks.class, Tests.Deparenthesize.class, Tests.Enum.class, Tests.Extensions.class, Tests.FunctionLiterals.class, Tests.Generics.class, Tests.IncompleteCode.class, Tests.Inference.class, Tests.Infos.class, Tests.Inner.class, Tests.J_k.class, Tests.Jdk_annotations.class, Tests.Library.class, Tests.NullabilityAndAutoCasts.class, Tests.NullableTypes.class, Tests.Objects.class, Tests.OperatorsOverloading.class, Tests.Overload.class, Tests.Override.class, Tests.Recovery.class, Tests.Redeclarations.class, Tests.Regressions.class, Tests.Resolve.class, Tests.Scopes.class, Tests.SenselessComparison.class, Tests.Shadowing.class, Tests.SmartCasts.class, Tests.Substitutions.class, Tests.Subtyping.class, Tests.ThisAndSuper.class, Tests.Varargs.class})
public static class Tests extends AbstractDiagnosticsTestWithEagerResolve { public static class Tests extends AbstractDiagnosticsTestWithEagerResolve {
@TestMetadata("Abstract.kt") @TestMetadata("Abstract.kt")
public void testAbstract() throws Exception { public void testAbstract() throws Exception {
@@ -3399,6 +3399,19 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
} }
@TestMetadata("compiler/testData/diagnostics/tests/recovery")
public static class Recovery extends AbstractDiagnosticsTestWithEagerResolve {
@TestMetadata("absentLeftHandSide.kt")
public void testAbsentLeftHandSide() throws Exception {
doTest("compiler/testData/diagnostics/tests/recovery/absentLeftHandSide.kt");
}
public void testAllFilesPresentInRecovery() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/recovery"), Pattern.compile("^(.+)\\.kt$"), true);
}
}
@TestMetadata("compiler/testData/diagnostics/tests/redeclarations") @TestMetadata("compiler/testData/diagnostics/tests/redeclarations")
public static class Redeclarations extends AbstractDiagnosticsTestWithEagerResolve { public static class Redeclarations extends AbstractDiagnosticsTestWithEagerResolve {
public void testAllFilesPresentInRedeclarations() throws Exception { public void testAllFilesPresentInRedeclarations() throws Exception {
@@ -4503,6 +4516,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
suite.addTestSuite(OperatorsOverloading.class); suite.addTestSuite(OperatorsOverloading.class);
suite.addTestSuite(Overload.class); suite.addTestSuite(Overload.class);
suite.addTestSuite(Override.class); suite.addTestSuite(Override.class);
suite.addTestSuite(Recovery.class);
suite.addTestSuite(Redeclarations.class); suite.addTestSuite(Redeclarations.class);
suite.addTestSuite(Regressions.class); suite.addTestSuite(Regressions.class);
suite.addTestSuite(Resolve.class); suite.addTestSuite(Resolve.class);
@@ -45,8 +45,11 @@ public class ReplaceInfixCallFix extends JetIntentionAction<JetBinaryExpression>
@Override @Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
String newText = element.getLeft().getText() + "?." + element.getOperationReference().getText() JetExpression left = element.getLeft();
+ "(" + element.getRight().getText() + ")"; JetExpression right = element.getRight();
assert left != null && right != null : "Preconditions checked by factory";
String newText = left.getText() + "?." + element.getOperationReference().getText()
+ "(" + right.getText() + ")";
JetQualifiedExpression newElement = (JetQualifiedExpression) JetPsiFactory.createExpression(project, newText); JetQualifiedExpression newElement = (JetQualifiedExpression) JetPsiFactory.createExpression(project, newText);
element.replace(newElement); element.replace(newElement);
} }
@@ -61,6 +64,9 @@ public class ReplaceInfixCallFix extends JetIntentionAction<JetBinaryExpression>
@Override @Override
public IntentionAction createAction(Diagnostic diagnostic) { public IntentionAction createAction(Diagnostic diagnostic) {
JetBinaryExpression expression = QuickFixUtil.getParentElementOfType(diagnostic, JetBinaryExpression.class); JetBinaryExpression expression = QuickFixUtil.getParentElementOfType(diagnostic, JetBinaryExpression.class);
if (expression == null) return null;
if (expression.getLeft() == null) return null;
if (expression.getRight() == null) return null;
return new ReplaceInfixCallFix(expression); return new ReplaceInfixCallFix(expression);
} }
}; };
@@ -23,6 +23,7 @@ import com.google.dart.compiler.backend.js.ast.JsLiteral;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetBinaryExpression; import org.jetbrains.jet.lang.psi.JetBinaryExpression;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions; import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
@@ -69,7 +70,9 @@ public final class EqualsIntrinsic implements BinaryOperationIntrinsic {
} }
private static boolean canUseSimpleEquals(@NotNull JetBinaryExpression expression, @NotNull TranslationContext context) { private static boolean canUseSimpleEquals(@NotNull JetBinaryExpression expression, @NotNull TranslationContext context) {
Name typeName = JsDescriptorUtils.getNameIfStandardType(expression.getLeft(), context); JetExpression left = expression.getLeft();
assert left != null : "No left-hand side: " + expression.getText();
Name typeName = JsDescriptorUtils.getNameIfStandardType(left, context);
return typeName != null && NamePredicate.PRIMITIVE_NUMBERS.apply(typeName); return typeName != null && NamePredicate.PRIMITIVE_NUMBERS.apply(typeName);
} }
} }
@@ -19,6 +19,7 @@ package org.jetbrains.k2js.translate.operation;
import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.backend.js.ast.JsExpression;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetBinaryExpression; import org.jetbrains.jet.lang.psi.JetBinaryExpression;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions; import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
import org.jetbrains.jet.lexer.JetToken; import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.context.TranslationContext;
@@ -61,7 +62,9 @@ public abstract class AssignmentTranslator extends AbstractTranslator {
super(context); super(context);
this.expression = expression; this.expression = expression;
this.isVariableReassignment = isVariableReassignment(context.bindingContext(), expression); this.isVariableReassignment = isVariableReassignment(context.bindingContext(), expression);
this.accessTranslator = AccessTranslationUtils.getAccessTranslator(expression.getLeft(), context()); JetExpression left = expression.getLeft();
assert left != null : "No left-hand side: " + expression.getText();
this.accessTranslator = AccessTranslationUtils.getAccessTranslator(left, context());
this.right = translateRightExpression(context(), expression); this.right = translateRightExpression(context(), expression);
} }
} }
@@ -153,7 +153,9 @@ public final class TranslationUtils {
@NotNull @NotNull
public static JsExpression translateLeftExpression(@NotNull TranslationContext context, public static JsExpression translateLeftExpression(@NotNull TranslationContext context,
@NotNull JetBinaryExpression expression) { @NotNull JetBinaryExpression expression) {
return Translation.translateAsExpression(expression.getLeft(), context); JetExpression left = expression.getLeft();
assert left != null : "Binary expression should have a left expression: " + expression.getText();
return Translation.translateAsExpression(left, context);
} }
@NotNull @NotNull