1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
5
using Boo.Lang.Compiler.Ast;
6
using ICSharpCode.SharpDevelop;
7
using ICSharpCode.SharpDevelop.Dom;
9
namespace Grunwald.BooBinding.CodeCompletion
12
/// Return type that is inferred from an expression.
14
public class BooInferredReturnType : ProxyReturnType
16
Expression expression;
18
IReturnType cachedType;
21
public BooInferredReturnType(Expression expression, IClass context)
23
if (expression == null) throw new ArgumentNullException("expression");
24
this.context = context;
25
this.expression = expression;
28
bool useLastStatementIfNoReturnStatement;
30
public BooInferredReturnType(Block block, IClass context, bool useLastStatementIfNoReturnStatement)
32
if (block == null) throw new ArgumentNullException("block");
33
this.useLastStatementIfNoReturnStatement = useLastStatementIfNoReturnStatement;
35
this.context = context;
38
public override IReturnType BaseType {
40
// clear up references to method/expression after the type has been resolved
42
GetReturnTypeVisitor v = new GetReturnTypeVisitor(this);
44
block = null; // reset block before calling Visit to prevent StackOverflow
46
if (v.noReturnStatement) {
47
if (useLastStatementIfNoReturnStatement && v.lastExpressionStatement != null) {
48
cachedType = new BooResolver().GetTypeOfExpression(v.lastExpressionStatement.Expression, context);
50
cachedType = ParserService.CurrentProjectContent.SystemTypes.Void;
52
} else if (v.result is NullReturnType) {
53
cachedType = ConvertVisitor.GetDefaultReturnType(ParserService.CurrentProjectContent);
55
cachedType = v.result;
57
} else if (expression != null) {
58
Expression expr = expression;
60
cachedType = new BooResolver().GetTypeOfExpression(expr, context);
66
class GetReturnTypeVisitor : DepthFirstVisitor
69
BooInferredReturnType parentReturnType;
70
public GetReturnTypeVisitor(BooInferredReturnType parentReturnType)
72
this.context = parentReturnType.context;
73
this.parentReturnType = parentReturnType;
76
public IReturnType result;
77
public bool noReturnStatement = true;
78
public ExpressionStatement lastExpressionStatement;
80
public override void OnReturnStatement(ReturnStatement node)
82
noReturnStatement = false;
83
if (node.Expression == null) {
84
result = ParserService.CurrentProjectContent.SystemTypes.Void;
86
result = new BooResolver().GetTypeOfExpression(node.Expression, context);
90
public override void OnExpressionStatement(ExpressionStatement node)
92
base.OnExpressionStatement(node);
93
lastExpressionStatement = node;
96
public override void OnYieldStatement(YieldStatement node)
98
noReturnStatement = false;
100
IProjectContent pc = context != null ? context.ProjectContent : ParserService.CurrentProjectContent;
101
IReturnType enumerable = new GetClassReturnType(pc, "System.Collections.Generic.IEnumerable", 1);
103
// Prevent creating an infinite number of InferredReturnTypes in inferring cycles
104
parentReturnType.expression = new NullLiteralExpression();
105
IReturnType returnType;
106
if (node.Expression == null)
107
returnType = ConvertVisitor.GetDefaultReturnType(pc);
109
returnType = new BooResolver().GetTypeOfExpression(node.Expression, context);
110
if (returnType != null) {
111
returnType.GetUnderlyingClass(); // force to infer type
113
if (parentReturnType.expression == null) {
114
// inferrence cycle with parentReturnType
115
returnType = new GetClassReturnType(pc, "?", 0);
117
parentReturnType.expression = null;
119
result = new ConstructedReturnType(enumerable, new IReturnType[] { returnType });
122
public override void OnBlockExpression(BlockExpression node)
124
// ignore return statements in callable blocks
127
public override bool Visit(Node node)
129
if (result != null && !(result is NullReturnType))
132
return base.Visit(node);