KT-1645 Propose members according to smart casts

#KT-1645 fixed
This commit is contained in:
Nikolay Krasko
2012-04-13 15:35:55 +04:00
parent 8ffca6e52f
commit 531ffaaffa
15 changed files with 147 additions and 16 deletions
@@ -30,6 +30,8 @@ import org.jetbrains.jet.lang.psi.JetImportDirective;
import org.jetbrains.jet.lang.psi.JetNamespaceHeader;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
@@ -53,10 +55,31 @@ public final class TipsManager {
JetExpression receiverExpression = expression.getReceiverExpression();
if (receiverExpression != null) {
// Process as call expression
final JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, receiverExpression);
final JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, expression);
final JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, receiverExpression);
if (expressionType != null && resolutionScope != null) {
if (!(expressionType instanceof NamespaceType)) {
ExpressionReceiver receiverDescriptor = new ExpressionReceiver(receiverExpression, expressionType);
Set<DeclarationDescriptor> descriptors = new HashSet<DeclarationDescriptor>();
DataFlowInfo info = context.get(BindingContext.NON_DEFAULT_EXPRESSION_DATA_FLOW, expression);
if (info == null) {
info = DataFlowInfo.EMPTY;
}
AutoCastServiceImpl autoCastService = new AutoCastServiceImpl(info, context);
List<ReceiverDescriptor> variantsForExplicitReceiver = autoCastService.getVariantsForReceiver(receiverDescriptor);
for (ReceiverDescriptor descriptor : variantsForExplicitReceiver) {
descriptors.addAll(includeExternalCallableExtensions(
excludePrivateDescriptors(descriptor.getType().getMemberScope().getAllDescriptors()),
resolutionScope, descriptor));
}
return descriptors;
}
return includeExternalCallableExtensions(
excludePrivateDescriptors(expressionType.getMemberScope().getAllDescriptors()),
resolutionScope, new ExpressionReceiver(receiverExpression, expressionType));
@@ -161,7 +184,7 @@ public final class TipsManager {
});
}
private static Collection<DeclarationDescriptor> includeExternalCallableExtensions(
private static Set<DeclarationDescriptor> includeExternalCallableExtensions(
@NotNull Collection<DeclarationDescriptor> descriptors,
@NotNull final JetScope externalScope,
@NotNull final ReceiverDescriptor receiverDescriptor
@@ -169,7 +192,7 @@ public final class TipsManager {
// It's impossible to add extension function for namespace
JetType receiverType = receiverDescriptor.getType();
if (receiverType instanceof NamespaceType) {
return descriptors;
return new HashSet<DeclarationDescriptor>(descriptors);
}
Set<DeclarationDescriptor> descriptorsSet = Sets.newHashSet(descriptors);
@@ -24,6 +24,7 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.DeferredType;
@@ -32,7 +33,6 @@ import org.jetbrains.jet.util.Box;
import org.jetbrains.jet.util.slicedmap.*;
import java.util.Collection;
import java.util.Set;
import static org.jetbrains.jet.util.slicedmap.RewritePolicy.DO_NOTHING;
@@ -63,6 +63,9 @@ public interface BindingContext {
/** A scope where type of expression has been resolved */
WritableSlice<JetExpression, JetScope> RESOLUTION_SCOPE = Slices.createSimpleSlice();
/** Collected during analyze, used in IDE in auto-cast completion */
WritableSlice<JetExpression, DataFlowInfo> NON_DEFAULT_EXPRESSION_DATA_FLOW = Slices.createSimpleSlice();
WritableSlice<JetExpression, Boolean> VARIABLE_REASSIGNMENT = Slices.createSimpleSetSlice();
WritableSlice<ValueParameterDescriptor, Boolean> AUTO_CREATED_IT = Slices.createSimpleSetSlice();
WritableSlice<JetExpression, DeclarationDescriptor> VARIABLE_ASSIGNMENT = Slices.createSimpleSlice();
@@ -358,7 +358,9 @@ public class BodyResolver {
public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
JetTypeReference typeReference = call.getTypeReference();
if (typeReference != null) {
callResolver.resolveFunctionCall(trace, scopeForSupertypeInitializers, CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call), NO_EXPECTED_TYPE, dataFlowInfo);
callResolver.resolveFunctionCall(trace, scopeForSupertypeInitializers,
CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call),
NO_EXPECTED_TYPE, dataFlowInfo);
}
}
@@ -28,7 +28,10 @@ import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.inference.*;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemSolution;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemWithPriorities;
import org.jetbrains.jet.lang.resolve.calls.inference.DebugConstraintResolutionListener;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
@@ -42,8 +45,7 @@ import javax.inject.Inject;
import java.util.*;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST;
import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLUTION_SCOPE;
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
import static org.jetbrains.jet.lang.resolve.calls.ResolutionStatus.*;
import static org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl.MAP_TO_CANDIDATE;
import static org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl.MAP_TO_RESULT;
@@ -255,6 +257,10 @@ public class CallResolver {
context.trace.record(ResolutionDebugInfo.RESOLUTION_DEBUG_INFO, context.call.getCallElement(), debugInfo);
context.trace.record(RESOLUTION_SCOPE, context.call.getCalleeExpression(), context.scope);
if (context.dataFlowInfo.hasTypeInfoConstraints()) {
context.trace.record(NON_DEFAULT_EXPRESSION_DATA_FLOW, context.call.getCalleeExpression(), context.dataFlowInfo);
}
debugInfo.set(ResolutionDebugInfo.TASKS, prioritizedTasks);
TemporaryBindingTrace traceForFirstNonemptyCandidateSet = null;
@@ -36,7 +36,10 @@ public class AutoCastUtils {
/**
* @return variants @param receiverToCast may be cast to according to @param dataFlowInfo, @param receiverToCast itself is NOT included
*/
public static List<ReceiverDescriptor> getAutoCastVariants(@NotNull final BindingContext bindingContext, @NotNull final DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiverToCast) {
public static List<ReceiverDescriptor> getAutoCastVariants(
@NotNull final BindingContext bindingContext,
@NotNull final DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiverToCast
) {
return receiverToCast.accept(new ReceiverDescriptorVisitor<List<ReceiverDescriptor>, Object>() {
@Override
public List<ReceiverDescriptor> visitNoReceiver(ReceiverDescriptor noReceiver, Object data) {
@@ -72,7 +75,8 @@ public class AutoCastUtils {
// else if (expression instanceof JetThisExpression) {
// return castThis(dataFlowInfo, receiver);
// }
DataFlowValue dataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(receiver.getExpression(),receiver.getType(), bindingContext);
DataFlowValue dataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(receiver.getExpression(),receiver.getType(),
bindingContext);
List<ReceiverDescriptor> result = Lists.newArrayList();
for (JetType possibleType : dataFlowInfo.getPossibleTypes(dataFlowValue)) {
result.add(new AutoCastReceiver(receiver, possibleType, dataFlowValue.isStableIdentifier()));
@@ -50,7 +50,9 @@ public class DataFlowInfo {
}
};
public static DataFlowInfo EMPTY = new DataFlowInfo(ImmutableMap.<DataFlowValue, Nullability>of(), Multimaps.newListMultimap(Collections.<DataFlowValue, Collection<JetType>>emptyMap(), CommonSuppliers.<JetType>getArrayListSupplier()));
public static DataFlowInfo EMPTY = new DataFlowInfo(
ImmutableMap.<DataFlowValue, Nullability>of(),
Multimaps.newListMultimap(Collections.<DataFlowValue, Collection<JetType>>emptyMap(), CommonSuppliers.<JetType>getArrayListSupplier()));
private final ImmutableMap<DataFlowValue, Nullability> nullabilityInfo;
/** Also immutable */
@@ -195,6 +197,10 @@ public class DataFlowInfo {
return new DataFlowInfo(ImmutableMap.copyOf(builder), newTypeInfo);
}
public boolean hasTypeInfoConstraints() {
return !typeInfo.isEmpty();
}
}
//public class DataFlowInfo {
@@ -617,6 +617,13 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
temporaryTrace.commit();
return null;
}
// Uncommitted changes in temp context
context.trace.record(RESOLUTION_SCOPE, nameExpression, context.scope);
if (context.dataFlowInfo.hasTypeInfoConstraints()) {
context.trace.record(NON_DEFAULT_EXPRESSION_DATA_FLOW, nameExpression, context.dataFlowInfo);
}
ExpressionTypingContext newContext = receiver.exists()
? context.replaceScope(receiver.getType().getMemberScope())
: context;
@@ -624,6 +631,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (jetType == null) {
context.trace.report(UNRESOLVED_REFERENCE.on(nameExpression));
}
return jetType;
}
else if (selectorExpression instanceof JetQualifiedExpression) {
@@ -59,7 +59,8 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
JetPattern pattern = expression.getPattern();
if (pattern != null) {
WritableScopeImpl scopeToExtend = newWritableScopeImpl(context).setDebugName("Scope extended in 'is'");
DataFlowInfo newDataFlowInfo = checkPatternType(pattern, knownType, false, scopeToExtend, context, DataFlowValueFactory.INSTANCE.createDataFlowValue(leftHandSide, knownType, context.trace.getBindingContext()));
DataFlowValue dataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(leftHandSide, knownType, context.trace.getBindingContext());
DataFlowInfo newDataFlowInfo = checkPatternType(pattern, knownType, false, scopeToExtend, context, dataFlowValue);
context.patternsToDataFlowInfo.put(pattern, newDataFlowInfo);
context.patternsToBoundVariableLists.put(pattern, scopeToExtend.getDeclaredVariables());
}
@@ -175,7 +176,9 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
return newDataFlowInfo[0];
}
private DataFlowInfo checkPatternType(@NotNull JetPattern pattern, @NotNull final JetType subjectType, final boolean conditionExpected, @NotNull final WritableScope scopeToExtend, final ExpressionTypingContext context, @NotNull final DataFlowValue... subjectVariables) {
private DataFlowInfo checkPatternType(@NotNull JetPattern pattern, @NotNull final JetType subjectType, final boolean conditionExpected,
@NotNull final WritableScope scopeToExtend, final ExpressionTypingContext context, @NotNull final DataFlowValue... subjectVariables
) {
final Ref<DataFlowInfo> result = new Ref<DataFlowInfo>(context.dataFlowInfo);
pattern.accept(new JetVisitorVoid() {
@Override
@@ -0,0 +1,14 @@
trait Expr
class Num(val value : Int) : Expr
fun eval(e : Expr) {
if (e is Num) {
return e.<caret>
}
}
// EXIST: value
@@ -0,0 +1,12 @@
class Expr {}
class Num : Expr() {
fun testing() {}
}
fun eval(e : Expr) {
if (e is Num) {
return e.<caret>()
}
}
// EXIST: testing
@@ -0,0 +1,11 @@
trait Expr {
public fun testThis() {
if (this is Num) {
this.<caret>
}
}
}
class Num(val toCheck : Int) : Expr
// EXIST: toCheck
@@ -0,0 +1,8 @@
trait Expr
class Sum(val left : Expr, val right : Expr) : Expr
fun evalWhen(e : Expr) : Int = when (e) {
is Sum -> e.<caret>
}
// EXIST: left, right
@@ -0,0 +1,11 @@
class TestClass {
public fun testMethod() {
}
}
fun testFun() {
val lambda = {() -> TestClass() }
lambda().<caret>
}
// EXIST: testMethod
@@ -1,13 +1,13 @@
package something
class SomeTempClass {
fun testSome() {
fun helloWorld() {
}
fun test() {
test<caret>()
hello<caret>()
}
}
// EXIST: test, testSome
// EXIST: helloWorld
@@ -25,6 +25,22 @@ import java.io.File;
*/
public class JetBasicCompletionTest extends JetCompletionTestBase {
public void testAutoCastAfterIf() {
doTest();
}
public void testAutoCastAfterIfMethod() {
doTest();
}
public void testAutoCastForThis() {
doTest();
}
public void testAutoCastInWhen() {
doTest();
}
public void testBasicAny() {
doTest();
}
@@ -37,6 +53,10 @@ public class JetBasicCompletionTest extends JetCompletionTestBase {
doTest();
}
public void testCallLocalLambda() {
doTest();
}
public void testExtendClassName() {
doTest();
}