Browse Source

Change ResolveVisitor to report the location of conversions.

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
42bc87ba02
  1. 2
      ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
  2. 24
      ICSharpCode.NRefactory/CSharp/Resolver/CompositeResolveVisitorNavigator.cs
  3. 7
      ICSharpCode.NRefactory/CSharp/Resolver/DetectSkippableNodesNavigator.cs
  4. 29
      ICSharpCode.NRefactory/CSharp/Resolver/FindReferences.cs
  5. 51
      ICSharpCode.NRefactory/CSharp/Resolver/IResolveVisitorNavigator.cs
  6. 17
      ICSharpCode.NRefactory/CSharp/Resolver/NodeListResolveVisitorNavigator.cs
  7. 424
      ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs

2
ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs

@ -2784,7 +2784,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// Specifies whether to allow treating single-dimensional arrays like compile-time constants. /// Specifies whether to allow treating single-dimensional arrays like compile-time constants.
/// This is used for attribute arguments. /// This is used for attribute arguments.
/// </param> /// </param>
public ResolveResult ResolveArrayCreation(IType elementType, int dimensions = 1, ResolveResult[] sizeArguments = null, ResolveResult[] initializerElements = null, bool allowArrayConstants = false) public ArrayCreateResolveResult ResolveArrayCreation(IType elementType, int dimensions = 1, ResolveResult[] sizeArguments = null, ResolveResult[] initializerElements = null, bool allowArrayConstants = false)
{ {
if (sizeArguments != null && dimensions != Math.Max(1, sizeArguments.Length)) if (sizeArguments != null && dimensions != Math.Max(1, sizeArguments.Length))
throw new ArgumentException("dimensions and sizeArguments.Length don't match"); throw new ArgumentException("dimensions and sizeArguments.Length don't match");

24
ICSharpCode.NRefactory/CSharp/Resolver/CompositeResolveVisitorNavigator.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
@ -31,17 +32,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public ResolveVisitorNavigationMode Scan(AstNode node) public ResolveVisitorNavigationMode Scan(AstNode node)
{ {
ResolveVisitorNavigationMode mode = ResolveVisitorNavigationMode.Skip; bool needsScan = false;
foreach (var navigator in navigators) { foreach (var navigator in navigators) {
ResolveVisitorNavigationMode newMode = navigator.Scan(node); ResolveVisitorNavigationMode mode = navigator.Scan(node);
if (newMode == ResolveVisitorNavigationMode.ResolveAll) if (mode == ResolveVisitorNavigationMode.Resolve)
return newMode; // ResolveAll has highest priority return mode; // resolve has highest priority
if (newMode == ResolveVisitorNavigationMode.Resolve) else if (mode == ResolveVisitorNavigationMode.Scan)
mode = newMode; // resolve has high priority and replaces the previous mode needsScan = true;
else if (mode == ResolveVisitorNavigationMode.Skip)
mode = newMode; // skip has lowest priority and always gets replaced
} }
return mode; return needsScan ? ResolveVisitorNavigationMode.Scan : ResolveVisitorNavigationMode.Skip;
} }
public void Resolved(AstNode node, ResolveResult result) public void Resolved(AstNode node, ResolveResult result)
@ -50,5 +49,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
navigator.Resolved(node, result); navigator.Resolved(node, result);
} }
} }
public void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{
foreach (var navigator in navigators) {
navigator.ProcessConversion(expression, result, conversion, targetType);
}
}
} }
} }

7
ICSharpCode.NRefactory/CSharp/Resolver/DetectSkippableNodesNavigator.cs

@ -18,6 +18,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
@ -76,5 +77,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
navigator.Resolved(node, result); navigator.Resolved(node, result);
} }
/// <inheritdoc/>
public void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{
navigator.ProcessConversion(expression, result, conversion, targetType);
}
} }
} }

29
ICSharpCode.NRefactory/CSharp/Resolver/FindReferences.cs

@ -127,11 +127,25 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
void IResolveVisitorNavigator.Resolved(AstNode node, ResolveResult result) void IResolveVisitorNavigator.Resolved(AstNode node, ResolveResult result)
{ {
if (CanMatch(node) && IsMatch(result)) { if (CanMatch(node) && IsMatch(result)) {
var referenceFound = findReferences.ReferenceFound; ReportMatch(node, result);
if (referenceFound != null)
referenceFound(node, result);
} }
} }
void IResolveVisitorNavigator.ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{
ProcessConversion(expression, result, conversion, targetType);
}
internal virtual void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{
}
protected void ReportMatch(AstNode node, ResolveResult result)
{
var referenceFound = findReferences.ReferenceFound;
if (referenceFound != null)
referenceFound(node, result);
}
} }
#endregion #endregion
@ -593,7 +607,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
internal override bool IsMatch(ResolveResult rr) internal override bool IsMatch(ResolveResult rr)
{ {
throw new NotImplementedException(); return false;
}
internal override void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{
if (conversion.IsUserDefined && conversion.Method.MemberDefinition == op) {
ReportMatch(expression, result);
}
} }
} }

51
ICSharpCode.NRefactory/CSharp/Resolver/IResolveVisitorNavigator.cs

@ -35,7 +35,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// <summary> /// <summary>
/// Notifies the navigator that a node was resolved. /// Notifies the navigator that a node was resolved.
/// </summary> /// </summary>
/// <param name="node">The node that was resolved</param>
/// <param name="result">Resolve result</param>
void Resolved(AstNode node, ResolveResult result); void Resolved(AstNode node, ResolveResult result);
/// <summary>
/// Notifies the navigator that a conversion was applied.
/// </summary>
/// <param name="expression">The expression that was resolved.</param>
/// <param name="result">The resolve result of the expression.</param>
/// <param name="conversion">The conversion applied to the expressed.</param>
/// <param name="targetType">The target type of the conversion.</param>
void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType);
} }
/// <summary> /// <summary>
@ -53,12 +64,40 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary> /// </summary>
Skip, Skip,
/// <summary> /// <summary>
/// Resolve the current node; but only scan subnodes which are not required for resolving the current node. /// Resolve the current node.
/// Subnodes which are not required for resolving the current node
/// will ask the navigator again whether they should be resolved.
/// </summary> /// </summary>
Resolve, Resolve
/// <summary> }
/// Resolves all nodes in the current subtree.
/// </summary> sealed class ConstantModeResolveVisitorNavigator : IResolveVisitorNavigator
ResolveAll {
readonly ResolveVisitorNavigationMode mode;
readonly IResolveVisitorNavigator targetForResolveCalls;
public ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode mode, IResolveVisitorNavigator targetForResolveCalls)
{
this.mode = mode;
this.targetForResolveCalls = targetForResolveCalls;
}
ResolveVisitorNavigationMode IResolveVisitorNavigator.Scan(AstNode node)
{
return mode;
}
void IResolveVisitorNavigator.Resolved(AstNode node, ResolveResult result)
{
if (targetForResolveCalls != null)
targetForResolveCalls.Resolved(node, result);
}
void IResolveVisitorNavigator.ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{
if (targetForResolveCalls != null)
targetForResolveCalls.ProcessConversion(expression, result, conversion, targetType);
}
} }
} }

17
ICSharpCode.NRefactory/CSharp/Resolver/NodeListResolveVisitorNavigator.cs

@ -18,6 +18,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
@ -32,12 +33,20 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// <summary> /// <summary>
/// Creates a new NodeListResolveVisitorNavigator that resolves the specified nodes. /// Creates a new NodeListResolveVisitorNavigator that resolves the specified nodes.
/// </summary> /// </summary>
public NodeListResolveVisitorNavigator(IEnumerable<AstNode> nodes) public NodeListResolveVisitorNavigator(params AstNode[] nodes)
: this((IEnumerable<AstNode>)nodes)
{
}
/// <summary>
/// Creates a new NodeListResolveVisitorNavigator that resolves the specified nodes.
/// </summary>
public NodeListResolveVisitorNavigator(IEnumerable<AstNode> nodes, bool scanOnly = false)
{ {
if (nodes == null) if (nodes == null)
throw new ArgumentNullException("nodes"); throw new ArgumentNullException("nodes");
foreach (var node in nodes) { foreach (var node in nodes) {
dict[node] = ResolveVisitorNavigationMode.Resolve; dict[node] = scanOnly ? ResolveVisitorNavigationMode.Scan : ResolveVisitorNavigationMode.Resolve;
for (var ancestor = node.Parent; ancestor != null && !dict.ContainsKey(ancestor); ancestor = ancestor.Parent) { for (var ancestor = node.Parent; ancestor != null && !dict.ContainsKey(ancestor); ancestor = ancestor.Parent) {
dict.Add(ancestor, ResolveVisitorNavigationMode.Scan); dict.Add(ancestor, ResolveVisitorNavigationMode.Scan);
} }
@ -58,5 +67,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
void IResolveVisitorNavigator.Resolved(AstNode node, ResolveResult result) void IResolveVisitorNavigator.Resolved(AstNode node, ResolveResult result)
{ {
} }
void IResolveVisitorNavigator.ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{
}
} }
} }

424
ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs

@ -66,8 +66,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
readonly Dictionary<AstNode, ResolveResult> resolveResultCache = new Dictionary<AstNode, ResolveResult>(); readonly Dictionary<AstNode, ResolveResult> resolveResultCache = new Dictionary<AstNode, ResolveResult>();
readonly Dictionary<AstNode, CSharpResolver> resolverBeforeDict = new Dictionary<AstNode, CSharpResolver>(); readonly Dictionary<AstNode, CSharpResolver> resolverBeforeDict = new Dictionary<AstNode, CSharpResolver>();
readonly IResolveVisitorNavigator navigator; IResolveVisitorNavigator navigator;
ResolveVisitorNavigationMode mode = ResolveVisitorNavigationMode.Scan; bool resolverEnabled;
List<LambdaBase> undecidedLambdas; List<LambdaBase> undecidedLambdas;
#region Constructor #region Constructor
@ -86,7 +86,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </param> /// </param>
/// <param name="navigator"> /// <param name="navigator">
/// The navigator, which controls where the resolve visitor will switch between scanning mode and resolving mode. /// The navigator, which controls where the resolve visitor will switch between scanning mode and resolving mode.
/// If you pass <c>null</c>, then <c>ResolveAll</c> mode will be used. /// If you pass <c>null</c>, then nothing will be resolved on the initial scan, and the resolver
/// will resolve additional nodes on demand (when one of the Get-methods is called).
/// </param> /// </param>
public ResolveVisitor(CSharpResolver resolver, ParsedFile parsedFile, IResolveVisitorNavigator navigator = null) public ResolveVisitor(CSharpResolver resolver, ParsedFile parsedFile, IResolveVisitorNavigator navigator = null)
{ {
@ -94,10 +95,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
throw new ArgumentNullException("resolver"); throw new ArgumentNullException("resolver");
this.resolver = resolver; this.resolver = resolver;
this.parsedFile = parsedFile; this.parsedFile = parsedFile;
this.navigator = navigator; this.navigator = navigator ?? new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Skip, null);
this.voidResult = new ResolveResult(KnownTypeReference.Void.Resolve(resolver.Context)); this.voidResult = new ResolveResult(KnownTypeReference.Void.Resolve(resolver.Context));
if (navigator == null)
mode = ResolveVisitorNavigationMode.ResolveAll;
} }
#endregion #endregion
@ -123,19 +122,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary> /// </summary>
void ResetContext(CSharpResolver storedContext, Action action) void ResetContext(CSharpResolver storedContext, Action action)
{ {
var oldMode = this.mode; var oldResolverEnabled = this.resolverEnabled;
var oldResolver = this.resolver; var oldResolver = this.resolver;
var oldTypeLookupMode = this.currentTypeLookupMode; var oldTypeLookupMode = this.currentTypeLookupMode;
var oldQueryType = this.currentQueryResult; var oldQueryType = this.currentQueryResult;
try { try {
this.mode = (navigator == null) ? ResolveVisitorNavigationMode.ResolveAll : ResolveVisitorNavigationMode.Resolve; this.resolverEnabled = false;
this.resolver = storedContext; this.resolver = storedContext;
this.currentTypeLookupMode = SimpleNameLookupMode.Type; this.currentTypeLookupMode = SimpleNameLookupMode.Type;
this.currentQueryResult = null; this.currentQueryResult = null;
action(); action();
} finally { } finally {
this.mode = oldMode; this.resolverEnabled = oldResolverEnabled;
this.resolver = oldResolver; this.resolver = oldResolver;
this.currentTypeLookupMode = oldTypeLookupMode; this.currentTypeLookupMode = oldTypeLookupMode;
this.currentQueryResult = oldQueryType; this.currentQueryResult = oldQueryType;
@ -144,10 +143,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion #endregion
#region Scan / Resolve #region Scan / Resolve
bool resolverEnabled { /// <summary>
get { return mode != ResolveVisitorNavigationMode.Scan; } /// Scans the AST rooted at the given node.
} /// </summary>
public void Scan(AstNode node) public void Scan(AstNode node)
{ {
if (node == null || node.IsNull) if (node == null || node.IsNull)
@ -157,44 +155,52 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
case NodeType.Whitespace: case NodeType.Whitespace:
return; // skip tokens, identifiers, comments, etc. return; // skip tokens, identifiers, comments, etc.
} }
if (mode == ResolveVisitorNavigationMode.ResolveAll) {
Resolve(node); var mode = navigator.Scan(node);
} else { switch (mode) {
ResolveVisitorNavigationMode oldMode = mode; case ResolveVisitorNavigationMode.Skip:
mode = navigator.Scan(node); if (node is VariableDeclarationStatement) {
switch (mode) { // Enforce scanning of variable declarations.
case ResolveVisitorNavigationMode.Skip: goto case ResolveVisitorNavigationMode.Scan;
if (node is VariableDeclarationStatement) { }
// Enforce scanning of variable declarations. if (resolverBeforeDict.Count == 0) {
goto case ResolveVisitorNavigationMode.Scan; // If we're just starting to resolve and haven't any context cached yet,
} // make sure to cache the root node.
break;
case ResolveVisitorNavigationMode.Scan:
if (node is LambdaExpression || node is AnonymousMethodExpression) {
// lambdas must be resolved so that they get stored in the 'undecided' list only once
goto case ResolveVisitorNavigationMode.Resolve;
}
StoreState(node, resolver.Clone()); StoreState(node, resolver.Clone());
node.AcceptVisitor(this, null); }
break; break;
case ResolveVisitorNavigationMode.Resolve: case ResolveVisitorNavigationMode.Scan:
case ResolveVisitorNavigationMode.ResolveAll: if (node is LambdaExpression || node is AnonymousMethodExpression) {
Resolve(node); // lambdas must be resolved so that they get stored in the 'undecided' list only once
break; goto case ResolveVisitorNavigationMode.Resolve;
default: }
throw new InvalidOperationException("Invalid value for ResolveVisitorNavigationMode"); bool oldResolverEnabled = resolverEnabled;
} resolverEnabled = false;
mode = oldMode; StoreState(node, resolver.Clone());
node.AcceptVisitor(this, null);
resolverEnabled = oldResolverEnabled;
break;
case ResolveVisitorNavigationMode.Resolve:
Resolve(node);
break;
default:
throw new InvalidOperationException("Invalid value for ResolveVisitorNavigationMode");
} }
} }
/// <summary>
/// Equivalent to 'Scan', but also resolves the node at the same time.
/// This method should be only used if the CSharpResolver passed to the ResolveVisitor was manually set
/// to the correct state.
/// Otherwise, use <c>resolver.Scan(compilationUnit); var result = resolver.GetResolveResult(node);</c>
/// instead.
/// </summary>
public ResolveResult Resolve(AstNode node) public ResolveResult Resolve(AstNode node)
{ {
if (node == null || node.IsNull) if (node == null || node.IsNull)
return errorResult; return errorResult;
bool wasScan = mode == ResolveVisitorNavigationMode.Scan; bool oldResolverEnabled = resolverEnabled;
if (wasScan) resolverEnabled = true;
mode = ResolveVisitorNavigationMode.Resolve;
ResolveResult result; ResolveResult result;
if (!resolveResultCache.TryGetValue(node, out result)) { if (!resolveResultCache.TryGetValue(node, out result)) {
resolver.cancellationToken.ThrowIfCancellationRequested(); resolver.cancellationToken.ThrowIfCancellationRequested();
@ -202,13 +208,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
result = node.AcceptVisitor(this, null) ?? errorResult; result = node.AcceptVisitor(this, null) ?? errorResult;
Log.WriteLine("Resolved '{0}' to {1}", node, result); Log.WriteLine("Resolved '{0}' to {1}", node, result);
StoreResult(node, result); StoreResult(node, result);
ProcessConversionsInResult(result);
} }
if (wasScan) resolverEnabled = oldResolverEnabled;
mode = ResolveVisitorNavigationMode.Scan;
return result; return result;
} }
IType ResolveType(AstType type)
{
return Resolve(type).Type;
}
void StoreState(AstNode node, CSharpResolver resolverState) void StoreState(AstNode node, CSharpResolver resolverState)
{ {
Debug.Assert(resolverState != null); Debug.Assert(resolverState != null);
@ -220,6 +229,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
void StoreResult(AstNode node, ResolveResult result) void StoreResult(AstNode node, ResolveResult result)
{ {
Debug.Assert(result != null); Debug.Assert(result != null);
if (node.IsNull)
return;
resolveResultCache.Add(node, result); resolveResultCache.Add(node, result);
if (navigator != null) if (navigator != null)
navigator.Resolved(node, result); navigator.Resolved(node, result);
@ -234,31 +245,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion #endregion
#region Process Conversions #region Process Conversions
/// <summary>
/// Processes conversions within this resolve result.
/// </summary>
void ProcessConversionsInResult(ResolveResult result)
{
ConversionResolveResult crr = result as ConversionResolveResult;
if (crr != null) {
ProcessConversion(crr.Input, crr.Conversion, crr.Type);
} else {
foreach (ResolveResult argumentResult in result.GetChildResults()) {
crr = argumentResult as ConversionResolveResult;
if (crr != null)
ProcessConversion(crr.Input, crr.Conversion, crr.Type);
}
}
}
/// <summary>
/// Convert 'rr' to the target type.
/// </summary>
void ProcessConversion(ResolveResult rr, IType targetType)
{
ProcessConversion(rr, resolver.conversions.ImplicitConversion(rr, targetType), targetType);
}
sealed class AnonymousFunctionConversionData sealed class AnonymousFunctionConversionData
{ {
public readonly IType ReturnType; public readonly IType ReturnType;
@ -285,7 +271,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// <summary> /// <summary>
/// Convert 'rr' to the target type using the specified conversion. /// Convert 'rr' to the target type using the specified conversion.
/// </summary> /// </summary>
void ProcessConversion(ResolveResult rr, Conversion conversion, IType targetType) void ProcessConversion(Expression expr, ResolveResult rr, Conversion conversion, IType targetType)
{ {
if (conversion.IsAnonymousFunctionConversion) { if (conversion.IsAnonymousFunctionConversion) {
Log.WriteLine("Processing conversion of anonymous function to " + targetType + "..."); Log.WriteLine("Processing conversion of anonymous function to " + targetType + "...");
@ -301,6 +287,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Log.WriteLine(" Data not found."); Log.WriteLine(" Data not found.");
} }
} }
if (expr != null && conversion != Conversion.IdentityConversion)
navigator.ProcessConversion(expr, rr, conversion, targetType);
}
/// <summary>
/// Convert 'rr' to the target type.
/// </summary>
void ProcessConversion(Expression expr, ResolveResult rr, IType targetType)
{
ProcessConversion(expr, rr, resolver.conversions.ImplicitConversion(rr, targetType), targetType);
} }
/// <summary> /// <summary>
@ -312,29 +308,99 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// no need to resolve the expression right now // no need to resolve the expression right now
Scan(expr); Scan(expr);
} else { } else {
ProcessConversion(Resolve(expr), targetType); ProcessConversion(expr, Resolve(expr), targetType);
}
}
void ProcessConversionResult(Expression expr, ConversionResolveResult rr)
{
if (rr != null)
ProcessConversion(expr, rr.Input, rr.Conversion, rr.Type);
}
void ProcessConversionResults(IEnumerable<Expression> expr, IEnumerable<ResolveResult> conversionResolveResults)
{
Debug.Assert(expr.Count() == conversionResolveResults.Count());
using (var e1 = expr.GetEnumerator()) {
using (var e2 = conversionResolveResults.GetEnumerator()) {
while (e1.MoveNext() && e2.MoveNext()) {
ProcessConversionResult(e1.Current, e2.Current as ConversionResolveResult);
}
}
}
}
void ProcessConversionsInInvocation(Expression target, IEnumerable<Expression> arguments, InvocationResolveResult invocation)
{
if (invocation == null)
return;
int i = 0;
if (invocation.IsExtensionMethodInvocation) {
Debug.Assert(arguments.Count() + 1 == invocation.Arguments.Count);
ProcessConversionResult(target, invocation.Arguments[0] as ConversionResolveResult);
i = 1;
} else {
Debug.Assert(arguments.Count() == invocation.Arguments.Count);
}
foreach (Expression arg in arguments) {
NamedArgumentExpression nae = arg as NamedArgumentExpression;
if (nae != null)
ProcessConversionResult(nae.Expression, invocation.Arguments[i++] as ConversionResolveResult);
else
ProcessConversionResult(arg, invocation.Arguments[i++] as ConversionResolveResult);
} }
} }
#endregion #endregion
#region GetResolveResult #region GetResolveResult
/// <summary> /// <summary>
/// Gets the cached resolve result for the specified node. /// Gets the resolve result for the specified node.
/// Returns <c>null</c> if no cached result was found (e.g. if the node was not visited; or if it was visited in scanning mode). /// If the node was not resolved by the navigator, this method will resolve it.
/// </summary> /// </summary>
public ResolveResult GetResolveResult(AstNode node) public ResolveResult GetResolveResult(AstNode node)
{ {
MergeUndecidedLambdas(); MergeUndecidedLambdas();
ResolveResult result; ResolveResult result;
if (resolveResultCache.TryGetValue(node, out result))
return result;
AstNode parent;
CSharpResolver storedResolver = GetPreviouslyScannedContext(node, out parent);
ResetContext(
storedResolver.Clone(),
delegate {
navigator = new NodeListResolveVisitorNavigator(node);
if (parent == node) {
Resolve(node);
} else {
Debug.Assert(!resolverEnabled);
parent.AcceptVisitor(this, null);
}
});
MergeUndecidedLambdas();
if (resolveResultCache.TryGetValue(node, out result)) if (resolveResultCache.TryGetValue(node, out result))
return result; return result;
else else
return null; return null;
} }
CSharpResolver GetPreviouslyScannedContext(AstNode node, out AstNode parent)
{
parent = node;
CSharpResolver storedResolver;
while (!resolverBeforeDict.TryGetValue(parent, out storedResolver)) {
parent = parent.Parent;
if (parent == null)
throw new InvalidOperationException("Could not find a resolver state for any parent of the specified node. Did you forget to call 'Scan(compilationUnit);'?");
}
return storedResolver;
}
/// <summary> /// <summary>
/// Gets the resolver state in front of the specified node. /// Gets the resolver state in front of the specified node.
/// Returns <c>null</c> if no cached resolver was found (e.g. if the node was skipped by the navigator) /// If the node was not visited by a previous scanning process, the
/// AST will be scanned again to determine the state.
/// </summary> /// </summary>
public CSharpResolver GetResolverStateBefore(AstNode node) public CSharpResolver GetResolverStateBefore(AstNode node)
{ {
@ -342,8 +408,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
CSharpResolver r; CSharpResolver r;
if (resolverBeforeDict.TryGetValue(node, out r)) if (resolverBeforeDict.TryGetValue(node, out r))
return r; return r;
else
return null; AstNode parent;
CSharpResolver storedResolver = GetPreviouslyScannedContext(node, out parent);
ResetContext(
storedResolver.Clone(),
delegate {
navigator = new NodeListResolveVisitorNavigator(new[] { node }, scanOnly: true);
Debug.Assert(!resolverEnabled);
parent.AcceptVisitor(this, null);
});
MergeUndecidedLambdas();
while (node != null) {
if (resolverBeforeDict.TryGetValue(node, out r))
return r;
node = node.Parent;
}
return null;
} }
#endregion #endregion
@ -494,12 +576,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ArrayType arrayType = result.Type as ArrayType; ArrayType arrayType = result.Type as ArrayType;
if (aie != null && arrayType != null) { if (aie != null && arrayType != null) {
StoreState(aie, resolver.Clone()); StoreState(aie, resolver.Clone());
List<ResolveResult> list = new List<ResolveResult>(); List<Expression> initializerElements = new List<Expression>();
UnpackArrayInitializer(list, aie, arrayType.Dimensions); UnpackArrayInitializer(initializerElements, aie, arrayType.Dimensions);
ResolveResult[] initializerElements = list.ToArray(); ResolveResult[] initializerElementResults = new ResolveResult[initializerElements.Count];
ResolveResult arrayCreation = resolver.ResolveArrayCreation(arrayType.ElementType, arrayType.Dimensions, null, initializerElements); for (int i = 0; i < initializerElementResults.Length; i++) {
initializerElementResults[i] = Resolve(initializerElements[i]);
}
var arrayCreation = resolver.ResolveArrayCreation(arrayType.ElementType, arrayType.Dimensions, null, initializerElementResults);
StoreResult(aie, arrayCreation); StoreResult(aie, arrayCreation);
ProcessConversionsInResult(arrayCreation); ProcessConversionResults(initializerElements, arrayCreation.InitializerElements);
} else { } else {
ResolveAndProcessConversion(variableInitializer.Initializer, result.Type); ResolveAndProcessConversion(variableInitializer.Initializer, result.Type);
} }
@ -754,11 +839,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion #endregion
#region Visit Expressions #region Visit Expressions
IType ResolveType(AstType type)
{
return Resolve(type).Type;
}
static string GetAnonymousTypePropertyName(Expression expr, out Expression resolveExpr) static string GetAnonymousTypePropertyName(Expression expr, out Expression resolveExpr)
{ {
if (expr is NamedExpression) { if (expr is NamedExpression) {
@ -829,40 +909,47 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
} }
ResolveResult[] initializerElements; List<Expression> initializerElements;
ResolveResult[] initializerElementResults;
if (arrayCreateExpression.Initializer.IsNull) { if (arrayCreateExpression.Initializer.IsNull) {
initializerElements = null; initializerElements = null;
initializerElementResults = null;
} else { } else {
List<ResolveResult> list = new List<ResolveResult>(); initializerElements = new List<Expression>();
UnpackArrayInitializer(list, arrayCreateExpression.Initializer, dimensions); UnpackArrayInitializer(initializerElements, arrayCreateExpression.Initializer, dimensions);
initializerElements = list.ToArray(); initializerElementResults = new ResolveResult[initializerElements.Count];
for (int i = 0; i < initializerElementResults.Length; i++) {
initializerElementResults[i] = Resolve(initializerElements[i]);
}
} }
ArrayCreateResolveResult acrr;
if (arrayCreateExpression.Type.IsNull) { if (arrayCreateExpression.Type.IsNull) {
return resolver.ResolveArrayCreation(null, dimensions, sizeArguments, initializerElements); acrr = resolver.ResolveArrayCreation(null, dimensions, sizeArguments, initializerElementResults);
} else { } else {
IType elementType = ResolveType(arrayCreateExpression.Type); IType elementType = ResolveType(arrayCreateExpression.Type);
foreach (var spec in arrayCreateExpression.AdditionalArraySpecifiers.Reverse()) { foreach (var spec in arrayCreateExpression.AdditionalArraySpecifiers.Reverse()) {
elementType = new ArrayType(elementType, spec.Dimensions); elementType = new ArrayType(elementType, spec.Dimensions);
} }
return resolver.ResolveArrayCreation(elementType, dimensions, sizeArguments, initializerElements); acrr = resolver.ResolveArrayCreation(elementType, dimensions, sizeArguments, initializerElementResults);
} }
return acrr;
} }
void UnpackArrayInitializer(List<ResolveResult> list, ArrayInitializerExpression initializer, int dimensions) void UnpackArrayInitializer(List<Expression> elementList, ArrayInitializerExpression initializer, int dimensions)
{ {
Debug.Assert(dimensions >= 1); Debug.Assert(dimensions >= 1);
if (dimensions > 1) { if (dimensions > 1) {
foreach (var node in initializer.Elements) { foreach (var node in initializer.Elements) {
ArrayInitializerExpression aie = node as ArrayInitializerExpression; ArrayInitializerExpression aie = node as ArrayInitializerExpression;
if (aie != null) if (aie != null)
UnpackArrayInitializer(list, aie, dimensions - 1); UnpackArrayInitializer(elementList, aie, dimensions - 1);
else else
list.Add(Resolve(node)); elementList.Add(node);
} }
} else { } else {
foreach (var expr in initializer.Elements) foreach (var expr in initializer.Elements)
list.Add(Resolve(expr)); elementList.Add(expr);
} }
} }
@ -909,9 +996,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult IAstVisitor<object, ResolveResult>.VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data) ResolveResult IAstVisitor<object, ResolveResult>.VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data)
{ {
if (resolverEnabled) { if (resolverEnabled) {
ResolveResult left = Resolve(binaryOperatorExpression.Left); Expression left = binaryOperatorExpression.Left;
ResolveResult right = Resolve(binaryOperatorExpression.Right); Expression right = binaryOperatorExpression.Right;
return resolver.ResolveBinaryOperator(binaryOperatorExpression.Operator, left, right); ResolveResult leftResult = Resolve(left);
ResolveResult rightResult = Resolve(right);
ResolveResult rr = resolver.ResolveBinaryOperator(binaryOperatorExpression.Operator, leftResult, rightResult);
BinaryOperatorResolveResult borr = rr as BinaryOperatorResolveResult;
if (borr != null) {
ProcessConversionResult(left, borr.Left as ConversionResolveResult);
ProcessConversionResult(right, borr.Right as ConversionResolveResult);
} else {
InvocationResolveResult irr = rr as InvocationResolveResult;
if (irr != null && irr.Arguments.Count == 2) {
ProcessConversionResult(left, irr.Arguments[0] as ConversionResolveResult);
ProcessConversionResult(right, irr.Arguments[1] as ConversionResolveResult);
}
}
return rr;
} else { } else {
ScanChildren(binaryOperatorExpression); ScanChildren(binaryOperatorExpression);
return null; return null;
@ -921,7 +1022,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult IAstVisitor<object, ResolveResult>.VisitCastExpression(CastExpression castExpression, object data) ResolveResult IAstVisitor<object, ResolveResult>.VisitCastExpression(CastExpression castExpression, object data)
{ {
if (resolverEnabled) { if (resolverEnabled) {
return resolver.ResolveCast(ResolveType(castExpression.Type), Resolve(castExpression.Expression)); IType targetType = ResolveType(castExpression.Type);
Expression expr = castExpression.Expression;
ResolveResult rr = resolver.ResolveCast(targetType, Resolve(expr));
ProcessConversionResult(expr, rr as ConversionResolveResult);
return rr;
} else { } else {
ScanChildren(castExpression); ScanChildren(castExpression);
return null; return null;
@ -931,10 +1036,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult IAstVisitor<object, ResolveResult>.VisitConditionalExpression(ConditionalExpression conditionalExpression, object data) ResolveResult IAstVisitor<object, ResolveResult>.VisitConditionalExpression(ConditionalExpression conditionalExpression, object data)
{ {
if (resolverEnabled) { if (resolverEnabled) {
return resolver.ResolveConditional( Expression condition = conditionalExpression.Condition;
Resolve(conditionalExpression.Condition), Expression trueExpr = conditionalExpression.TrueExpression;
Resolve(conditionalExpression.TrueExpression), Expression falseExpr = conditionalExpression.FalseExpression;
Resolve(conditionalExpression.FalseExpression));
ResolveResult rr = resolver.ResolveConditional(Resolve(condition), Resolve(trueExpr), Resolve(falseExpr));
ConditionalOperatorResolveResult corr = rr as ConditionalOperatorResolveResult;
if (corr != null) {
ProcessConversionResult(condition, corr.Condition as ConversionResolveResult);
ProcessConversionResult(trueExpr, corr.True as ConversionResolveResult);
ProcessConversionResult(falseExpr, corr.False as ConversionResolveResult);
}
return rr;
} else { } else {
ScanChildren(conditionalExpression); ScanChildren(conditionalExpression);
return null; return null;
@ -970,10 +1083,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult IAstVisitor<object, ResolveResult>.VisitIndexerExpression(IndexerExpression indexerExpression, object data) ResolveResult IAstVisitor<object, ResolveResult>.VisitIndexerExpression(IndexerExpression indexerExpression, object data)
{ {
if (resolverEnabled) { if (resolverEnabled) {
ResolveResult target = Resolve(indexerExpression.Target); Expression target = indexerExpression.Target;
ResolveResult targetResult = Resolve(target);
string[] argumentNames; string[] argumentNames;
ResolveResult[] arguments = GetArguments(indexerExpression.Arguments, out argumentNames); ResolveResult[] arguments = GetArguments(indexerExpression.Arguments, out argumentNames);
return resolver.ResolveIndexer(target, arguments, argumentNames); ResolveResult rr = resolver.ResolveIndexer(targetResult, arguments, argumentNames);
ArrayAccessResolveResult aarr = rr as ArrayAccessResolveResult;
if (aarr != null) {
ProcessConversionResults(indexerExpression.Arguments, aarr.Indices);
} else {
ProcessConversionsInInvocation(target, indexerExpression.Arguments, rr as InvocationResolveResult);
}
return rr;
} else { } else {
ScanChildren(indexerExpression); ScanChildren(indexerExpression);
return null; return null;
@ -1043,7 +1164,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
string[] argumentNames; string[] argumentNames;
ResolveResult[] arguments = GetArguments(objectCreateExpression.Arguments, out argumentNames); ResolveResult[] arguments = GetArguments(objectCreateExpression.Arguments, out argumentNames);
return resolver.ResolveObjectCreation(type, arguments, argumentNames); ResolveResult rr = resolver.ResolveObjectCreation(type, arguments, argumentNames);
ProcessConversionsInInvocation(null, objectCreateExpression.Arguments, rr as InvocationResolveResult);
return rr;
} else { } else {
foreach (AstNode node in objectCreateExpression.Arguments) { foreach (AstNode node in objectCreateExpression.Arguments) {
Scan(node); Scan(node);
@ -1081,7 +1204,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
OverloadResolution or = mgrr.PerformOverloadResolution(resolver.Context, addArguments, null, false, false, resolver.conversions); OverloadResolution or = mgrr.PerformOverloadResolution(resolver.Context, addArguments, null, false, false, resolver.conversions);
var invocationRR = new InvocationResolveResult(targetResult, or, resolver.Context); var invocationRR = new InvocationResolveResult(targetResult, or, resolver.Context);
StoreResult(aie, invocationRR); StoreResult(aie, invocationRR);
ProcessConversionsInResult(invocationRR); ProcessConversionsInInvocation(null, aie.Elements, invocationRR);
} else { } else {
StoreResult(aie, addRR); StoreResult(aie, addRR);
} }
@ -1182,8 +1305,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult IAstVisitor<object, ResolveResult>.VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data) ResolveResult IAstVisitor<object, ResolveResult>.VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data)
{ {
if (resolverEnabled) { if (resolverEnabled) {
ResolveResult expr = Resolve(unaryOperatorExpression.Expression); Expression expr = unaryOperatorExpression.Expression;
return resolver.ResolveUnaryOperator(unaryOperatorExpression.Operator, expr); ResolveResult input = Resolve(expr);
ResolveResult rr = resolver.ResolveUnaryOperator(unaryOperatorExpression.Operator, input);
UnaryOperatorResolveResult uorr = rr as UnaryOperatorResolveResult;
if (uorr != null) {
ProcessConversionResult(expr, uorr.Input as ConversionResolveResult);
} else {
InvocationResolveResult irr = rr as InvocationResolveResult;
if (irr != null && irr.Arguments.Count == 1) {
ProcessConversionResult(expr, irr.Arguments[0] as ConversionResolveResult);
}
}
return rr;
} else { } else {
ScanChildren(unaryOperatorExpression); ScanChildren(unaryOperatorExpression);
return null; return null;
@ -1320,13 +1454,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult simpleNameRR = IsStaticResult(rr, null) ? trr : target; ResolveResult simpleNameRR = IsStaticResult(rr, null) ? trr : target;
Log.WriteLine("Ambiguous simple name '{0}' was resolved to {1}", identifierExpression, simpleNameRR); Log.WriteLine("Ambiguous simple name '{0}' was resolved to {1}", identifierExpression, simpleNameRR);
StoreResult(identifierExpression, simpleNameRR); StoreResult(identifierExpression, simpleNameRR);
ProcessConversionsInResult(simpleNameRR);
return rr; return rr;
} else { } else {
// It's not ambiguous // It's not ambiguous
Log.WriteLine("Simple name '{0}' was resolved to {1}", identifierExpression, target); Log.WriteLine("Simple name '{0}' was resolved to {1}", identifierExpression, target);
StoreResult(identifierExpression, target); StoreResult(identifierExpression, target);
ProcessConversionsInResult(target);
if (resolverEnabled) { if (resolverEnabled) {
return ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression); return ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression);
} else { } else {
@ -1375,7 +1507,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult target = ResolveMemberReferenceOnGivenTarget(idRR, mre); ResolveResult target = ResolveMemberReferenceOnGivenTarget(idRR, mre);
Log.WriteLine("Member reference '{0}' on potentially-ambiguous simple-name was resolved to {1}", mre, target); Log.WriteLine("Member reference '{0}' on potentially-ambiguous simple-name was resolved to {1}", mre, target);
StoreResult(mre, target); StoreResult(mre, target);
ProcessConversionsInResult(target);
TypeResolveResult trr; TypeResolveResult trr;
if (IsVariableReferenceWithSameType(idRR, identifierExpression.Identifier, out trr)) { if (IsVariableReferenceWithSameType(idRR, identifierExpression.Identifier, out trr)) {
// It's ambiguous // It's ambiguous
@ -1384,13 +1515,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Log.WriteLine("Ambiguous simple name '{0}' was resolved to {1}", Log.WriteLine("Ambiguous simple name '{0}' was resolved to {1}",
identifierExpression, simpleNameRR); identifierExpression, simpleNameRR);
StoreResult(identifierExpression, simpleNameRR); StoreResult(identifierExpression, simpleNameRR);
ProcessConversionsInResult(simpleNameRR);
return rr; return rr;
} else { } else {
// It's not ambiguous // It's not ambiguous
Log.WriteLine("Simple name '{0}' was resolved to {1}", identifierExpression, idRR); Log.WriteLine("Simple name '{0}' was resolved to {1}", identifierExpression, idRR);
StoreResult(identifierExpression, idRR); StoreResult(identifierExpression, idRR);
ProcessConversionsInResult(idRR);
if (resolverEnabled) { if (resolverEnabled) {
return ResolveInvocationOnGivenTarget(target, invocationExpression); return ResolveInvocationOnGivenTarget(target, invocationExpression);
} else { } else {
@ -1418,7 +1547,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
string[] argumentNames; string[] argumentNames;
ResolveResult[] arguments = GetArguments(invocationExpression.Arguments, out argumentNames); ResolveResult[] arguments = GetArguments(invocationExpression.Arguments, out argumentNames);
return resolver.ResolveInvocation(target, arguments, argumentNames); ResolveResult rr = resolver.ResolveInvocation(target, arguments, argumentNames);
ProcessConversionsInInvocation(invocationExpression.Target, invocationExpression.Arguments, rr as InvocationResolveResult);
return rr;
} }
#endregion #endregion
@ -1491,6 +1622,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
AstNode body; AstNode body;
IType inferredReturnType; IType inferredReturnType;
IList<Expression> returnExpressions;
IList<ResolveResult> returnValues; IList<ResolveResult> returnValues;
bool isValidAsVoidMethod; bool isValidAsVoidMethod;
bool success; bool success;
@ -1540,7 +1672,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
visitor.ResetContext( visitor.ResetContext(
storedContext, storedContext,
delegate { delegate {
visitor.AnalyzeLambda(body, out success, out isValidAsVoidMethod, out inferredReturnType, out returnValues); visitor.AnalyzeLambda(body, out success, out isValidAsVoidMethod, out inferredReturnType, out returnExpressions, out returnValues);
}); });
Log.Unindent(); Log.Unindent();
Log.WriteLine("Finished analyzing " + this.LambdaExpression); Log.WriteLine("Finished analyzing " + this.LambdaExpression);
@ -1605,8 +1737,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
visitor.undecidedLambdas.Remove(this); visitor.undecidedLambdas.Remove(this);
Analyze(); Analyze();
Log.WriteLine("Applying return type {0} to explicitly-typed lambda {1}", returnType, this.LambdaExpression); Log.WriteLine("Applying return type {0} to explicitly-typed lambda {1}", returnType, this.LambdaExpression);
foreach (var returnValue in returnValues) { for (int i = 0; i < returnExpressions.Count; i++) {
visitor.ProcessConversion(returnValue, returnType); visitor.ProcessConversion(returnExpressions[i], returnValues[i], returnType);
} }
} }
@ -1802,6 +1934,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
readonly ResolveVisitor visitor; readonly ResolveVisitor visitor;
internal readonly IType inferredReturnType; internal readonly IType inferredReturnType;
IList<Expression> returnExpressions;
IList<ResolveResult> returnValues; IList<ResolveResult> returnValues;
bool isValidAsVoidMethod; bool isValidAsVoidMethod;
internal bool success; internal bool success;
@ -1833,7 +1966,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
} }
visitor.AnalyzeLambda(lambda.Body, out success, out isValidAsVoidMethod, out inferredReturnType, out returnValues); visitor.AnalyzeLambda(lambda.Body, out success, out isValidAsVoidMethod, out inferredReturnType, out returnExpressions, out returnValues);
visitor.resolver.PopBlock(); visitor.resolver.PopBlock();
Log.Unindent(); Log.Unindent();
Log.WriteLine("Finished analyzing " + ToString()); Log.WriteLine("Finished analyzing " + ToString());
@ -1872,8 +2005,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
lambda.winningHypothesis = this; lambda.winningHypothesis = this;
foreach (var returnValue in returnValues) { for (int i = 0; i < returnExpressions.Count; i++) {
visitor.ProcessConversion(returnValue, returnType); visitor.ProcessConversion(returnExpressions[i], returnValues[i], returnType);
} }
visitor.MergeUndecidedLambdas(); visitor.MergeUndecidedLambdas();
@ -1933,7 +2066,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (parent != null && resolverBeforeDict.TryGetValue(parent, out storedResolver)) { if (parent != null && resolverBeforeDict.TryGetValue(parent, out storedResolver)) {
Log.WriteLine("Trying to resolve '" + parent + "' in order to merge the lambda..."); Log.WriteLine("Trying to resolve '" + parent + "' in order to merge the lambda...");
Log.Indent(); Log.Indent();
ResetContext(storedResolver, delegate { Resolve(parent); }); ResetContext(storedResolver.Clone(), delegate { Resolve(parent); });
Log.Unindent(); Log.Unindent();
} else { } else {
Log.WriteLine("Could not find a suitable parent for '" + lambda); Log.WriteLine("Could not find a suitable parent for '" + lambda);
@ -1962,12 +2095,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion #endregion
#region AnalyzeLambda #region AnalyzeLambda
void AnalyzeLambda(AstNode body, out bool success, out bool isValidAsVoidMethod, out IType inferredReturnType, out IList<ResolveResult> returnValues) void AnalyzeLambda(AstNode body, out bool success, out bool isValidAsVoidMethod, out IType inferredReturnType, out IList<Expression> returnExpressions, out IList<ResolveResult> returnValues)
{ {
mode = ResolveVisitorNavigationMode.ResolveAll; var oldNavigator = this.navigator;
this.navigator = new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Resolve, oldNavigator);
Expression expr = body as Expression; Expression expr = body as Expression;
if (expr != null) { if (expr != null) {
isValidAsVoidMethod = ExpressionPermittedAsStatement(expr); isValidAsVoidMethod = ExpressionPermittedAsStatement(expr);
returnExpressions = new [] { expr };
returnValues = new[] { Resolve(expr) }; returnValues = new[] { Resolve(expr) };
inferredReturnType = returnValues[0].Type; inferredReturnType = returnValues[0].Type;
} else { } else {
@ -1977,12 +2113,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
body.AcceptVisitor(alv, null); body.AcceptVisitor(alv, null);
isValidAsVoidMethod = (alv.ReturnExpressions.Count == 0); isValidAsVoidMethod = (alv.ReturnExpressions.Count == 0);
if (alv.HasVoidReturnStatements) { if (alv.HasVoidReturnStatements) {
returnExpressions = EmptyList<Expression>.Instance;
returnValues = EmptyList<ResolveResult>.Instance; returnValues = EmptyList<ResolveResult>.Instance;
inferredReturnType = KnownTypeReference.Void.Resolve(resolver.Context); inferredReturnType = KnownTypeReference.Void.Resolve(resolver.Context);
} else { } else {
returnValues = new ResolveResult[alv.ReturnExpressions.Count]; returnExpressions = alv.ReturnExpressions;
returnValues = new ResolveResult[returnExpressions.Count];
for (int i = 0; i < returnValues.Count; i++) { for (int i = 0; i < returnValues.Count; i++) {
returnValues[i] = resolveResultCache[alv.ReturnExpressions[i]]; returnValues[i] = resolveResultCache[returnExpressions[i]];
} }
TypeInference ti = new TypeInference(resolver.Context, resolver.conversions); TypeInference ti = new TypeInference(resolver.Context, resolver.conversions);
bool tiSuccess; bool tiSuccess;
@ -1993,7 +2131,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
Log.WriteLine("Lambda return type was inferred to: " + inferredReturnType); Log.WriteLine("Lambda return type was inferred to: " + inferredReturnType);
// TODO: check for compiler errors within the lambda body // TODO: check for compiler errors within the lambda body
success = true; success = true;
this.navigator = oldNavigator;
} }
static bool ExpressionPermittedAsStatement(Expression expr) static bool ExpressionPermittedAsStatement(Expression expr)
@ -2079,8 +2219,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ITypeDefinition disposable = resolver.Context.GetTypeDefinition( ITypeDefinition disposable = resolver.Context.GetTypeDefinition(
"System", "IDisposable", 0, StringComparer.Ordinal); "System", "IDisposable", 0, StringComparer.Ordinal);
ResolveAndProcessConversion((Expression)child, disposable ?? SharedTypes.UnknownType); ResolveAndProcessConversion((Expression)child, disposable ?? SharedTypes.UnknownType);
} else {
Scan(child);
} }
Scan(child);
} }
} else { } else {
ScanChildren(usingStatement); ScanChildren(usingStatement);
@ -2113,7 +2254,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
resolver.PushBlock(); resolver.PushBlock();
ITypeReference type = MakeTypeReference(foreachStatement.VariableType, foreachStatement.InExpression, true); ITypeReference type = MakeTypeReference(foreachStatement.VariableType, foreachStatement.InExpression, true);
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)));
ScanChildren(foreachStatement); ScanChildren(foreachStatement);
resolver.PopBlock(); resolver.PopBlock();
return voidResult; return voidResult;
@ -2322,13 +2464,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary> /// </summary>
ITypeReference MakeTypeReference(AstType type, AstNode initializerExpression, bool isForEach) ITypeReference MakeTypeReference(AstType type, AstNode initializerExpression, bool isForEach)
{ {
bool typeNeedsResolving; bool typeNeedsResolving = (navigator.Scan(type) == ResolveVisitorNavigationMode.Resolve);
if (mode == ResolveVisitorNavigationMode.ResolveAll) {
typeNeedsResolving = true;
} else {
var modeForType = navigator.Scan(type);
typeNeedsResolving = (modeForType == ResolveVisitorNavigationMode.Resolve || modeForType == ResolveVisitorNavigationMode.ResolveAll);
}
if (initializerExpression != null && IsVar(type)) { if (initializerExpression != null && IsVar(type)) {
var typeRef = new VarTypeReference(this, resolver.Clone(), initializerExpression, isForEach); var typeRef = new VarTypeReference(this, resolver.Clone(), initializerExpression, isForEach);
if (typeNeedsResolving) { if (typeNeedsResolving) {
@ -2456,7 +2592,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// Resolve the ctor arguments and find the matching ctor overload // Resolve the ctor arguments and find the matching ctor overload
string[] argumentNames; string[] argumentNames;
ResolveResult[] arguments = GetArguments(constructorArguments, out argumentNames); ResolveResult[] arguments = GetArguments(constructorArguments, out argumentNames);
return resolver.ResolveObjectCreation(type, arguments, argumentNames); ResolveResult rr = resolver.ResolveObjectCreation(type, arguments, argumentNames);
ProcessConversionsInInvocation(null, constructorArguments, rr as InvocationResolveResult);
return rr;
} else { } else {
foreach (var node in constructorArguments) foreach (var node in constructorArguments)
Scan(node); Scan(node);
@ -2838,7 +2976,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (invocationRR != null && invocationRR.Arguments.Count > 0) { if (invocationRR != null && invocationRR.Arguments.Count > 0) {
ConversionResolveResult crr = invocationRR.Arguments[invocationRR.Arguments.Count - 1] as ConversionResolveResult; ConversionResolveResult crr = invocationRR.Arguments[invocationRR.Arguments.Count - 1] as ConversionResolveResult;
if (crr != null) if (crr != null)
ProcessConversion(crr.Input, crr.Conversion, crr.Type); ProcessConversion(null, crr.Input, crr.Conversion, crr.Type);
} }
implicitlyTypedLambda.EnforceMerge(this); implicitlyTypedLambda.EnforceMerge(this);
@ -2886,7 +3024,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult condition = Resolve(queryWhereClause.Condition); ResolveResult condition = Resolve(queryWhereClause.Condition);
IType boolType = KnownTypeReference.Boolean.Resolve(resolver.Context); IType boolType = KnownTypeReference.Boolean.Resolve(resolver.Context);
Conversion conversionToBool = resolver.conversions.ImplicitConversion(condition, boolType); Conversion conversionToBool = resolver.conversions.ImplicitConversion(condition, boolType);
ProcessConversion(condition, conversionToBool, boolType); ProcessConversion(queryWhereClause.Condition, condition, conversionToBool, boolType);
if (resolverEnabled && currentQueryResult != null) { if (resolverEnabled && currentQueryResult != null) {
if (conversionToBool != Conversion.IdentityConversion && conversionToBool != Conversion.None) { if (conversionToBool != Conversion.IdentityConversion && conversionToBool != Conversion.None) {
condition = new ConversionResolveResult(boolType, condition, conversionToBool); condition = new ConversionResolveResult(boolType, condition, conversionToBool);
@ -3032,7 +3170,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
string[] argumentNames; string[] argumentNames;
ResolveResult[] arguments = GetArguments(constructorInitializer.Arguments, out argumentNames); ResolveResult[] arguments = GetArguments(constructorInitializer.Arguments, out argumentNames);
return resolver.ResolveObjectCreation(target.Type, arguments, argumentNames); ResolveResult rr = resolver.ResolveObjectCreation(target.Type, arguments, argumentNames);
ProcessConversionsInInvocation(null, constructorInitializer.Arguments, rr as InvocationResolveResult);
return rr;
} }
#endregion #endregion

Loading…
Cancel
Save