|
|
@ -174,6 +174,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver |
|
|
|
// lambdas must be resolved so that they get stored in the 'undecided' list only once
|
|
|
|
// lambdas must be resolved so that they get stored in the 'undecided' list only once
|
|
|
|
goto case ResolveVisitorNavigationMode.Resolve; |
|
|
|
goto case ResolveVisitorNavigationMode.Resolve; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We shouldn't scan nodes that were already resolved.
|
|
|
|
|
|
|
|
Debug.Assert(!resolveResultCache.ContainsKey(node)); |
|
|
|
|
|
|
|
// Doing so should be harmless since we allow scanning twice, but it indicates
|
|
|
|
|
|
|
|
// a bug in the logic that causes the scan.
|
|
|
|
|
|
|
|
|
|
|
|
bool oldResolverEnabled = resolverEnabled; |
|
|
|
bool oldResolverEnabled = resolverEnabled; |
|
|
|
resolverEnabled = false; |
|
|
|
resolverEnabled = false; |
|
|
|
StoreState(node, resolver.Clone()); |
|
|
|
StoreState(node, resolver.Clone()); |
|
|
@ -231,6 +237,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver |
|
|
|
Debug.Assert(result != null); |
|
|
|
Debug.Assert(result != null); |
|
|
|
if (node.IsNull) |
|
|
|
if (node.IsNull) |
|
|
|
return; |
|
|
|
return; |
|
|
|
|
|
|
|
Debug.Assert(!resolveResultCache.ContainsKey(node)); |
|
|
|
resolveResultCache.Add(node, result); |
|
|
|
resolveResultCache.Add(node, result); |
|
|
|
if (navigator != null) |
|
|
|
if (navigator != null) |
|
|
|
navigator.Resolved(node, result); |
|
|
|
navigator.Resolved(node, result); |
|
|
@ -1631,7 +1638,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver |
|
|
|
|
|
|
|
|
|
|
|
var lambda = new ExplicitlyTypedLambda(parameters, isAnonymousMethod, resolver.Clone(), this, body); |
|
|
|
var lambda = new ExplicitlyTypedLambda(parameters, isAnonymousMethod, resolver.Clone(), this, body); |
|
|
|
|
|
|
|
|
|
|
|
Scan(body); |
|
|
|
// Don't scan the lambda body here - we'll do that later when analyzing the ExplicitlyTypedLambda.
|
|
|
|
|
|
|
|
|
|
|
|
resolver.PopBlock(); |
|
|
|
resolver.PopBlock(); |
|
|
|
return lambda; |
|
|
|
return lambda; |
|
|
@ -2263,12 +2270,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver |
|
|
|
ResolveResult IAstVisitor<object, ResolveResult>.VisitFixedStatement(FixedStatement fixedStatement, object data) |
|
|
|
ResolveResult IAstVisitor<object, ResolveResult>.VisitFixedStatement(FixedStatement fixedStatement, object data) |
|
|
|
{ |
|
|
|
{ |
|
|
|
resolver.PushBlock(); |
|
|
|
resolver.PushBlock(); |
|
|
|
|
|
|
|
ITypeReference type = MakeTypeReference(fixedStatement.Type); |
|
|
|
VariableInitializer firstInitializer = fixedStatement.Variables.FirstOrDefault(); |
|
|
|
|
|
|
|
ITypeReference type = MakeTypeReference(fixedStatement.Type, |
|
|
|
|
|
|
|
firstInitializer != null ? firstInitializer.Initializer : null, |
|
|
|
|
|
|
|
false); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (AstNode node = fixedStatement.FirstChild; node != null; node = node.NextSibling) { |
|
|
|
for (AstNode node = fixedStatement.FirstChild; node != null; node = node.NextSibling) { |
|
|
|
if (node.Role == FixedStatement.Roles.Variable) { |
|
|
|
if (node.Role == FixedStatement.Roles.Variable) { |
|
|
|
VariableInitializer vi = (VariableInitializer)node; |
|
|
|
VariableInitializer vi = (VariableInitializer)node; |
|
|
@ -2283,10 +2285,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver |
|
|
|
ResolveResult IAstVisitor<object, ResolveResult>.VisitForeachStatement(ForeachStatement foreachStatement, object data) |
|
|
|
ResolveResult IAstVisitor<object, ResolveResult>.VisitForeachStatement(ForeachStatement foreachStatement, object data) |
|
|
|
{ |
|
|
|
{ |
|
|
|
resolver.PushBlock(); |
|
|
|
resolver.PushBlock(); |
|
|
|
ITypeReference type = MakeTypeReference(foreachStatement.VariableType, foreachStatement.InExpression, true); |
|
|
|
ITypeReference type; |
|
|
|
|
|
|
|
if (IsVar(foreachStatement.VariableType)) { |
|
|
|
|
|
|
|
if (navigator.Scan(foreachStatement.VariableType) == ResolveVisitorNavigationMode.Resolve) { |
|
|
|
|
|
|
|
IType collectionType = Resolve(foreachStatement.InExpression).Type; |
|
|
|
|
|
|
|
IType elementType = GetElementType(collectionType, resolver.Context, false); |
|
|
|
|
|
|
|
StoreResult(foreachStatement.VariableType, new TypeResolveResult(elementType)); |
|
|
|
|
|
|
|
type = elementType; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
Scan(foreachStatement.InExpression); |
|
|
|
|
|
|
|
type = MakeVarTypeReference(foreachStatement.InExpression, true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
type = ResolveType(foreachStatement.VariableType); |
|
|
|
|
|
|
|
} |
|
|
|
IVariable v = resolver.AddVariable(type, MakeRegion(foreachStatement.VariableNameToken), foreachStatement.VariableName); |
|
|
|
IVariable v = resolver.AddVariable(type, MakeRegion(foreachStatement.VariableNameToken), foreachStatement.VariableName); |
|
|
|
StoreResult(foreachStatement.VariableNameToken, new LocalResolveResult(v, v.Type.Resolve(resolver.Context))); |
|
|
|
StoreResult(foreachStatement.VariableNameToken, new LocalResolveResult(v, v.Type.Resolve(resolver.Context))); |
|
|
|
ScanChildren(foreachStatement); |
|
|
|
Scan(foreachStatement.EmbeddedStatement); |
|
|
|
resolver.PopBlock(); |
|
|
|
resolver.PopBlock(); |
|
|
|
return voidResult; |
|
|
|
return voidResult; |
|
|
|
} |
|
|
|
} |
|
|
@ -2302,8 +2317,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver |
|
|
|
ResolveResult IAstVisitor<object, ResolveResult>.VisitCatchClause(CatchClause catchClause, object data) |
|
|
|
ResolveResult IAstVisitor<object, ResolveResult>.VisitCatchClause(CatchClause catchClause, object data) |
|
|
|
{ |
|
|
|
{ |
|
|
|
resolver.PushBlock(); |
|
|
|
resolver.PushBlock(); |
|
|
|
if (catchClause.VariableName != null) { |
|
|
|
if (!string.IsNullOrEmpty(catchClause.VariableName)) { |
|
|
|
ITypeReference variableType = MakeTypeReference(catchClause.Type, null, false); |
|
|
|
ITypeReference variableType = MakeTypeReference(catchClause.Type); |
|
|
|
DomRegion region = MakeRegion(catchClause.VariableNameToken); |
|
|
|
DomRegion region = MakeRegion(catchClause.VariableNameToken); |
|
|
|
IVariable v = resolver.AddVariable(variableType, region, catchClause.VariableName); |
|
|
|
IVariable v = resolver.AddVariable(variableType, region, catchClause.VariableName); |
|
|
|
StoreResult(catchClause.VariableNameToken, new LocalResolveResult(v, v.Type.Resolve(resolver.Context))); |
|
|
|
StoreResult(catchClause.VariableNameToken, new LocalResolveResult(v, v.Type.Resolve(resolver.Context))); |
|
|
@ -2318,33 +2333,56 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver |
|
|
|
ResolveResult IAstVisitor<object, ResolveResult>.VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement, object data) |
|
|
|
ResolveResult IAstVisitor<object, ResolveResult>.VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement, object data) |
|
|
|
{ |
|
|
|
{ |
|
|
|
bool isConst = (variableDeclarationStatement.Modifiers & Modifiers.Const) != 0; |
|
|
|
bool isConst = (variableDeclarationStatement.Modifiers & Modifiers.Const) != 0; |
|
|
|
VariableInitializer firstInitializer = variableDeclarationStatement.Variables.FirstOrDefault(); |
|
|
|
if (!isConst && IsVar(variableDeclarationStatement.Type) && variableDeclarationStatement.Variables.Count == 1) { |
|
|
|
ITypeReference type = MakeTypeReference(variableDeclarationStatement.Type, |
|
|
|
VariableInitializer vi = variableDeclarationStatement.Variables.Single(); |
|
|
|
firstInitializer != null ? firstInitializer.Initializer : null, |
|
|
|
bool needResolve = resolverEnabled |
|
|
|
false); |
|
|
|
|| navigator.Scan(variableDeclarationStatement.Type) == ResolveVisitorNavigationMode.Resolve |
|
|
|
|
|
|
|
|| navigator.Scan(vi) == ResolveVisitorNavigationMode.Resolve; |
|
|
|
int initializerCount = variableDeclarationStatement.Variables.Count; |
|
|
|
ITypeReference type; |
|
|
|
ResolveResult result = null; |
|
|
|
if (needResolve) { |
|
|
|
for (AstNode node = variableDeclarationStatement.FirstChild; node != null; node = node.NextSibling) { |
|
|
|
type = Resolve(vi.Initializer).Type; |
|
|
|
if (node.Role == VariableDeclarationStatement.Roles.Variable) { |
|
|
|
} else { |
|
|
|
VariableInitializer vi = (VariableInitializer)node; |
|
|
|
Scan(vi.Initializer); |
|
|
|
|
|
|
|
type = MakeVarTypeReference(vi.Initializer, false); |
|
|
|
IConstantValue cv = null; |
|
|
|
} |
|
|
|
if (isConst) { |
|
|
|
IVariable v = resolver.AddVariable(type, MakeRegion(vi), vi.Name); |
|
|
|
cv = TypeSystemConvertVisitor.ConvertConstantValue(type, vi.Initializer, resolver.CurrentTypeDefinition, resolver.CurrentMember as IMethod, resolver.CurrentUsingScope); |
|
|
|
StoreState(vi, resolver.Clone()); |
|
|
|
|
|
|
|
if (needResolve) { |
|
|
|
|
|
|
|
ResolveResult result; |
|
|
|
|
|
|
|
if (!resolveResultCache.TryGetValue(vi, out result)) { |
|
|
|
|
|
|
|
result = new LocalResolveResult(v, type.Resolve(resolver.Context)); |
|
|
|
|
|
|
|
StoreResult(vi, result); |
|
|
|
} |
|
|
|
} |
|
|
|
resolver.AddVariable(type, MakeRegion(vi), vi.Name, cv); |
|
|
|
return result; |
|
|
|
|
|
|
|
} else { |
|
|
|
if (resolverEnabled && initializerCount == 1) { |
|
|
|
return null; |
|
|
|
result = Resolve(node); |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
ITypeReference type = MakeTypeReference(variableDeclarationStatement.Type); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int initializerCount = variableDeclarationStatement.Variables.Count; |
|
|
|
|
|
|
|
ResolveResult result = null; |
|
|
|
|
|
|
|
for (AstNode node = variableDeclarationStatement.FirstChild; node != null; node = node.NextSibling) { |
|
|
|
|
|
|
|
if (node.Role == VariableDeclarationStatement.Roles.Variable) { |
|
|
|
|
|
|
|
VariableInitializer vi = (VariableInitializer)node; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IConstantValue cv = null; |
|
|
|
|
|
|
|
if (isConst) { |
|
|
|
|
|
|
|
cv = TypeSystemConvertVisitor.ConvertConstantValue(type, vi.Initializer, resolver.CurrentTypeDefinition, resolver.CurrentMember as IMethod, resolver.CurrentUsingScope); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
resolver.AddVariable(type, MakeRegion(vi), vi.Name, cv); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (resolverEnabled && initializerCount == 1) { |
|
|
|
|
|
|
|
result = Resolve(node); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
Scan(node); |
|
|
|
|
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
Scan(node); |
|
|
|
Scan(node); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
|
|
|
|
Scan(node); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
@ -2488,39 +2526,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver |
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Local Variable Type Inference
|
|
|
|
#region Local Variable Type Inference
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Creates a type reference for the specified type node.
|
|
|
|
|
|
|
|
/// If the type node is 'var', performs type inference on the initializer expression.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
ITypeReference MakeTypeReference(AstType type, AstNode initializerExpression, bool isForEach) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
bool typeNeedsResolving = (navigator.Scan(type) == ResolveVisitorNavigationMode.Resolve); |
|
|
|
|
|
|
|
if (initializerExpression != null && IsVar(type)) { |
|
|
|
|
|
|
|
var typeRef = new VarTypeReference(this, resolver.Clone(), initializerExpression, isForEach); |
|
|
|
|
|
|
|
if (typeNeedsResolving) { |
|
|
|
|
|
|
|
// Hack: I don't see a clean way to make the 'var' SimpleType resolve to the inferred type,
|
|
|
|
|
|
|
|
// so we just do it here and store the result in the resolver cache.
|
|
|
|
|
|
|
|
IType actualType = typeRef.Resolve(resolver.Context); |
|
|
|
|
|
|
|
if (actualType.Kind != TypeKind.Unknown) { |
|
|
|
|
|
|
|
StoreResult(type, new TypeResolveResult(actualType)); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
StoreResult(type, errorResult); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return actualType; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return typeRef; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// Perf: avoid duplicate resolving of the type (once as ITypeReference, once directly in ResolveVisitor)
|
|
|
|
|
|
|
|
// if possible. By using ResolveType when we know we need to resolve the node anyways, the resolve cache
|
|
|
|
|
|
|
|
// can take care of the duplicate call.
|
|
|
|
|
|
|
|
if (typeNeedsResolving) |
|
|
|
|
|
|
|
return ResolveType(type); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
return MakeTypeReference(type); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static bool IsVar(AstType returnType) |
|
|
|
static bool IsVar(AstType returnType) |
|
|
|
{ |
|
|
|
{ |
|
|
|
SimpleType st = returnType as SimpleType; |
|
|
|
SimpleType st = returnType as SimpleType; |
|
|
@ -2532,6 +2537,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver |
|
|
|
return TypeSystemConvertVisitor.ConvertType(type, resolver.CurrentTypeDefinition, resolver.CurrentMember as IMethod, resolver.CurrentUsingScope, currentTypeLookupMode); |
|
|
|
return TypeSystemConvertVisitor.ConvertType(type, resolver.CurrentTypeDefinition, resolver.CurrentMember as IMethod, resolver.CurrentUsingScope, currentTypeLookupMode); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ITypeReference MakeVarTypeReference(Expression initializer, bool isForEach) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return new VarTypeReference(this, resolver.Clone(), initializer, isForEach); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
sealed class VarTypeReference : ITypeReference |
|
|
|
sealed class VarTypeReference : ITypeReference |
|
|
|
{ |
|
|
|
{ |
|
|
|
ResolveVisitor visitor; |
|
|
|
ResolveVisitor visitor; |
|
|
|