diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BinaryOperatorExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BinaryOperatorExpression.cs index 171e3e31c2..cef22fecd2 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BinaryOperatorExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BinaryOperatorExpression.cs @@ -128,11 +128,15 @@ namespace ICSharpCode.NRefactory.CSharp public enum BinaryOperatorType { + /// + /// Any binary operator (used in pattern matching) + /// + Any, + // We avoid 'logical or' on purpose, because it's not clear if that refers to the bitwise // or to the short-circuiting (conditional) operator: // MCS and old NRefactory used bitwise='|', logical='||' // but the C# spec uses logical='|', conditional='||' - /// left & right BitwiseAnd, /// left | right @@ -174,11 +178,6 @@ namespace ICSharpCode.NRefactory.CSharp ShiftRight, /// left ?? right - NullCoalescing, - - /// - /// Any binary operator (used in pattern matching) - /// - Any + NullCoalescing } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/UnaryOperatorExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/UnaryOperatorExpression.cs index 2cc7256d88..c99d4ea941 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/UnaryOperatorExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/UnaryOperatorExpression.cs @@ -1,6 +1,6 @@ // // UnaryOperatorExpression.cs -// +// // Author: // Mike Krüger // @@ -67,7 +67,8 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { UnaryOperatorExpression o = other as UnaryOperatorExpression; - return o != null && this.Operator == o.Operator && this.Expression.DoMatch(o.Expression, match); + return o != null && (this.Operator == UnaryOperatorType.Any || this.Operator == o.Operator) + && this.Expression.DoMatch(o.Expression, match); } public static string GetOperatorSymbol(UnaryOperatorType op) @@ -101,6 +102,11 @@ namespace ICSharpCode.NRefactory.CSharp public enum UnaryOperatorType { + /// + /// Any unary operator (used in pattern matching) + /// + Any, + /// Logical not (!a) Not, /// Bitwise not (~a) diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/Conversions.cs b/ICSharpCode.NRefactory/CSharp/Resolver/Conversions.cs index 5465213dcc..7c1ba5ba0b 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/Conversions.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/Conversions.cs @@ -86,16 +86,22 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public static Conversion UserDefinedImplicitConversion(IMethod operatorMethod, bool isLifted) { + if (operatorMethod == null) + throw new ArgumentNullException("operatorMethod"); return new Conversion(isLifted ? liftedUserDefinedImplicitConversionKind : userDefinedImplicitConversionKind, operatorMethod); } public static Conversion UserDefinedExplicitConversion(IMethod operatorMethod, bool isLifted) { + if (operatorMethod == null) + throw new ArgumentNullException("operatorMethod"); return new Conversion(isLifted ? liftedUserDefinedExplicitConversionKind : userDefinedExplicitConversionKind, operatorMethod); } public static Conversion MethodGroupConversion(IMethod chosenMethod) { + if (chosenMethod == null) + throw new ArgumentNullException("chosenMethod"); return new Conversion(methodGroupConversionKind, chosenMethod); } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/FindReferencedEntities.cs b/ICSharpCode.NRefactory/CSharp/Resolver/FindReferencedEntities.cs new file mode 100644 index 0000000000..e3c5d6e693 --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Resolver/FindReferencedEntities.cs @@ -0,0 +1,64 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.CSharp.Resolver +{ + /// + /// Find all entities that are referenced in the scanned AST. + /// + public sealed class FindReferencedEntities : IResolveVisitorNavigator + { + readonly Action referenceFound; + + public FindReferencedEntities(Action referenceFound) + { + if (referenceFound == null) + throw new ArgumentNullException("referenceFound"); + this.referenceFound = referenceFound; + } + + public ResolveVisitorNavigationMode Scan(AstNode node) + { + return ResolveVisitorNavigationMode.Resolve; + } + + public void Resolved(AstNode node, ResolveResult result) + { + MemberResolveResult mrr = result as MemberResolveResult; + if (mrr != null) { + referenceFound(node, mrr.Member); + } + TypeResolveResult trr = result as TypeResolveResult; + if (trr != null) { + ITypeDefinition typeDef = trr.Type.GetDefinition(); + if (typeDef != null) + referenceFound(node, typeDef); + } + } + + public void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType) + { + if (conversion.IsUserDefined || conversion.IsMethodGroupConversion) { + referenceFound(expression, conversion.Method); + } + } + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/Log.cs b/ICSharpCode.NRefactory/CSharp/Resolver/Log.cs index 11053b90df..c3d43c2f4d 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/Log.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/Log.cs @@ -35,7 +35,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// static class Log { - const bool logEnabled = true; + const bool logEnabled = false; [Conditional(logEnabled ? "DEBUG" : "LOG_DISABLED")] internal static void WriteLine(string text) diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs index 8b52443f19..edfaaa977b 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs @@ -359,6 +359,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// public ResolveResult GetResolveResult(AstNode node) { + if (IsUnresolvableNode(node)) + return null; + MergeUndecidedLambdas(); ResolveResult result; if (resolveResultCache.TryGetValue(node, out result)) @@ -385,6 +388,28 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return null; } + /// + /// Gets whether the specified node is unresolvable. + /// + public static bool IsUnresolvableNode(AstNode node) + { + return (node.NodeType == NodeType.Whitespace || node is ArraySpecifier || node is NamedArgumentExpression); + } + + /// + /// Gets the resolve result for the specified node. + /// If the node was not resolved by the navigator, this method will return null. + /// + public ResolveResult GetResolveResultIfResolved(AstNode node) + { + MergeUndecidedLambdas(); + ResolveResult result; + if (resolveResultCache.TryGetValue(node, out result)) + return result; + else + return null; + } + CSharpResolver GetPreviouslyScannedContext(AstNode node, out AstNode parent) { parent = node; @@ -577,7 +602,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (aie != null && arrayType != null) { StoreState(aie, resolver.Clone()); List initializerElements = new List(); - UnpackArrayInitializer(initializerElements, aie, arrayType.Dimensions); + UnpackArrayInitializer(initializerElements, aie, arrayType.Dimensions, true); ResolveResult[] initializerElementResults = new ResolveResult[initializerElements.Count]; for (int i = 0; i < initializerElementResults.Length; i++) { initializerElementResults[i] = Resolve(initializerElements[i]); @@ -916,11 +941,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver initializerElementResults = null; } else { initializerElements = new List(); - UnpackArrayInitializer(initializerElements, arrayCreateExpression.Initializer, dimensions); + UnpackArrayInitializer(initializerElements, arrayCreateExpression.Initializer, dimensions, true); initializerElementResults = new ResolveResult[initializerElements.Count]; for (int i = 0; i < initializerElementResults.Length; i++) { initializerElementResults[i] = Resolve(initializerElements[i]); } + StoreResult(arrayCreateExpression.Initializer, voidResult); } ArrayCreateResolveResult acrr; @@ -936,16 +962,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return acrr; } - void UnpackArrayInitializer(List elementList, ArrayInitializerExpression initializer, int dimensions) + void UnpackArrayInitializer(List elementList, ArrayInitializerExpression initializer, int dimensions, bool resolveNestedInitializesToVoid) { Debug.Assert(dimensions >= 1); if (dimensions > 1) { foreach (var node in initializer.Elements) { ArrayInitializerExpression aie = node as ArrayInitializerExpression; - if (aie != null) - UnpackArrayInitializer(elementList, aie, dimensions - 1); - else + if (aie != null) { + if (resolveNestedInitializesToVoid) + StoreResult(aie, voidResult); + UnpackArrayInitializer(elementList, aie, dimensions - 1, resolveNestedInitializesToVoid); + } else { elementList.Add(node); + } } } else { foreach (var expr in initializer.Elements) @@ -1215,6 +1244,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } resolver.PopInitializerType(); + StoreResult(initializer, voidResult); } ResolveResult IAstVisitor.VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data) @@ -1672,7 +1702,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver visitor.ResetContext( storedContext, delegate { + var oldNavigator = visitor.navigator; + visitor.navigator = new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Resolve, oldNavigator); visitor.AnalyzeLambda(body, out success, out isValidAsVoidMethod, out inferredReturnType, out returnExpressions, out returnValues); + visitor.navigator = oldNavigator; }); Log.Unindent(); Log.WriteLine("Finished analyzing " + this.LambdaExpression); @@ -1857,7 +1890,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (ok) return h; } - ResolveVisitor visitor = new ResolveVisitor(storedContext.Clone(), parsedFile); + var resolveAll = new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Resolve, null); + ResolveVisitor visitor = new ResolveVisitor(storedContext.Clone(), parsedFile, resolveAll); var newHypothesis = new LambdaTypeHypothesis(this, parameterTypes, visitor, lambda != null ? lambda.Parameters : null); hypotheses.Add(newHypothesis); return newHypothesis; @@ -2050,7 +2084,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver void MergeUndecidedLambdas() { - if (undecidedLambdas == null) + if (undecidedLambdas == null || undecidedLambdas.Count == 0) return; Log.WriteLine("MergeUndecidedLambdas()..."); Log.Indent(); @@ -2097,9 +2131,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver #region AnalyzeLambda void AnalyzeLambda(AstNode body, out bool success, out bool isValidAsVoidMethod, out IType inferredReturnType, out IList returnExpressions, out IList returnValues) { - var oldNavigator = this.navigator; - this.navigator = new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Resolve, oldNavigator); - Expression expr = body as Expression; if (expr != null) { isValidAsVoidMethod = ExpressionPermittedAsStatement(expr); @@ -2133,7 +2164,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver // TODO: check for compiler errors within the lambda body success = true; - this.navigator = oldNavigator; } static bool ExpressionPermittedAsStatement(Expression expr) @@ -2679,7 +2709,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } ResolveResult target; if (memberType.IsDoubleColon && memberType.Target is SimpleType) { - target = resolver.ResolveAlias(((SimpleType)memberType.Target).Identifier); + SimpleType t = (SimpleType)memberType.Target; + target = resolver.ResolveAlias(t.Identifier); + StoreResult(t, target); } else { target = Resolve(memberType.Target); } diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 5e1b57a98d..5d0087768b 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -102,6 +102,7 @@ +