Add JetInvokeFunctionReference for JetCallExpression

This commit is contained in:
Natalia.Ukhorskaya
2013-03-13 13:42:09 +04:00
parent 4039202806
commit 37986891df
15 changed files with 211 additions and 15 deletions
@@ -31,6 +31,7 @@ import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.psi.JetSuperExpression;
import org.jetbrains.jet.lang.psi.JetTreeVisitorVoid;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.types.ErrorUtils;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lexer.JetTokens;
@@ -79,6 +80,10 @@ public class DebugInfoUtil {
@Override
public void visitReferenceExpression(JetReferenceExpression expression) {
if (!BindingContextUtils.isExpressionWithValidReference(expression, bindingContext)){
super.visitReferenceExpression(expression);
return;
}
if (expression instanceof JetSimpleNameExpression) {
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) expression;
IElementType elementType = expression.getNode().getElementType();
@@ -18,6 +18,9 @@ package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.PsiReferenceService;
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -27,11 +30,25 @@ import org.jetbrains.jet.lexer.JetTokens;
import java.util.Collections;
import java.util.List;
public class JetCallExpression extends JetExpressionImpl implements JetCallElement {
public class JetCallExpression extends JetReferenceExpression implements JetCallElement {
public JetCallExpression(@NotNull ASTNode node) {
super(node);
}
@Nullable
@Override
public PsiReference getReference() {
PsiReference[] references = getReferences();
if (references.length == 1) return references[0];
else return null;
}
@NotNull
@Override
public PsiReference[] getReferences() {
return ReferenceProvidersRegistry.getReferencesFromProviders(this);
}
@Override
public void accept(@NotNull JetVisitorVoid visitor) {
visitor.visitCallExpression(this);
@@ -229,7 +229,7 @@ public class JetVisitorVoid extends PsiElementVisitor {
}
public void visitCallExpression(JetCallExpression expression) {
visitExpression(expression);
visitReferenceExpression(expression);
}
public void visitArrayAccessExpression(JetArrayAccessExpression expression) {
@@ -25,6 +25,8 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeInfo;
@@ -297,7 +299,7 @@ public class BindingContextUtils {
if (result.getDataFlowInfo() != DataFlowInfo.EMPTY) {
trace.record(BindingContext.EXPRESSION_DATA_FLOW_INFO, expression, result.getDataFlowInfo());
}
if (!(expression instanceof JetReferenceExpression)) {
if (!isExpressionWithValidReference(expression, trace.getBindingContext())) {
trace.record(BindingContext.RESOLUTION_SCOPE, expression, resolutionScope);
}
}
@@ -312,4 +314,33 @@ public class BindingContextUtils {
JetType type = context.get(BindingContext.EXPRESSION_TYPE, expression);
return JetTypeInfo.create(type, dataFlowInfo);
}
public static boolean isExpressionWithValidReference(
@NotNull JetExpression expression,
@NotNull BindingContext context
) {
if (!(expression instanceof JetReferenceExpression)) {
return false;
}
if (!(expression instanceof JetCallExpression)) {
return true;
}
return isCallExpressionWithValidReference(expression, context);
}
public static boolean isCallExpressionWithValidReference(
@NotNull JetExpression expression,
@NotNull BindingContext context
) {
if (expression instanceof JetCallExpression) {
JetExpression calleeExpression = ((JetCallExpression) expression).getCalleeExpression();
ResolvedCall<? extends CallableDescriptor> resolvedCall = context.get(BindingContext.RESOLVED_CALL, calleeExpression);
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
return true;
}
}
return false;
}
}
@@ -304,6 +304,23 @@ public class CandidateResolver {
}
}
}
recordReferenceForInvokeFunction(context);
}
private <D extends CallableDescriptor> void recordReferenceForInvokeFunction(CallCandidateResolutionContext<D> context) {
// TODO Replace using CallForImplicitInvoke
JetExpression calleeExpression = context.call.getCalleeExpression();
if (calleeExpression != null) {
PsiElement parent = calleeExpression.getParent();
if (parent instanceof JetCallExpression) {
JetCallExpression callExpression = (JetCallExpression) parent;
if (BindingContextUtils.isCallExpressionWithValidReference(callExpression, context.trace.getBindingContext())) {
CallableDescriptor resultingDescriptor = context.candidateCall.getResultingDescriptor();
context.trace.record(BindingContext.EXPRESSION_TYPE, callExpression, resultingDescriptor.getReturnType());
context.trace.record(BindingContext.REFERENCE_TARGET, callExpression, resultingDescriptor);
}
}
}
}
private <D extends CallableDescriptor> void addConstraintForFunctionLiteral(
@@ -372,7 +389,7 @@ public class CandidateResolver {
}
TypeSubstitutor substituteDontCare = ConstraintSystemWithPriorities
.makeConstantSubstitutor(candidateWithFreshVariables.getTypeParameters(), DONT_CARE);
.makeConstantSubstitutor(candidateWithFreshVariables.getTypeParameters(), DONT_CARE);
// Value parameters
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
@@ -446,7 +463,7 @@ public class CandidateResolver {
JetType expectedType = substitutor.substitute(effectiveExpectedType, Variance.INVARIANT);
CallResolutionContext newContext = context.replaceBindingTrace(traceToResolveArgument).replaceExpectedType(expectedType);
JetTypeInfo typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(argumentExpression, newContext,
resolveFunctionArgumentBodies, traceToResolveArgument);
resolveFunctionArgumentBodies, traceToResolveArgument);
JetType type = typeInfoForCall.getType();
constraintSystem.addSubtypeConstraint(type, effectiveExpectedType, ConstraintPosition.getValueParameterPosition(
valueParameterDescriptor.getIndex()));
@@ -254,7 +254,7 @@ public class ResolveSessionUtils {
DelegatingBindingTrace trace = new DelegatingBindingTrace(
resolveSession.getBindingContext(), "trace to resolve a member scope of expression", expression);
if (expression instanceof JetReferenceExpression) {
if (BindingContextUtils.isExpressionWithValidReference(expression, resolveSession.getBindingContext())) {
QualifiedExpressionResolver qualifiedExpressionResolver = resolveSession.getInjector().getQualifiedExpressionResolver();
// In some type declaration
@@ -131,7 +131,7 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetTypeInfo, E
result = JetTypeInfo.create(null, context.dataFlowInfo);
}
if (!context.trace.get(BindingContext.PROCESSED, expression) && !(expression instanceof JetReferenceExpression)) {
if (!context.trace.get(BindingContext.PROCESSED, expression) && !BindingContextUtils.isExpressionWithValidReference(expression, context.trace.getBindingContext())) {
context.trace.record(BindingContext.RESOLUTION_SCOPE, expression, context.scope);
}
context.trace.record(BindingContext.PROCESSED, expression);
@@ -0,0 +1,109 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.references;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetCallExpression;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetValueArgumentList;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.project.WholeProjectAnalyzerFacade;
import java.util.ArrayList;
import java.util.List;
import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL;
class JetInvokeFunctionReference extends JetPsiReference implements MultiRangeReference {
public static PsiReference[] create(@NotNull JetCallExpression expression) {
return new PsiReference[] { new JetInvokeFunctionReference(expression) };
}
public JetInvokeFunctionReference(@NotNull JetCallExpression expression) {
super(expression);
}
@Override
public TextRange getRangeInElement() {
return getElement().getTextRange().shiftRight(-getElement().getTextOffset());
}
@Override
protected PsiElement doResolve() {
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(
(JetFile) getElement().getContainingFile()).getBindingContext();
ResolvedCall<? extends CallableDescriptor> invokeFunction =
bindingContext.get(RESOLVED_CALL, ((JetCallExpression) myExpression).getCalleeExpression());
if (invokeFunction != null && invokeFunction instanceof VariableAsFunctionResolvedCall) {
FunctionDescriptor resultingDescriptor = ((VariableAsFunctionResolvedCall) invokeFunction).getResultingDescriptor();
PsiElement invokeFunctionElement = BindingContextUtils.callableDescriptorToDeclaration(bindingContext, resultingDescriptor);
return invokeFunctionElement;
}
return null;
}
@Override
protected ResolveResult[] doMultiResolve() {
// TODO If there are more than one invoke(), add all function ("ambiguity"). See JetPsiReference
PsiElement element = doResolve();
if (element == null) {
return ResolveResult.EMPTY_ARRAY;
}
return new ResolveResult[] {new PsiElementResolveResult(element, true)};
}
@Override
public List<TextRange> getRanges() {
List<TextRange> list = new ArrayList<TextRange>();
JetValueArgumentList valueArgumentList = ((JetCallExpression) myExpression).getValueArgumentList();
if (valueArgumentList == null) {
return list;
}
if (valueArgumentList.getArguments().size() > 0) {
ASTNode valueArgumentListNode = valueArgumentList.getNode();
ASTNode lPar = valueArgumentListNode.findChildByType(JetTokens.LPAR);
if (lPar != null) {
list.add(getRange(lPar));
}
ASTNode rPar = valueArgumentListNode.findChildByType(JetTokens.RPAR);
if (rPar != null) {
list.add(getRange(rPar));
}
}
else {
list.add(getRange(valueArgumentList.getNode()));
}
return list;
}
private TextRange getRange(ASTNode node) {
TextRange textRange = node.getTextRange();
return textRange.shiftRight(-myExpression.getTextOffset());
}
}
@@ -20,6 +20,7 @@ import com.intellij.psi.*;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetArrayAccessExpression;
import org.jetbrains.jet.lang.psi.JetCallExpression;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.psi.JetThisReferenceExpression;
@@ -54,5 +55,14 @@ public class JetReferenceContributor extends PsiReferenceContributor {
return JetArrayAccessReference.create((JetArrayAccessExpression) element);
}
});
registrar.registerReferenceProvider(psiElement(JetCallExpression.class),
new PsiReferenceProvider() {
@NotNull
@Override
public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext processingContext) {
return JetInvokeFunctionReference.create((JetCallExpression) element);
}
});
}
}
@@ -1,3 +1,3 @@
fun main(args: Array<String>) {
throw IllegalAccessExceptio<caret>() //Press Ctrl+Space and select it
throw IllegalAccessExceptio<caret> //Press Ctrl+Space and select it
}
@@ -1,3 +1,3 @@
fun main(args: Array<String>) {
throw IllegalAccessException<caret>() //Press Ctrl+Space and select it
throw IllegalAccessException<caret> //Press Ctrl+Space and select it
}
@@ -9,5 +9,5 @@ class A {
}
fun testMy() {
A.testOthe<caret>()
A.testOthe<caret>
}
@@ -326,7 +326,10 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@NotNull
public JsNode visitThisExpression(@NotNull JetThisExpression expression,
@NotNull TranslationContext context) {
return context.getThisObject(getDescriptorForReferenceExpression(context.bindingContext(), expression.getInstanceReference()));
DeclarationDescriptor thisExpression =
getDescriptorForReferenceExpression(context.bindingContext(), expression.getInstanceReference());
assert thisExpression != null : "This expression must reference a descriptor: " + expression.getText();
return context.getThisObject(thisExpression);
}
@Override
@@ -37,6 +37,7 @@ public final class ReferenceAccessTranslator extends AbstractTranslator implemen
/*package*/ static ReferenceAccessTranslator newInstance(@NotNull JetSimpleNameExpression expression,
@NotNull TranslationContext context) {
DeclarationDescriptor referenceDescriptor = getDescriptorForReferenceExpression(context.bindingContext(), expression);
assert referenceDescriptor != null : "JetSimpleName expression must reference a descriptor " + expression.getText();
return new ReferenceAccessTranslator(referenceDescriptor, context);
}
@@ -123,13 +123,16 @@ public final class BindingUtils {
return context.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
}
@NotNull
@Nullable
public static DeclarationDescriptor getDescriptorForReferenceExpression(@NotNull BindingContext context,
@NotNull JetReferenceExpression reference) {
DeclarationDescriptor referencedDescriptor = getNullableDescriptorForReferenceExpression(context, reference);
assert referencedDescriptor != null
: message(reference, "Reference expression must reference a descriptor for reference " + reference.getText());
return referencedDescriptor;
if (BindingContextUtils.isExpressionWithValidReference(reference, context)) {
assert referencedDescriptor != null
: message(reference, "Reference expression must reference a descriptor for reference " + reference.getText());
return referencedDescriptor;
}
return null;
}
@Nullable