提交 d5266dde 编写于 作者: A Andrey Breslav

KT-33 Provide method descriptors for both getter and setter when accessing collections via []

上级 93240981
......@@ -36,6 +36,9 @@ public interface BindingContext {
WritableSlice<JetExpression, CallableDescriptor> LOOP_RANGE_HAS_NEXT = Slices.createSimpleSlice("LOOP_RANGE_HAS_NEXT");
WritableSlice<JetExpression, FunctionDescriptor> LOOP_RANGE_NEXT = Slices.createSimpleSlice("LOOP_RANGE_NEXT");
WritableSlice<JetExpression, FunctionDescriptor> INDEXED_LVALUE_GET = Slices.createSimpleSlice("INDEXED_LVALUE_GET");
WritableSlice<JetExpression, FunctionDescriptor> INDEXED_LVALUE_SET = Slices.createSimpleSlice("INDEXED_LVALUE_SET");
WritableSlice<JetExpression, JetType> AUTOCAST = Slices.createSimpleSlice("AUTOCAST");
WritableSlice<JetExpression, JetScope> RESOLUTION_SCOPE = Slices.createSimpleSlice("RESOLUTION_SCOPE");
......
......@@ -165,12 +165,16 @@ public class CallMaker {
return makeCall(expression, baseAsReceiver, null, expression.getOperationSign(), Collections.<ValueArgument>emptyList());
}
public static Call makeCall(@NotNull ReceiverDescriptor arrayAsReceiver,JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide) {
public static Call makeArraySetCall(@NotNull ReceiverDescriptor arrayAsReceiver, JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide) {
List<JetExpression> arguments = Lists.newArrayList(arrayAccessExpression.getIndexExpressions());
arguments.add(rightHandSide);
return makeCallWithExpressions(arrayAccessExpression, arrayAsReceiver, null, arrayAccessExpression, arguments);
}
public static Call makeArrayGetCall(@NotNull ReceiverDescriptor arrayAsReceiver, JetArrayAccessExpression arrayAccessExpression) {
return makeCallWithExpressions(arrayAccessExpression, arrayAsReceiver, null, arrayAccessExpression, arrayAccessExpression.getIndexExpressions());
}
public static ValueArgument makeValueArgument(@NotNull JetExpression expression) {
return makeValueArgument(expression, expression);
}
......
......@@ -246,7 +246,7 @@ public class ExpressionTypingServices {
}
}
if (mightBeUnit) {
// ExpressionTypingVisitorWithWritableScope should return only null or Unit for declarations and assignments
// ExpressionTypingVisitorForStatements should return only null or Unit for declarations and assignments
assert result == null || JetStandardClasses.isUnit(result);
result = JetStandardClasses.getUnitType();
}
......
......@@ -38,7 +38,7 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetType, Expre
return new ExpressionTypingVisitorDispatcher(new Function<ExpressionTypingInternals, BasicExpressionTypingVisitor>() {
@Override
public BasicExpressionTypingVisitor fun(ExpressionTypingInternals facade) {
return new ExpressionTypingVisitorWithWritableScope(facade, writableScope);
return new ExpressionTypingVisitorForStatements(facade, writableScope);
}
});
}
......
......@@ -11,24 +11,39 @@ import org.jetbrains.jet.lang.resolve.TopDownAnalyzer;
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.lexer.JetTokens;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_GET;
import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_SET;
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.getExpressionReceiver;
/**
* @author abreslav
*/
public class ExpressionTypingVisitorWithWritableScope extends BasicExpressionTypingVisitor {
public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingVisitor {
private final WritableScope scope;
public ExpressionTypingVisitorWithWritableScope(@NotNull ExpressionTypingInternals facade, @NotNull WritableScope scope) {
public ExpressionTypingVisitorForStatements(@NotNull ExpressionTypingInternals facade, @NotNull WritableScope scope) {
super(facade);
this.scope = scope;
}
@Nullable
private JetType checkExpectedType(JetExpression expression, ExpressionTypingContext context) {
if (context.expectedType != TypeUtils.NO_EXPECTED_TYPE) {
if (JetStandardClasses.isUnit(context.expectedType)) {
return JetStandardClasses.getUnitType();
}
context.trace.report(EXPECTED_TYPE_MISMATCH.on(expression, context.expectedType));
}
return null;
}
@Override
public JetType visitObjectDeclaration(JetObjectDeclaration declaration, ExpressionTypingContext context) {
TopDownAnalyzer.processObject(context.semanticServices, context.trace, scope, scope.getContainingDeclaration(), declaration);
......@@ -93,17 +108,24 @@ public class ExpressionTypingVisitorWithWritableScope extends BasicExpressionTyp
@Override
protected JetType visitAssignmentOperation(JetBinaryExpression expression, ExpressionTypingContext context) {
// If there's += (or similar op) defined as such, we just call it.
IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
String name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType);
TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create(context.trace);
JetType assignmentOperationType = getTypeForBinaryCall(scope, name, context.replaceBindingTrace(temporaryBindingTrace), expression);
// If there isn't, we call plus (or like) and then assign
if (assignmentOperationType == null) {
String counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
JetType typeForBinaryCall = getTypeForBinaryCall(scope, counterpartName, context, expression);
if (typeForBinaryCall != null) {
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
if (left instanceof JetArrayAccessExpression) {
resolveArrayAccessToLValue((JetArrayAccessExpression) left, expression.getRight(), expression.getOperationReference(), context, true);
}
context.trace.record(BindingContext.VARIABLE_REASSIGNMENT, expression);
ExpressionTypingUtils.checkWrappingInRef(expression.getLeft(), context);
}
......@@ -114,25 +136,14 @@ public class ExpressionTypingVisitorWithWritableScope extends BasicExpressionTyp
return checkExpectedType(expression, context);
}
@Nullable
private JetType checkExpectedType(JetExpression expression, ExpressionTypingContext context) {
if (context.expectedType != TypeUtils.NO_EXPECTED_TYPE) {
if (JetStandardClasses.isUnit(context.expectedType)) {
return JetStandardClasses.getUnitType();
}
context.trace.report(EXPECTED_TYPE_MISMATCH.on(expression, context.expectedType));
}
return null;
}
@Override
protected JetType visitAssignment(JetBinaryExpression expression, ExpressionTypingContext context) {
JetExpression left = expression.getLeft();
JetExpression deparenthesized = JetPsiUtil.deparenthesize(left);
boolean getterNeeded = false;
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
JetExpression right = expression.getRight();
if (deparenthesized instanceof JetArrayAccessExpression) {
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) deparenthesized;
return resolveArrayAccessToLValue(arrayAccessExpression, right, expression.getOperationReference(), context);
if (left instanceof JetArrayAccessExpression) {
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
return resolveArrayAccessToLValue(arrayAccessExpression, right, expression.getOperationReference(), context, getterNeeded);
}
JetType leftType = facade.getType(left, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceScope(scope));
if (right != null) {
......@@ -153,18 +164,30 @@ public class ExpressionTypingVisitorWithWritableScope extends BasicExpressionTyp
return checkExpectedType(expression, context);
}
private JetType resolveArrayAccessToLValue(JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide, JetSimpleNameExpression operationSign, ExpressionTypingContext context) {
private JetType resolveArrayAccessToLValue(JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide, JetSimpleNameExpression operationSign, ExpressionTypingContext context, boolean getterNeeded) {
ExpressionReceiver receiver = getExpressionReceiver(facade, arrayAccessExpression.getArrayExpression(), context.replaceScope(scope));
if (receiver == null) return null;
//
Call call = CallMaker.makeCall(receiver, arrayAccessExpression, rightHandSide);
FunctionDescriptor functionDescriptor = context.replaceScope(scope).replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).resolveCallWithGivenName(
Call call = CallMaker.makeArraySetCall(receiver, arrayAccessExpression, rightHandSide);
FunctionDescriptor setFunction = context.replaceScope(scope).replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).resolveCallWithGivenName(
call,
arrayAccessExpression,
"set", receiver);
if (functionDescriptor == null) return null;
context.trace.record(REFERENCE_TARGET, operationSign, functionDescriptor);
return DataFlowUtils.checkType(functionDescriptor.getReturnType(), arrayAccessExpression, context);
if (setFunction == null) return null;
context.trace.record(INDEXED_LVALUE_SET, arrayAccessExpression, setFunction);
if (getterNeeded) {
FunctionDescriptor getFunction = context.replaceScope(scope).replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).resolveCallWithGivenName(
CallMaker.makeArrayGetCall(receiver, arrayAccessExpression),
arrayAccessExpression,
"get", receiver);
if (getFunction == null) return null;
context.trace.record(INDEXED_LVALUE_GET, arrayAccessExpression, getFunction);
}
else {
context.trace.record(REFERENCE_TARGET, operationSign, setFunction);
}
return DataFlowUtils.checkType(setFunction.getReturnType(), arrayAccessExpression, context);
}
@Override
......
......@@ -2,15 +2,20 @@ package org.jetbrains.jet.plugin.references;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.MultiRangeReference;
import com.intellij.psi.PsiReference;
import com.intellij.psi.*;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetArrayAccessExpression;
import org.jetbrains.jet.lang.psi.JetContainerNode;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import java.util.ArrayList;
import java.util.List;
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
/**
* @author yole
*/
......@@ -32,6 +37,28 @@ class JetArrayAccessReference extends JetPsiReference implements MultiRangeRefer
return getElement().getTextRange().shiftRight(-getElement().getTextOffset());
}
@Override
protected PsiElement doResolve() {
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) getElement().getContainingFile());
FunctionDescriptor getFunction = bindingContext.get(INDEXED_LVALUE_GET, expression);
FunctionDescriptor setFunction = bindingContext.get(INDEXED_LVALUE_SET, expression);
if (getFunction != null && setFunction != null) {
return null; // Call doMultiResolve
}
return super.doResolve();
}
@Override
protected ResolveResult[] doMultiResolve() {
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) getElement().getContainingFile());
FunctionDescriptor getFunction = bindingContext.get(INDEXED_LVALUE_GET, expression);
PsiElement getFunctionElement = bindingContext.get(DESCRIPTOR_TO_DECLARATION, getFunction);
FunctionDescriptor setFunction = bindingContext.get(INDEXED_LVALUE_SET, expression);
PsiElement setFunctionElement = bindingContext.get(DESCRIPTOR_TO_DECLARATION, setFunction);
return new ResolveResult[] {new PsiElementResolveResult(getFunctionElement, true), new PsiElementResolveResult(setFunctionElement, true)};
// return super.doMultiResolve();
}
@Override
public List<TextRange> getRanges() {
List<TextRange> list = new ArrayList<TextRange>();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册