diff --git a/NRefactory/.gitattributes b/NRefactory/.gitattributes
index 1a1533024..fbfb41be8 100644
--- a/NRefactory/.gitattributes
+++ b/NRefactory/.gitattributes
@@ -1,2 +1,3 @@
-*.sln -crlf
-*.csproj -crlf
\ No newline at end of file
+*.cs text diff=csharp
+*.sln text eol=crlf
+*.csproj text eol=crlf
diff --git a/NRefactory/.gitignore b/NRefactory/.gitignore
index 0031dcbe2..813e7d15c 100644
--- a/NRefactory/.gitignore
+++ b/NRefactory/.gitignore
@@ -1,5 +1,6 @@
bin
obj
+*.suo
/lib/*.dll
/ICSharpCode.NRefactory.Tests/PartCover/*
_ReSharper*/*
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp.AstVerifier/AssemblyInfo.cs b/NRefactory/ICSharpCode.NRefactory.CSharp.AstVerifier/AssemblyInfo.cs
deleted file mode 100644
index 7bd701bed..000000000
--- a/NRefactory/ICSharpCode.NRefactory.CSharp.AstVerifier/AssemblyInfo.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-
-// Information about this assembly is defined by the following attributes.
-// Change them to the values specific to your project.
-
-[assembly: AssemblyTitle("ICSharpCode.NRefactory.CSharp.AstVerifier")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("")]
-[assembly: AssemblyCopyright("mike")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
-// The form "{Major}.{Minor}.*" will automatically update the build and revision,
-// and "{Major}.{Minor}.{Build}.*" will update just the revision.
-
-[assembly: AssemblyVersion("1.0.*")]
-
-// The following attributes are used to specify the signing key for the assembly,
-// if desired. See the Mono documentation for more information about signing.
-
-//[assembly: AssemblyDelaySign(false)]
-//[assembly: AssemblyKeyFile("")]
-
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp.AstVerifier/ICSharpCode.NRefactory.CSharp.AstVerifier.csproj b/NRefactory/ICSharpCode.NRefactory.CSharp.AstVerifier/ICSharpCode.NRefactory.CSharp.AstVerifier.csproj
deleted file mode 100644
index 0647960a0..000000000
--- a/NRefactory/ICSharpCode.NRefactory.CSharp.AstVerifier/ICSharpCode.NRefactory.CSharp.AstVerifier.csproj
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
- Debug
- AnyCPU
- 10.0.0
- 2.0
- {961DADFA-7CE6-429F-BC22-47630D6DB826}
- Exe
- ICSharpCode.NRefactory.CSharp.AstVerifier
- AstVerifier
-
-
- true
- full
- false
- bin\Debug
- DEBUG;
- prompt
- 4
- true
-
-
- none
- false
- bin\Release
- prompt
- 4
- true
-
-
- true
- full
- false
- bin\Debug
- DEBUG;
- prompt
- 4
- true
- v4.5
-
-
- none
- false
- bin\Release
- prompt
- 4
- true
- v4.5
-
-
-
-
-
-
-
-
-
-
-
- {53DCA265-3C3C-42F9-B647-F72BA678122B}
- ICSharpCode.NRefactory.CSharp
-
-
- {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}
- ICSharpCode.NRefactory
-
-
-
\ No newline at end of file
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp.AstVerifier/Main.cs b/NRefactory/ICSharpCode.NRefactory.CSharp.AstVerifier/Main.cs
deleted file mode 100644
index 54ac57b80..000000000
--- a/NRefactory/ICSharpCode.NRefactory.CSharp.AstVerifier/Main.cs
+++ /dev/null
@@ -1,83 +0,0 @@
-using System;
-using System.IO;
-
-namespace ICSharpCode.NRefactory.CSharp.AstVerifier
-{
- class MainClass
- {
- static bool IsMatch (string src1, string src2, out int i, out int j)
- {
- i = 0;
- j = 0;
- while (i < src1.Length && j < src2.Length) {
- char c1 = src1 [i];
- char c2 = src2 [j];
- if (char.IsWhiteSpace (c1)) {
- i++;
- continue;
- }
- if (char.IsWhiteSpace (c2)) {
- j++;
- continue;
- }
- if (c1 != c2)
- return false;
- i++;
- j++;
- }
- while (i < src1.Length && char.IsWhiteSpace (src1[i])) {
- i++;
- }
- while (j < src2.Length && char.IsWhiteSpace (src2[j])) {
- j++;
- }
-
- return i == src1.Length && j == src2.Length;
- }
-
- public static void Main (string[] args)
- {
- if (args.Length == 0) {
- Console.WriteLine ("Usage: AstVerifier [-v|-verbose] [Directory]");
- return;
- }
- string directory = args[args.Length - 1];
- bool verboseOutput = args.Length > 1 && (args[0] == "-v" || args[0] == "-verbose");
-
- try {
- if (!Directory.Exists (directory)) {
- Console.WriteLine ("Directory not found.");
- return;
- }
- } catch (IOException) {
- Console.WriteLine ("Exception while trying to access the directory.");
- return;
- }
- int failed = 0, passed = 0;
- Console.WriteLine ("search in " + directory);
- foreach (var file in Directory.GetFileSystemEntries (directory, "*", SearchOption.AllDirectories)) {
- if (!file.EndsWith (".cs"))
- continue;
- string text = File.ReadAllText (file);
- var unit = SyntaxTree.Parse (text, file);
- if (unit == null)
- continue;
- string generated = unit.GetText ();
- int i, j;
- if (!IsMatch (text, generated, out i, out j)) {
- if (i > 0 && j > 0 && verboseOutput) {
- Console.WriteLine ("fail :" + file + "----original:");
- Console.WriteLine (text.Substring (0, Math.Min (text.Length, i + 1)));
- Console.WriteLine ("----generated:");
- Console.WriteLine (generated.Substring (0, Math.Min (generated.Length, j + 1)));
- }
- failed++;
- } else {
- passed++;
- }
- }
-
- Console.WriteLine ("{0} passed, {1} failed", passed, failed);
- }
- }
-}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/EmptyExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/AnnotationNames.cs
similarity index 50%
rename from NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/EmptyExpression.cs
rename to NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/AnnotationNames.cs
index 7dc5da777..94d19e4b6 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/EmptyExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/AnnotationNames.cs
@@ -1,10 +1,10 @@
-//
-// EmptyExpression.cs
+//
+// Annotations.cs
//
// Author:
-// Mike Krüger
+// Luís Reis
//
-// Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+// Copyright (c) 2013 Luís Reis
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,57 +23,26 @@
// 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;
namespace ICSharpCode.NRefactory.CSharp
{
- ///
- /// Type<[EMPTY]>
- ///
- public class EmptyExpression : Expression
+ public static class AnnotationNames
{
- TextLocation location;
+ //Used const instead of readonly to allow values to be used in switch cases.
- public override TextLocation StartLocation {
- get {
- return location;
- }
- }
-
- public override TextLocation EndLocation {
- get {
- return location;
- }
- }
+ public const string AssertionMethodAttribute = "JetBrains.Annotations.AssertionMethodAttribute";
+ public const string AssertionConditionAttribute = "JetBrains.Annotations.AssertionConditionAttribute";
+ public const string AssertionConditionTypeAttribute = "JetBrains.Annotations.AssertionConditionType";
- public EmptyExpression ()
- {
- }
+ public const string AssertionConditionTypeIsTrue = "JetBrains.Annotations.AssertionConditionType.IS_TRUE";
+ public const string AssertionConditionTypeIsFalse = "JetBrains.Annotations.AssertionConditionType.IS_FALSE";
+ public const string AssertionConditionTypeIsNull = "JetBrains.Annotations.AssertionConditionType.IS_NULL";
+ public const string AssertionConditionTypeIsNotNull = "JetBrains.Annotations.AssertionConditionType.IS_NOT_NULL";
- public EmptyExpression (TextLocation location)
- {
- this.location = location;
- }
-
- public override void AcceptVisitor (IAstVisitor visitor)
- {
- visitor.VisitEmptyExpression (this);
- }
-
- public override T AcceptVisitor (IAstVisitor visitor)
- {
- return visitor.VisitEmptyExpression (this);
- }
-
- public override S AcceptVisitor (IAstVisitor visitor, T data)
- {
- return visitor.VisitEmptyExpression (this, data);
- }
-
- protected internal override bool DoMatch (AstNode other, PatternMatching.Match match)
- {
- var o = other as EmptyExpression;
- return o != null;
- }
+ public const string NotNullAttribute = "JetBrains.Annotations.NotNullAttribute";
+ public const string CanBeNullAttribute = "JetBrains.Annotations.CanBeNullAttribute";
}
}
+
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs
index 21b452696..2d3895b1e 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs
@@ -1,4 +1,4 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
+// Copyright (c) 2010-2013 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
@@ -26,6 +26,7 @@ using ICSharpCode.NRefactory.CSharp.TypeSystem;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
+using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.CSharp.Analysis
{
@@ -248,6 +249,8 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
#region Create*Node
ControlFlowNode CreateStartNode(Statement statement)
{
+ if (statement.IsNull)
+ return null;
ControlFlowNode node = CreateNode(null, statement, ControlFlowNodeType.StartNode);
nodes.Add(node);
return node;
@@ -294,6 +297,8 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
/// The constant value of the expression; or null if the expression is not a constant.
ResolveResult EvaluateConstant(Expression expr)
{
+ if (expr.IsNull)
+ return null;
if (EvaluateOnlyPrimitiveConstants) {
if (!(expr is PrimitiveExpression || expr is NullReferenceExpression))
return null;
@@ -336,6 +341,8 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
internal ControlFlowEdge Connect(ControlFlowNode from, ControlFlowNode to, ControlFlowEdgeType type = ControlFlowEdgeType.Normal)
{
+ if (from == null || to == null)
+ return null;
ControlFlowEdge edge = builder.CreateEdge(from, to, type);
from.Outgoing.Add(edge);
to.Incoming.Add(edge);
@@ -354,8 +361,8 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
protected override ControlFlowNode VisitChildren(AstNode node, ControlFlowNode data)
{
- // We have overrides for all possible expressions and should visit expressions only.
- throw new NotImplementedException();
+ // We have overrides for all possible statements and should visit statements only.
+ throw new NotSupportedException();
}
public override ControlFlowNode VisitBlockStatement(BlockStatement blockStatement, ControlFlowNode data)
@@ -406,22 +413,20 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
public override ControlFlowNode VisitIfElseStatement(IfElseStatement ifElseStatement, ControlFlowNode data)
{
bool? cond = builder.EvaluateCondition(ifElseStatement.Condition);
+
ControlFlowNode trueBegin = builder.CreateStartNode(ifElseStatement.TrueStatement);
if (cond != false)
Connect(data, trueBegin, ControlFlowEdgeType.ConditionTrue);
ControlFlowNode trueEnd = ifElseStatement.TrueStatement.AcceptVisitor(this, trueBegin);
- ControlFlowNode falseEnd;
- if (ifElseStatement.FalseStatement.IsNull) {
- falseEnd = null;
- } else {
- ControlFlowNode falseBegin = builder.CreateStartNode(ifElseStatement.FalseStatement);
- if (cond != true)
- Connect(data, falseBegin, ControlFlowEdgeType.ConditionFalse);
- falseEnd = ifElseStatement.FalseStatement.AcceptVisitor(this, falseBegin);
- }
+
+ ControlFlowNode falseBegin = builder.CreateStartNode(ifElseStatement.FalseStatement);
+ if (cond != true)
+ Connect(data, falseBegin, ControlFlowEdgeType.ConditionFalse);
+ ControlFlowNode falseEnd = ifElseStatement.FalseStatement.AcceptVisitor(this, falseBegin);
+ // (if no else statement exists, both falseBegin and falseEnd will be null)
+
ControlFlowNode end = builder.CreateEndNode(ifElseStatement);
- if (trueEnd != null)
- Connect(trueEnd, end);
+ Connect(trueEnd, end);
if (falseEnd != null) {
Connect(falseEnd, end);
} else if (cond != true) {
@@ -599,8 +604,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
ControlFlowNode bodyStart = builder.CreateStartNode(forStatement.EmbeddedStatement);
ControlFlowNode bodyEnd = forStatement.EmbeddedStatement.AcceptVisitor(this, bodyStart);
- if (bodyEnd != null)
- Connect(bodyEnd, iteratorStart);
+ Connect(bodyEnd, iteratorStart);
breakTargets.Pop();
continueTargets.Pop();
@@ -743,5 +747,57 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
return CreateConnectedEndNode(fixedStatement, bodyEnd);
}
}
+
+ ///
+ /// Debugging helper that exports a control flow graph.
+ ///
+ public static GraphVizGraph ExportGraph(IList nodes)
+ {
+ GraphVizGraph g = new GraphVizGraph();
+ GraphVizNode[] n = new GraphVizNode[nodes.Count];
+ Dictionary dict = new Dictionary();
+ for (int i = 0; i < n.Length; i++) {
+ dict.Add(nodes[i], i);
+ n[i] = new GraphVizNode(i);
+ string name = "#" + i + " = ";
+ switch (nodes[i].Type) {
+ case ControlFlowNodeType.StartNode:
+ case ControlFlowNodeType.BetweenStatements:
+ name += nodes[i].NextStatement.DebugToString();
+ break;
+ case ControlFlowNodeType.EndNode:
+ name += "End of " + nodes[i].PreviousStatement.DebugToString();
+ break;
+ case ControlFlowNodeType.LoopCondition:
+ name += "Condition in " + nodes[i].NextStatement.DebugToString();
+ break;
+ default:
+ name += "?";
+ break;
+ }
+ n[i].label = name;
+ g.AddNode(n[i]);
+ }
+ for (int i = 0; i < n.Length; i++) {
+ foreach (ControlFlowEdge edge in nodes[i].Outgoing) {
+ GraphVizEdge ge = new GraphVizEdge(i, dict[edge.To]);
+ if (edge.IsLeavingTryFinally)
+ ge.style = "dashed";
+ switch (edge.Type) {
+ case ControlFlowEdgeType.ConditionTrue:
+ ge.color = "green";
+ break;
+ case ControlFlowEdgeType.ConditionFalse:
+ ge.color = "red";
+ break;
+ case ControlFlowEdgeType.Jump:
+ ge.color = "blue";
+ break;
+ }
+ g.AddEdge(ge);
+ }
+ }
+ return g;
+ }
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/DeclarationSpace/LocalDeclarationSpace.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/DeclarationSpace/LocalDeclarationSpace.cs
new file mode 100644
index 000000000..a412cba3a
--- /dev/null
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/DeclarationSpace/LocalDeclarationSpace.cs
@@ -0,0 +1,157 @@
+//
+// LovalVariableDeclarationSpace.cs
+//
+// Author:
+// Simon Lindgren
+//
+// Copyright (c) 2013 Simon Lindgren
+//
+// 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 ICSharpCode.NRefactory.Utils;
+using System.Collections.Generic;
+using System.Linq;
+using System;
+
+namespace ICSharpCode.NRefactory.CSharp.Analysis
+{
+ ///
+ /// Represents a declaration space. (§3.3)
+ ///
+ public class LocalDeclarationSpace
+ {
+ ///
+ /// Maps from variable name to the declarations in this declaration space.
+ ///
+ ///
+ /// This maps from variable name
+ ///
+ MultiDictionary declarations = new MultiDictionary ();
+
+ public LocalDeclarationSpace()
+ {
+ Children = new List ();
+ }
+
+ ///
+ /// The child declaration spaces.
+ ///
+ public IList Children {
+ get;
+ private set;
+ }
+
+ ///
+ /// The parent declaration space.
+ ///
+ /// The parent.
+ public LocalDeclarationSpace Parent {
+ get;
+ private set;
+ }
+
+ ///
+ /// The names declared in this declaration space, excluding child spaces.
+ ///
+ /// The declared names.
+ public ICollection DeclaredNames {
+ get {
+ return declarations.Keys;
+ }
+ }
+
+ ///
+ /// Get all nodes declaring the name specified in .
+ ///
+ /// The declaring nodes.
+ /// The declaration name.
+ public IEnumerable GetNameDeclarations(string name)
+ {
+ return declarations [name].Concat(Children.SelectMany(child => child.GetNameDeclarations(name)));
+ }
+
+ ///
+ /// Adds a child declaration space.
+ ///
+ /// The to add.
+ public void AddChildSpace(LocalDeclarationSpace child)
+ {
+ if (child == null)
+ throw new ArgumentNullException("child");
+ if (Children.Contains(child))
+ throw new InvalidOperationException("the child was already added");
+
+ Children.Add(child);
+ child.Parent = this;
+ }
+
+ ///
+ /// Adds a new declaration to the declaration space.
+ ///
+ /// The name of the declared variable.
+ /// A node associated with the declaration.
+ public void AddDeclaration(string name, AstNode node)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+ if (node == null)
+ throw new ArgumentNullException("node");
+ declarations.Add(name, node);
+ }
+
+ ///
+ /// Determines if the name exists in the this declaration space.
+ ///
+ /// true, if the name specified in is used in this variable declaration space, false otherwise.
+ /// The name to look for.
+ /// When true, child declaration spaces are included in the search.
+ public bool ContainsName(string name, bool includeChildren)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+
+ if (declarations.Keys.Contains(name))
+ return true;
+ return includeChildren && Children.Any(child => child.ContainsName(name, true));
+ }
+
+ ///
+ /// Determines whether the name specified in is used in surrouding code.
+ ///
+ /// true if the name is used, false otherwise.
+ /// The name to check.
+ ///
+ /// Contrary to , this method also checks parent declaration spaces
+ /// for name conflicts. Typically, this will be the right method to use when determining if a name can be used.
+ ///
+ public bool IsNameUsed(string name)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+
+ return IsNameUsedBySelfOrParent(name) || Children.Any(child => child.ContainsName(name, true));
+ }
+
+ bool IsNameUsedBySelfOrParent(string name)
+ {
+ if (declarations.Keys.Contains(name))
+ return true;
+ return Parent != null && Parent.IsNameUsedBySelfOrParent(name);
+ }
+ }
+}
\ No newline at end of file
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/DeclarationSpace/LocalDeclarationSpaceVisitor.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/DeclarationSpace/LocalDeclarationSpaceVisitor.cs
new file mode 100644
index 000000000..08389a413
--- /dev/null
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/DeclarationSpace/LocalDeclarationSpaceVisitor.cs
@@ -0,0 +1,138 @@
+//
+// LocalDeclarationSpaceVisitor.cs
+//
+// Author:
+// Simon Lindgren
+//
+// Copyright (c) 2013 Simon Lindgren
+//
+// 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 System.Collections.Generic;
+
+namespace ICSharpCode.NRefactory.CSharp.Analysis
+{
+ public class LocalDeclarationSpaceVisitor : DepthFirstAstVisitor
+ {
+ LocalDeclarationSpace currentDeclarationSpace;
+ Dictionary nodeDeclarationSpaces = new Dictionary();
+
+ public LocalDeclarationSpace GetDeclarationSpace(AstNode node)
+ {
+ if (node == null)
+ throw new ArgumentNullException("node");
+ while (node != null) {
+ LocalDeclarationSpace declarationSpace;
+ if (nodeDeclarationSpaces.TryGetValue(node, out declarationSpace))
+ return declarationSpace;
+ node = node.Parent;
+ }
+ return null;
+ }
+
+ #region Visitor
+
+ void AddDeclaration(string name, AstNode node)
+ {
+ if (currentDeclarationSpace != null)
+ currentDeclarationSpace.AddDeclaration(name, node);
+ }
+
+ public override void VisitVariableInitializer(VariableInitializer variableInitializer)
+ {
+ AddDeclaration(variableInitializer.Name, variableInitializer);
+ base.VisitVariableInitializer(variableInitializer);
+ }
+
+ public override void VisitParameterDeclaration(ParameterDeclaration parameterDeclaration)
+ {
+ AddDeclaration(parameterDeclaration.Name, parameterDeclaration);
+ base.VisitParameterDeclaration(parameterDeclaration);
+ }
+
+ void VisitNewDeclarationSpace(AstNode node)
+ {
+ var oldDeclarationSpace = currentDeclarationSpace;
+ currentDeclarationSpace = new LocalDeclarationSpace();
+ if (oldDeclarationSpace != null)
+ oldDeclarationSpace.AddChildSpace(currentDeclarationSpace);
+
+ VisitChildren(node);
+
+ nodeDeclarationSpaces.Add(node, currentDeclarationSpace);
+ currentDeclarationSpace = oldDeclarationSpace;
+ }
+
+ #region Declaration space creating nodes
+
+ public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration)
+ {
+ VisitNewDeclarationSpace(methodDeclaration);
+ }
+
+ public override void VisitBlockStatement(BlockStatement blockStatement)
+ {
+ VisitNewDeclarationSpace(blockStatement);
+ }
+
+ public override void VisitSwitchStatement(SwitchStatement switchStatement)
+ {
+ VisitNewDeclarationSpace(switchStatement);
+ }
+
+ public override void VisitForeachStatement(ForeachStatement foreachStatement)
+ {
+ AddDeclaration(foreachStatement.VariableName, foreachStatement);
+ VisitNewDeclarationSpace(foreachStatement);
+ }
+
+ public override void VisitForStatement(ForStatement forStatement)
+ {
+ VisitNewDeclarationSpace(forStatement);
+ }
+
+ public override void VisitUsingStatement(UsingStatement usingStatement)
+ {
+ VisitNewDeclarationSpace(usingStatement);
+ }
+
+ public override void VisitLambdaExpression(LambdaExpression lambdaExpression)
+ {
+ VisitNewDeclarationSpace(lambdaExpression);
+ }
+
+ public override void VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression)
+ {
+ VisitNewDeclarationSpace(anonymousMethodExpression);
+ }
+
+ public override void VisitEventDeclaration(EventDeclaration eventDeclaration)
+ {
+ AddDeclaration(eventDeclaration.Name, eventDeclaration);
+ }
+
+ public override void VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration)
+ {
+ VisitNewDeclarationSpace(eventDeclaration);
+ }
+
+ #endregion
+ #endregion
+ }
+}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/DefiniteAssignmentAnalysis.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/DefiniteAssignmentAnalysis.cs
index 0e2ad2b89..9b33e74a7 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/DefiniteAssignmentAnalysis.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/DefiniteAssignmentAnalysis.cs
@@ -1,4 +1,4 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
+// Copyright (c) 2010-2013 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
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/NullValueAnalysis.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/NullValueAnalysis.cs
new file mode 100644
index 000000000..a20b4a0f0
--- /dev/null
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/NullValueAnalysis.cs
@@ -0,0 +1,2215 @@
+//
+// NullValueAnalysis.cs
+//
+// Author:
+// Luís Reis
+//
+// Copyright (c) 2013 Luís Reis
+//
+// 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 System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.Text;
+using ICSharpCode.NRefactory.CSharp.Resolver;
+using ICSharpCode.NRefactory.Semantics;
+using ICSharpCode.NRefactory.TypeSystem;
+using ICSharpCode.NRefactory.CSharp.Refactoring;
+using ICSharpCode.NRefactory.PatternMatching;
+using ICSharpCode.NRefactory.CSharp;
+using ICSharpCode.NRefactory.Utils;
+
+namespace ICSharpCode.NRefactory.CSharp.Analysis
+{
+ public class NullValueAnalysis
+ {
+ sealed class VariableStatusInfo : IEquatable, IEnumerable>
+ {
+ readonly Dictionary VariableStatus = new Dictionary();
+
+ public NullValueStatus this[string name]
+ {
+ get {
+ NullValueStatus status;
+ if (VariableStatus.TryGetValue(name, out status)) {
+ return status;
+ }
+ return NullValueStatus.UnreachableOrInexistent;
+ }
+ set {
+ if (value == NullValueStatus.UnreachableOrInexistent) {
+ VariableStatus.Remove(name);
+ } else {
+ VariableStatus [name] = value;
+ }
+ }
+ }
+
+ ///
+ /// Modifies the variable state to consider a new incoming path
+ ///
+ /// true, if the state has changed, false otherwise.
+ /// The variable state of the incoming path
+ public bool ReceiveIncoming(VariableStatusInfo incomingState)
+ {
+ bool changed = false;
+ var listOfVariables = VariableStatus.Keys.Concat(incomingState.VariableStatus.Keys).ToList();
+ foreach (string variable in listOfVariables)
+ {
+ var newValue = CombineStatus(this [variable], incomingState [variable]);
+ if (this [variable] != newValue) {
+ this [variable] = newValue;
+ changed = true;
+ }
+ }
+
+ return changed;
+ }
+
+ public static NullValueStatus CombineStatus(NullValueStatus oldValue, NullValueStatus incomingValue)
+ {
+ if (oldValue == NullValueStatus.Error || incomingValue == NullValueStatus.Error)
+ return NullValueStatus.Error;
+
+ if (oldValue == NullValueStatus.UnreachableOrInexistent ||
+ oldValue == NullValueStatus.Unassigned)
+ return incomingValue;
+
+ if (incomingValue == NullValueStatus.Unassigned) {
+ return NullValueStatus.Unassigned;
+ }
+
+ if (oldValue == NullValueStatus.CapturedUnknown || incomingValue == NullValueStatus.CapturedUnknown) {
+ //TODO: Check if this is right
+ return NullValueStatus.CapturedUnknown;
+ }
+
+ if (oldValue == NullValueStatus.Unknown) {
+ return NullValueStatus.Unknown;
+ }
+
+ if (oldValue == NullValueStatus.DefinitelyNull) {
+ return incomingValue == NullValueStatus.DefinitelyNull ?
+ NullValueStatus.DefinitelyNull : NullValueStatus.PotentiallyNull;
+ }
+
+ if (oldValue == NullValueStatus.DefinitelyNotNull) {
+ if (incomingValue == NullValueStatus.Unknown)
+ return NullValueStatus.Unknown;
+ if (incomingValue == NullValueStatus.DefinitelyNotNull)
+ return NullValueStatus.DefinitelyNotNull;
+ return NullValueStatus.PotentiallyNull;
+ }
+
+ Debug.Assert(oldValue == NullValueStatus.PotentiallyNull);
+ return NullValueStatus.PotentiallyNull;
+ }
+
+ public bool HasVariable(string variable) {
+ return VariableStatus.ContainsKey(variable);
+ }
+
+ public VariableStatusInfo Clone() {
+ var clone = new VariableStatusInfo();
+ foreach (var item in VariableStatus) {
+ clone.VariableStatus.Add(item.Key, item.Value);
+ }
+ return clone;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as VariableStatusInfo);
+ }
+
+ public bool Equals(VariableStatusInfo obj)
+ {
+ if (obj == null) {
+ return false;
+ }
+
+ if (VariableStatus.Count != obj.VariableStatus.Count)
+ return false;
+
+ return VariableStatus.All(item => item.Value == obj[item.Key]);
+ }
+
+ public override int GetHashCode()
+ {
+ //STUB
+ return VariableStatus.Count.GetHashCode();
+ }
+
+ public static bool operator ==(VariableStatusInfo obj1, VariableStatusInfo obj2) {
+ return object.ReferenceEquals(obj1, null) ?
+ object.ReferenceEquals(obj2, null) : obj1.Equals(obj2);
+ }
+
+ public static bool operator !=(VariableStatusInfo obj1, VariableStatusInfo obj2) {
+ return !(obj1 == obj2);
+ }
+
+ public IEnumerator> GetEnumerator()
+ {
+ return VariableStatus.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ public override string ToString()
+ {
+ var builder = new StringBuilder("[");
+ foreach (var item in this) {
+ builder.Append(item.Key);
+ builder.Append("=");
+ builder.Append(item.Value);
+ }
+ builder.Append("]");
+ return builder.ToString();
+ }
+ }
+
+ sealed class NullAnalysisNode : ControlFlowNode
+ {
+ public readonly VariableStatusInfo VariableState = new VariableStatusInfo();
+ public bool Visited { get; private set; }
+
+ public NullAnalysisNode(Statement previousStatement, Statement nextStatement, ControlFlowNodeType type)
+ : base(previousStatement, nextStatement, type)
+ {
+ }
+
+ public bool ReceiveIncoming(VariableStatusInfo incomingState)
+ {
+ bool changed = VariableState.ReceiveIncoming(incomingState);
+ if (!Visited) {
+ Visited = true;
+ return true;
+ }
+ return changed;
+ }
+ }
+
+ sealed class NullAnalysisGraphBuilder : ControlFlowGraphBuilder
+ {
+ protected override ControlFlowNode CreateNode(Statement previousStatement, Statement nextStatement, ControlFlowNodeType type)
+ {
+ return new NullAnalysisNode(previousStatement, nextStatement, type);
+ }
+ }
+
+ class PendingNode : IEquatable {
+ internal readonly NullAnalysisNode nodeToVisit;
+ internal readonly VariableStatusInfo statusInfo;
+ internal readonly ComparableList pendingTryFinallyNodes;
+ internal readonly NullAnalysisNode nodeAfterFinally;
+
+ internal PendingNode(NullAnalysisNode nodeToVisit, VariableStatusInfo statusInfo)
+ : this(nodeToVisit, statusInfo, new ComparableList(), null)
+ {
+ }
+
+ public PendingNode(NullAnalysisNode nodeToVisit, VariableStatusInfo statusInfo, ComparableList pendingFinallyNodes, NullAnalysisNode nodeAfterFinally)
+ {
+ this.nodeToVisit = nodeToVisit;
+ this.statusInfo = statusInfo;
+ this.pendingTryFinallyNodes = pendingFinallyNodes;
+ this.nodeAfterFinally = nodeAfterFinally;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as PendingNode);
+ }
+
+ public bool Equals(PendingNode obj) {
+ if (obj == null) return false;
+
+ if (nodeToVisit != obj.nodeToVisit) return false;
+ if (statusInfo != obj.statusInfo) return false;
+ if (pendingTryFinallyNodes != obj.pendingTryFinallyNodes) return false;
+ if (nodeAfterFinally != obj.nodeAfterFinally) return false;
+
+ return true;
+ }
+
+ public override int GetHashCode()
+ {
+ return nodeToVisit.GetHashCode() ^
+ statusInfo.GetHashCode() ^
+ pendingTryFinallyNodes.GetHashCode() ^
+ (nodeAfterFinally == null ? 0 : nodeAfterFinally.GetHashCode());
+ }
+ }
+
+ readonly BaseRefactoringContext context;
+ readonly NullAnalysisVisitor visitor;
+ List allNodes;
+ readonly HashSet nodesToVisit = new HashSet();
+ Dictionary nodeBeforeStatementDict;
+ Dictionary nodeAfterStatementDict;
+ readonly Dictionary expressionResult = new Dictionary();
+
+ public NullValueAnalysis(BaseRefactoringContext context, MethodDeclaration methodDeclaration, CancellationToken cancellationToken)
+ : this(context, methodDeclaration.Body, methodDeclaration.Parameters, cancellationToken)
+ {
+ }
+
+ readonly IEnumerable parameters;
+ readonly Statement rootStatement;
+
+ readonly CancellationToken cancellationToken;
+
+ public NullValueAnalysis(BaseRefactoringContext context, Statement rootStatement, IEnumerable parameters, CancellationToken cancellationToken)
+ {
+ if (rootStatement == null)
+ throw new ArgumentNullException("rootStatement");
+ if (context == null)
+ throw new ArgumentNullException("context");
+
+ this.context = context;
+ this.rootStatement = rootStatement;
+ this.parameters = parameters;
+ this.visitor = new NullAnalysisVisitor(this);
+ this.cancellationToken = cancellationToken;
+ }
+
+ ///
+ /// Sets the local variable value.
+ /// This method does not change anything if identifier does not refer to a local variable.
+ /// Do not use this in variable declarations since resolving the variable won't work yet.
+ ///
+ /// true, if local variable value was set, false otherwise.
+ /// The variable status data to change.
+ /// The identifier to set.
+ /// The name of the identifier to set.
+ /// The value to set the identifier.
+ bool SetLocalVariableValue (VariableStatusInfo data, AstNode identifierNode, string identifierName, NullValueStatus value) {
+ var resolveResult = context.Resolve(identifierNode);
+ if (resolveResult is LocalResolveResult) {
+ if (data [identifierName] != NullValueStatus.CapturedUnknown) {
+ data [identifierName] = value;
+
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool SetLocalVariableValue (VariableStatusInfo data, IdentifierExpression identifierExpression, NullValueStatus value) {
+ return SetLocalVariableValue(data, identifierExpression, identifierExpression.Identifier, value);
+ }
+
+ bool SetLocalVariableValue (VariableStatusInfo data, Identifier identifier, NullValueStatus value) {
+ return SetLocalVariableValue(data, identifier, identifier.Name, value);
+ }
+
+ void SetupNode(NullAnalysisNode node)
+ {
+ foreach (var parameter in parameters) {
+ var resolveResult = context.Resolve(parameter.Type);
+ node.VariableState[parameter.Name] = GetInitialVariableStatus(resolveResult);
+ }
+
+ nodesToVisit.Add(new PendingNode(node, node.VariableState));
+ }
+
+ static bool IsTypeNullable(IType type)
+ {
+ return type.IsReferenceType == true || type.FullName == "System.Nullable";
+ }
+
+ public bool IsParametersAreUninitialized {
+ get;
+ set;
+ }
+
+ NullValueStatus GetInitialVariableStatus(ResolveResult resolveResult)
+ {
+ var typeResolveResult = resolveResult as TypeResolveResult;
+ if (typeResolveResult == null) {
+ return NullValueStatus.Error;
+ }
+ var type = typeResolveResult.Type;
+ if (type.IsReferenceType == null) {
+ return NullValueStatus.Error;
+ }
+ if (!IsParametersAreUninitialized)
+ return NullValueStatus.DefinitelyNotNull;
+ return IsTypeNullable(type) ? NullValueStatus.PotentiallyNull : NullValueStatus.DefinitelyNotNull;
+ }
+
+ public void Analyze()
+ {
+ var cfgBuilder = new NullAnalysisGraphBuilder();
+ allNodes = cfgBuilder.BuildControlFlowGraph(rootStatement, cancellationToken).Cast().ToList();
+ nodeBeforeStatementDict = allNodes.Where(node => node.Type == ControlFlowNodeType.StartNode || node.Type == ControlFlowNodeType.BetweenStatements)
+ .ToDictionary(node => node.NextStatement);
+ nodeAfterStatementDict = allNodes.Where(node => node.Type == ControlFlowNodeType.BetweenStatements || node.Type == ControlFlowNodeType.EndNode)
+ .ToDictionary(node => node.PreviousStatement);
+
+ foreach (var node in allNodes) {
+ if (node.Type == ControlFlowNodeType.StartNode && node.NextStatement == rootStatement) {
+ Debug.Assert(!nodesToVisit.Any());
+
+ SetupNode(node);
+ }
+ }
+
+ while (nodesToVisit.Any()) {
+ var nodeToVisit = nodesToVisit.First();
+ nodesToVisit.Remove(nodeToVisit);
+
+ Visit(nodeToVisit);
+ }
+ }
+
+ int visits = 0;
+
+ public int NodeVisits
+ {
+ get {
+ return visits;
+ }
+ }
+
+ void Visit(PendingNode nodeInfo)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var node = nodeInfo.nodeToVisit;
+ var statusInfo = nodeInfo.statusInfo;
+
+ visits++;
+ if (visits > 100) {
+ //Visiting way too often, let's enter fast mode
+ //Fast mode is slighly less accurate but visits each node less times
+ nodesToVisit.RemoveWhere(candidate => candidate.nodeToVisit == nodeInfo.nodeToVisit &&
+ candidate.pendingTryFinallyNodes.Equals(nodeInfo.pendingTryFinallyNodes) &&
+ candidate.nodeAfterFinally == nodeInfo.nodeAfterFinally);
+ statusInfo = node.VariableState;
+ }
+
+ var nextStatement = node.NextStatement;
+ VariableStatusInfo outgoingStatusInfo = statusInfo;
+ VisitorResult result = null;
+
+ if (nextStatement != null && (!(nextStatement is DoWhileStatement) || node.Type == ControlFlowNodeType.LoopCondition)) {
+ result = nextStatement.AcceptVisitor(visitor, statusInfo);
+ if (result == null) {
+ Console.WriteLine("Failure in {0}", nextStatement);
+ throw new InvalidOperationException();
+ }
+
+ outgoingStatusInfo = result.Variables;
+ }
+
+ if ((result == null || !result.ThrowsException) && node.Outgoing.Any()) {
+ var tryFinallyStatement = nextStatement as TryCatchStatement;
+
+ foreach (var outgoingEdge in node.Outgoing) {
+ VariableStatusInfo edgeInfo;
+ edgeInfo = outgoingStatusInfo.Clone();
+
+ if (node.Type == ControlFlowNodeType.EndNode) {
+ var previousBlock = node.PreviousStatement as BlockStatement;
+ if (previousBlock != null) {
+ //We're leaving a block statement.
+ //As such, we'll remove the variables that were declared *in* the loop
+ //This helps GetVariableStatusAfter/BeforeStatement be more accurate
+ //and prevents some redundant revisiting.
+
+ foreach (var variableInitializer in previousBlock.Statements
+ .OfType()
+ .SelectMany(declaration => declaration.Variables)) {
+
+ edgeInfo [variableInitializer.Name] = NullValueStatus.UnreachableOrInexistent;
+ }
+ }
+ }
+
+ if (tryFinallyStatement != null) {
+ //With the exception of try statements, this needs special handling:
+ //we'll set all changed variables to Unknown or CapturedUnknown
+ if (outgoingEdge.To.NextStatement == tryFinallyStatement.FinallyBlock) {
+ foreach (var identifierExpression in tryFinallyStatement.TryBlock.Descendants.OfType()) {
+ //TODO: Investigate CaptureUnknown
+ SetLocalVariableValue(edgeInfo, identifierExpression, NullValueStatus.Unknown);
+ }
+ } else {
+ var clause = tryFinallyStatement.CatchClauses
+ .FirstOrDefault(candidateClause => candidateClause.Body == outgoingEdge.To.NextStatement);
+
+ if (clause != null) {
+ SetLocalVariableValue(edgeInfo, clause.VariableNameToken, NullValueStatus.DefinitelyNotNull);
+
+ foreach (var identifierExpression in tryFinallyStatement.TryBlock.Descendants.OfType()) {
+ //TODO: Investigate CaptureUnknown
+ SetLocalVariableValue(edgeInfo, identifierExpression, NullValueStatus.Unknown);
+ }
+ }
+ }
+ }
+
+ if (result != null) {
+ switch (outgoingEdge.Type) {
+ case ControlFlowEdgeType.ConditionTrue:
+ if (result.KnownBoolResult == false) {
+ //No need to explore this path -- expression is known to be false
+ continue;
+ }
+ edgeInfo = result.TruePathVariables;
+ break;
+ case ControlFlowEdgeType.ConditionFalse:
+ if (result.KnownBoolResult == true) {
+ //No need to explore this path -- expression is known to be true
+ continue;
+ }
+ edgeInfo = result.FalsePathVariables;
+ break;
+ }
+ }
+
+ if (outgoingEdge.IsLeavingTryFinally) {
+ var nodeAfterFinally = (NullAnalysisNode)outgoingEdge.To;
+ var finallyNodes = outgoingEdge.TryFinallyStatements.Select(tryFinally => nodeBeforeStatementDict [tryFinally.FinallyBlock]).ToList();
+ var nextNode = finallyNodes.First();
+ var remainingFinallyNodes = new ComparableList(finallyNodes.Skip(1));
+ //We have to visit the node even if ReceiveIncoming returns false
+ //since the finallyNodes/nodeAfterFinally might be different even if the values of variables are the same -- and they need to be visited either way!
+ //TODO 1: Is there any point in visiting the finally statement here?
+ //TODO 2: Do we need the ReceiveIncoming at all?
+ nextNode.ReceiveIncoming(edgeInfo);
+ nodesToVisit.Add(new PendingNode(nextNode, edgeInfo, remainingFinallyNodes, nodeAfterFinally));
+ } else {
+ var outgoingNode = (NullAnalysisNode)outgoingEdge.To;
+ if (outgoingNode.ReceiveIncoming(edgeInfo)) {
+ nodesToVisit.Add(new PendingNode(outgoingNode, edgeInfo));
+ }
+ }
+ }
+ } else {
+ //We found a return/throw/yield break or some other termination node
+ var finallyBlockStarts = nodeInfo.pendingTryFinallyNodes;
+ var nodeAfterFinally = nodeInfo.nodeAfterFinally;
+
+ if (finallyBlockStarts.Any()) {
+ var nextNode = finallyBlockStarts.First();
+ if (nextNode.ReceiveIncoming(outgoingStatusInfo))
+ nodesToVisit.Add(new PendingNode(nextNode, outgoingStatusInfo, new ComparableList(finallyBlockStarts.Skip(1)), nodeInfo.nodeAfterFinally));
+ } else if (nodeAfterFinally != null && nodeAfterFinally.ReceiveIncoming(outgoingStatusInfo)) {
+ nodesToVisit.Add(new PendingNode(nodeAfterFinally, outgoingStatusInfo));
+ } else {
+ //Maybe we finished a try/catch/finally statement the "normal" way (no direct jumps)
+ //so let's check that case
+ var statement = node.PreviousStatement ?? node.NextStatement;
+ Debug.Assert(statement != null);
+ var parent = statement.GetParent();
+ var parentTryCatch = parent as TryCatchStatement;
+ if (parentTryCatch != null) {
+ var nextNode = nodeAfterStatementDict [parentTryCatch];
+ if (nextNode.ReceiveIncoming(outgoingStatusInfo)) {
+ nodesToVisit.Add(new PendingNode(nextNode, outgoingStatusInfo));
+ }
+ }
+ }
+ }
+ }
+
+ public NullValueStatus GetExpressionResult(Expression expr)
+ {
+ if (expr == null)
+ throw new ArgumentNullException("expr");
+
+ NullValueStatus info;
+ if (expressionResult.TryGetValue(expr, out info)) {
+ return info;
+ }
+
+ return NullValueStatus.UnreachableOrInexistent;
+ }
+
+ public NullValueStatus GetVariableStatusBeforeStatement(Statement stmt, string variableName)
+ {
+ if (stmt == null)
+ throw new ArgumentNullException("stmt");
+ if (variableName == null)
+ throw new ArgumentNullException("variableName");
+
+ NullAnalysisNode node;
+ if (nodeBeforeStatementDict.TryGetValue(stmt, out node)) {
+ return node.VariableState [variableName];
+ }
+
+ return NullValueStatus.UnreachableOrInexistent;
+ }
+
+ public NullValueStatus GetVariableStatusAfterStatement(Statement stmt, string variableName)
+ {
+ if (stmt == null)
+ throw new ArgumentNullException("stmt");
+ if (variableName == null)
+ throw new ArgumentNullException("variableName");
+
+ NullAnalysisNode node;
+ if (nodeAfterStatementDict.TryGetValue(stmt, out node)) {
+ return node.VariableState [variableName];
+ }
+
+ return NullValueStatus.UnreachableOrInexistent;
+ }
+
+ class ConditionalBranchInfo
+ {
+ ///
+ /// True if the variable is null for the true path, false if it is false for the true path.
+ ///
+ public Dictionary TrueResultVariableNullStates = new Dictionary();
+ ///
+ /// True if the variable is null for the false path, false if it is false for the false path.
+ ///
+ public Dictionary FalseResultVariableNullStates = new Dictionary();
+ }
+
+ class VisitorResult
+ {
+ ///
+ /// Indicates the return value of the expression.
+ ///
+ ///
+ /// Only applicable for expressions.
+ ///
+ public NullValueStatus NullableReturnResult;
+
+ ///
+ /// Indicates the value of each item in an array or linq query.
+ ///
+ public NullValueStatus EnumeratedValueResult;
+
+ ///
+ /// Information that indicates the restrictions to add
+ /// when branching.
+ ///
+ ///
+ /// Used in if/else statements, conditional expressions and
+ /// while statements.
+ ///
+ public ConditionalBranchInfo ConditionalBranchInfo;
+
+ ///
+ /// The state of the variables after the expression is executed.
+ ///
+ public VariableStatusInfo Variables;
+
+ ///
+ /// The expression is known to be invalid and trigger an error
+ /// (e.g. a NullReferenceException)
+ ///
+ public bool ThrowsException;
+
+ ///
+ /// The known bool result of an expression.
+ ///
+ public bool? KnownBoolResult;
+
+ public static VisitorResult ForEnumeratedValue(VariableStatusInfo variables, NullValueStatus itemValues)
+ {
+ var result = new VisitorResult();
+ result.NullableReturnResult = NullValueStatus.DefinitelyNotNull;
+ result.EnumeratedValueResult = itemValues;
+ result.Variables = variables.Clone();
+ return result;
+ }
+
+ public static VisitorResult ForValue(VariableStatusInfo variables, NullValueStatus returnValue)
+ {
+ var result = new VisitorResult();
+ result.NullableReturnResult = returnValue;
+ result.Variables = variables.Clone();
+ return result;
+ }
+
+ public static VisitorResult ForBoolValue(VariableStatusInfo variables, bool newValue)
+ {
+ var result = new VisitorResult();
+ result.NullableReturnResult = NullValueStatus.DefinitelyNotNull; //Bool expressions are never null
+ result.KnownBoolResult = newValue;
+ result.Variables = variables.Clone();
+ return result;
+ }
+
+ public static VisitorResult ForException(VariableStatusInfo variables) {
+ var result = new VisitorResult();
+ result.NullableReturnResult = NullValueStatus.UnreachableOrInexistent;
+ result.ThrowsException = true;
+ result.Variables = variables.Clone();
+ return result;
+ }
+
+ public VisitorResult Negated {
+ get {
+ var result = new VisitorResult();
+ if (NullableReturnResult.IsDefiniteValue()) {
+ result.NullableReturnResult = NullableReturnResult == NullValueStatus.DefinitelyNull
+ ? NullValueStatus.DefinitelyNotNull : NullValueStatus.DefinitelyNull;
+ } else {
+ result.NullableReturnResult = NullableReturnResult;
+ }
+ result.Variables = Variables.Clone();
+ result.KnownBoolResult = !KnownBoolResult;
+ if (ConditionalBranchInfo != null) {
+ result.ConditionalBranchInfo = new ConditionalBranchInfo();
+ foreach (var item in ConditionalBranchInfo.TrueResultVariableNullStates) {
+ result.ConditionalBranchInfo.FalseResultVariableNullStates [item.Key] = item.Value;
+ }
+ foreach (var item in ConditionalBranchInfo.FalseResultVariableNullStates) {
+ result.ConditionalBranchInfo.TrueResultVariableNullStates [item.Key] = item.Value;
+ }
+ }
+ return result;
+ }
+ }
+
+ public VariableStatusInfo TruePathVariables {
+ get {
+ var variables = Variables.Clone();
+ if (ConditionalBranchInfo != null) {
+ foreach (var item in ConditionalBranchInfo.TrueResultVariableNullStates) {
+ variables [item.Key] = item.Value ? NullValueStatus.DefinitelyNull : NullValueStatus.DefinitelyNotNull;
+ }
+ }
+ return variables;
+ }
+ }
+
+ public VariableStatusInfo FalsePathVariables {
+ get {
+ var variables = Variables.Clone();
+ if (ConditionalBranchInfo != null) {
+ foreach (var item in ConditionalBranchInfo.FalseResultVariableNullStates) {
+ variables [item.Key] = item.Value ? NullValueStatus.DefinitelyNull : NullValueStatus.DefinitelyNotNull;
+ }
+ }
+ return variables;
+ }
+ }
+
+ public static VisitorResult AndOperation(VisitorResult tentativeLeftResult, VisitorResult tentativeRightResult)
+ {
+ var result = new VisitorResult();
+ result.KnownBoolResult = tentativeLeftResult.KnownBoolResult & tentativeRightResult.KnownBoolResult;
+
+ var trueTruePath = tentativeRightResult.TruePathVariables;
+ var trueFalsePath = tentativeRightResult.FalsePathVariables;
+ var falsePath = tentativeLeftResult.FalsePathVariables;
+
+ var trueVariables = trueTruePath;
+
+ var falseVariables = trueFalsePath.Clone();
+ falseVariables.ReceiveIncoming(falsePath);
+ result.Variables = trueVariables.Clone();
+ result.Variables.ReceiveIncoming(falseVariables);
+
+ result.ConditionalBranchInfo = new ConditionalBranchInfo();
+
+ foreach (var variable in trueVariables) {
+ if (!variable.Value.IsDefiniteValue())
+ continue;
+
+ string variableName = variable.Key;
+
+ if (variable.Value != result.Variables[variableName]) {
+ bool isNull = variable.Value == NullValueStatus.DefinitelyNull;
+ result.ConditionalBranchInfo.TrueResultVariableNullStates.Add(variableName, isNull);
+ }
+ }
+
+ foreach (var variable in falseVariables) {
+ if (!variable.Value.IsDefiniteValue())
+ continue;
+
+ string variableName = variable.Key;
+
+ if (variable.Value != result.Variables [variableName]) {
+ bool isNull = variable.Value == NullValueStatus.DefinitelyNull;
+ result.ConditionalBranchInfo.FalseResultVariableNullStates.Add(variableName, isNull);
+ }
+ }
+
+ return result;
+ }
+
+ public static VisitorResult OrOperation(VisitorResult tentativeLeftResult, VisitorResult tentativeRightResult)
+ {
+ return VisitorResult.AndOperation(tentativeLeftResult.Negated, tentativeRightResult.Negated).Negated;
+ }
+ }
+
+ class NullAnalysisVisitor : DepthFirstAstVisitor
+ {
+ NullValueAnalysis analysis;
+
+ public NullAnalysisVisitor(NullValueAnalysis analysis) {
+ this.analysis = analysis;
+ }
+
+ protected override VisitorResult VisitChildren(AstNode node, VariableStatusInfo data)
+ {
+ Debug.Fail("Missing override for " + node.GetType().Name);
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitNullNode(AstNode nullNode, VariableStatusInfo data)
+ {
+ // can occur due to syntax errors
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitEmptyStatement(EmptyStatement emptyStatement, VariableStatusInfo data)
+ {
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitBlockStatement(BlockStatement blockStatement, VariableStatusInfo data)
+ {
+ //We'll visit the child statements later (we'll visit each one directly from the CFG)
+ //As such this is mostly a dummy node.
+ return new VisitorResult { Variables = data };
+ }
+
+ public override VisitorResult VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement, VariableStatusInfo data)
+ {
+ foreach (var variable in variableDeclarationStatement.Variables) {
+ var result = variable.AcceptVisitor(this, data);
+ if (result.ThrowsException)
+ return result;
+ data = result.Variables;
+ }
+
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitVariableInitializer(VariableInitializer variableInitializer, VariableStatusInfo data)
+ {
+ if (variableInitializer.Initializer.IsNull) {
+ data = data.Clone();
+ data[variableInitializer.Name] = NullValueStatus.Unassigned;
+ } else {
+ var result = variableInitializer.Initializer.AcceptVisitor(this, data);
+ if (result.ThrowsException)
+ return result;
+ data = result.Variables.Clone();
+ data[variableInitializer.Name] = result.NullableReturnResult;
+ }
+
+ return VisitorResult.ForValue(data, data [variableInitializer.Name]);
+ }
+
+ public override VisitorResult VisitIfElseStatement(IfElseStatement ifElseStatement, VariableStatusInfo data)
+ {
+ //We'll visit the true/false statements later (directly from the CFG)
+ return ifElseStatement.Condition.AcceptVisitor(this, data);
+ }
+
+ public override VisitorResult VisitWhileStatement(WhileStatement whileStatement, VariableStatusInfo data)
+ {
+ return whileStatement.Condition.AcceptVisitor(this, data);
+ }
+
+ public override VisitorResult VisitDoWhileStatement(DoWhileStatement doWhileStatement, VariableStatusInfo data)
+ {
+ return doWhileStatement.Condition.AcceptVisitor(this, data);
+ }
+
+ public override VisitorResult VisitForStatement(ForStatement forStatement, VariableStatusInfo data)
+ {
+ //The initializers, the embedded statement and the iterators aren't visited here
+ //because they have their own CFG nodes.
+ if (forStatement.Condition.IsNull)
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ return forStatement.Condition.AcceptVisitor(this, data);
+ }
+
+ public override VisitorResult VisitForeachStatement(ForeachStatement foreachStatement, VariableStatusInfo data)
+ {
+ var newVariable = foreachStatement.VariableNameToken;
+ var inExpressionResult = foreachStatement.InExpression.AcceptVisitor(this, data);
+ if (inExpressionResult.ThrowsException)
+ return inExpressionResult;
+
+ var newData = inExpressionResult.Variables.Clone();
+
+ var resolveResult = analysis.context.Resolve(foreachStatement.VariableNameToken) as LocalResolveResult;
+ if (resolveResult != null) {
+ //C# 5.0 changed the meaning of foreach so that each iteration declares a new variable
+ //as such, the variable is "uncaptured" only for C# >= 5.0
+ if (analysis.context.Supports(new Version(5, 0)) || data[newVariable.Name] != NullValueStatus.CapturedUnknown) {
+ newData[newVariable.Name] = NullValueAnalysis.IsTypeNullable(resolveResult.Type) ? inExpressionResult.EnumeratedValueResult : NullValueStatus.DefinitelyNotNull;
+ }
+ }
+
+ return VisitorResult.ForValue(newData, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitUsingStatement(UsingStatement usingStatement, VariableStatusInfo data)
+ {
+ return usingStatement.ResourceAcquisition.AcceptVisitor(this, data);
+ }
+
+ public override VisitorResult VisitFixedStatement(FixedStatement fixedStatement, VariableStatusInfo data)
+ {
+ foreach (var variable in fixedStatement.Variables) {
+ var result = variable.AcceptVisitor(this, data);
+ if (result.ThrowsException)
+ return result;
+ data = result.Variables;
+ }
+
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitSwitchStatement(SwitchStatement switchStatement, VariableStatusInfo data)
+ {
+ //We could do better than this, but it would require special handling outside the visitor
+ //so for now, for simplicity, we'll just take the easy way
+
+ var tentativeResult = switchStatement.Expression.AcceptVisitor(this, data);
+ if (tentativeResult.ThrowsException) {
+ return tentativeResult;
+ }
+
+ foreach (var section in switchStatement.SwitchSections) {
+ //No need to check for ThrowsException, since it will always be false (see VisitSwitchSection)
+ section.AcceptVisitor(this, tentativeResult.Variables);
+ }
+
+ return VisitorResult.ForValue(tentativeResult.Variables, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitSwitchSection(SwitchSection switchSection, VariableStatusInfo data)
+ {
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitExpressionStatement(ExpressionStatement expressionStatement, VariableStatusInfo data)
+ {
+ return expressionStatement.Expression.AcceptVisitor(this, data);
+ }
+
+ public override VisitorResult VisitReturnStatement(ReturnStatement returnStatement, VariableStatusInfo data)
+ {
+ if (returnStatement.Expression.IsNull)
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ return returnStatement.Expression.AcceptVisitor(this, data);
+ }
+
+ public override VisitorResult VisitTryCatchStatement(TryCatchStatement tryCatchStatement, VariableStatusInfo data)
+ {
+ //The needs special treatment in the analyser itself
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitBreakStatement(BreakStatement breakStatement, VariableStatusInfo data)
+ {
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitContinueStatement(ContinueStatement continueStatement, VariableStatusInfo data)
+ {
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitGotoStatement(GotoStatement gotoStatement, VariableStatusInfo data)
+ {
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitGotoCaseStatement(GotoCaseStatement gotoCaseStatement, VariableStatusInfo data)
+ {
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitGotoDefaultStatement(GotoDefaultStatement gotoDefaultStatement, VariableStatusInfo data)
+ {
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitLabelStatement(LabelStatement labelStatement, VariableStatusInfo data)
+ {
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitUnsafeStatement(UnsafeStatement unsafeStatement, VariableStatusInfo data)
+ {
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitLockStatement(LockStatement lockStatement, VariableStatusInfo data)
+ {
+ var expressionResult = lockStatement.Expression.AcceptVisitor(this, data);
+ if (expressionResult.ThrowsException)
+ return expressionResult;
+
+ if (expressionResult.NullableReturnResult == NullValueStatus.DefinitelyNull) {
+ return VisitorResult.ForException(expressionResult.Variables);
+ }
+
+ var identifier = CSharpUtil.GetInnerMostExpression(lockStatement.Expression) as IdentifierExpression;
+ if (identifier != null) {
+ var identifierValue = expressionResult.Variables [identifier.Identifier];
+ if (identifierValue != NullValueStatus.CapturedUnknown) {
+ var newVariables = expressionResult.Variables.Clone();
+ analysis.SetLocalVariableValue(newVariables, identifier, NullValueStatus.DefinitelyNotNull);
+
+ return VisitorResult.ForValue(newVariables, NullValueStatus.Unknown);
+ }
+ }
+
+ return VisitorResult.ForValue(expressionResult.Variables, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitThrowStatement(ThrowStatement throwStatement, VariableStatusInfo data)
+ {
+ if (throwStatement.Expression.IsNull)
+ return VisitorResult.ForValue(data, NullValueStatus.DefinitelyNotNull);
+ return throwStatement.Expression.AcceptVisitor(this, data);
+ }
+
+ public override VisitorResult VisitYieldBreakStatement(YieldBreakStatement yieldBreakStatement, VariableStatusInfo data)
+ {
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitYieldReturnStatement(YieldReturnStatement yieldReturnStatement, VariableStatusInfo data)
+ {
+ return yieldReturnStatement.Expression.AcceptVisitor(this, data);
+ }
+
+ public override VisitorResult VisitCheckedStatement(CheckedStatement checkedStatement, VariableStatusInfo data)
+ {
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitUncheckedStatement(UncheckedStatement uncheckedStatement, VariableStatusInfo data)
+ {
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ void RegisterExpressionResult(Expression expression, NullValueStatus expressionResult)
+ {
+ NullValueStatus oldStatus;
+ if (analysis.expressionResult.TryGetValue(expression, out oldStatus)) {
+ analysis.expressionResult[expression] = VariableStatusInfo.CombineStatus(analysis.expressionResult[expression], expressionResult);
+ }
+ else {
+ analysis.expressionResult[expression] = expressionResult;
+ }
+ }
+
+ VisitorResult HandleExpressionResult(Expression expression, VariableStatusInfo dataAfterExpression, NullValueStatus expressionResult) {
+ RegisterExpressionResult(expression, expressionResult);
+
+ return VisitorResult.ForValue(dataAfterExpression, expressionResult);
+ }
+
+ VisitorResult HandleExpressionResult(Expression expression, VariableStatusInfo dataAfterExpression, bool expressionResult) {
+ RegisterExpressionResult(expression, NullValueStatus.DefinitelyNotNull);
+
+ return VisitorResult.ForBoolValue(dataAfterExpression, expressionResult);
+ }
+
+ VisitorResult HandleExpressionResult(Expression expression, VisitorResult result) {
+ RegisterExpressionResult(expression, result.NullableReturnResult);
+
+ return result;
+ }
+
+ public override VisitorResult VisitAssignmentExpression(AssignmentExpression assignmentExpression, VariableStatusInfo data)
+ {
+ var tentativeResult = assignmentExpression.Left.AcceptVisitor(this, data);
+ if (tentativeResult.ThrowsException)
+ return HandleExpressionResult(assignmentExpression, tentativeResult);
+ tentativeResult = assignmentExpression.Right.AcceptVisitor(this, tentativeResult.Variables);
+ if (tentativeResult.ThrowsException)
+ return HandleExpressionResult(assignmentExpression, tentativeResult);
+
+ var leftIdentifier = assignmentExpression.Left as IdentifierExpression;
+ if (leftIdentifier != null) {
+ var resolveResult = analysis.context.Resolve(leftIdentifier);
+ if (resolveResult.IsError) {
+ return HandleExpressionResult(assignmentExpression, data, NullValueStatus.Error);
+ }
+
+ if (resolveResult is LocalResolveResult) {
+ var result = new VisitorResult();
+ result.NullableReturnResult = tentativeResult.NullableReturnResult;
+ result.Variables = tentativeResult.Variables.Clone();
+ var oldValue = result.Variables [leftIdentifier.Identifier];
+
+ if (assignmentExpression.Operator == AssignmentOperatorType.Assign ||
+ oldValue == NullValueStatus.Unassigned ||
+ oldValue == NullValueStatus.DefinitelyNotNull ||
+ tentativeResult.NullableReturnResult == NullValueStatus.Error ||
+ tentativeResult.NullableReturnResult == NullValueStatus.Unknown) {
+ analysis.SetLocalVariableValue(result.Variables, leftIdentifier, tentativeResult.NullableReturnResult);
+ } else {
+ if (oldValue == NullValueStatus.DefinitelyNull) {
+ //Do nothing --it'll remain null
+ } else {
+ analysis.SetLocalVariableValue(result.Variables, leftIdentifier, NullValueStatus.PotentiallyNull);
+ }
+ }
+
+ return HandleExpressionResult(assignmentExpression, result);
+ }
+ }
+
+ return HandleExpressionResult(assignmentExpression, tentativeResult);
+ }
+
+ public override VisitorResult VisitIdentifierExpression(IdentifierExpression identifierExpression, VariableStatusInfo data)
+ {
+ var resolveResult = analysis.context.Resolve(identifierExpression);
+ if (resolveResult.IsError) {
+ return HandleExpressionResult(identifierExpression, data, NullValueStatus.Error);
+ }
+ var local = resolveResult as LocalResolveResult;
+ if (local != null) {
+ var value = data [local.Variable.Name];
+ if (value == NullValueStatus.CapturedUnknown)
+ value = NullValueStatus.Unknown;
+ return HandleExpressionResult(identifierExpression, data, value);
+ }
+ if (resolveResult.IsCompileTimeConstant) {
+ object value = resolveResult.ConstantValue;
+ if (value == null) {
+ return HandleExpressionResult(identifierExpression, data, NullValueStatus.DefinitelyNull);
+ }
+ var boolValue = value as bool?;
+ if (boolValue != null) {
+ return VisitorResult.ForBoolValue(data, (bool)boolValue);
+ }
+ return HandleExpressionResult(identifierExpression, data, NullValueStatus.DefinitelyNotNull);
+ }
+
+ var memberResolveResult = resolveResult as MemberResolveResult;
+
+ var returnValue = GetFieldReturnValue(memberResolveResult, data);
+
+ return HandleExpressionResult(identifierExpression, data, returnValue);
+ }
+
+ public override VisitorResult VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression, VariableStatusInfo data)
+ {
+ var resolveResult = analysis.context.Resolve(defaultValueExpression);
+ if (resolveResult.IsError) {
+ return HandleExpressionResult(defaultValueExpression, data, NullValueStatus.Unknown);
+ }
+
+ Debug.Assert(resolveResult.IsCompileTimeConstant);
+
+ var status = resolveResult.ConstantValue == null && resolveResult.Type.IsReferenceType != false ? NullValueStatus.DefinitelyNull : NullValueStatus.DefinitelyNotNull;
+ return HandleExpressionResult(defaultValueExpression, data, status);
+ }
+
+ public override VisitorResult VisitNullReferenceExpression(NullReferenceExpression nullReferenceExpression, VariableStatusInfo data)
+ {
+ return HandleExpressionResult(nullReferenceExpression, data, NullValueStatus.DefinitelyNull);
+ }
+
+ public override VisitorResult VisitPrimitiveExpression(PrimitiveExpression primitiveExpression, VariableStatusInfo data)
+ {
+ return HandleExpressionResult(primitiveExpression, data, NullValueStatus.DefinitelyNotNull);
+ }
+
+ public override VisitorResult VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, VariableStatusInfo data)
+ {
+ return HandleExpressionResult(parenthesizedExpression, parenthesizedExpression.Expression.AcceptVisitor(this, data));
+ }
+
+ public override VisitorResult VisitConditionalExpression(ConditionalExpression conditionalExpression, VariableStatusInfo data)
+ {
+ var tentativeBaseResult = conditionalExpression.Condition.AcceptVisitor(this, data);
+ if (tentativeBaseResult.ThrowsException)
+ return HandleExpressionResult(conditionalExpression, tentativeBaseResult);
+
+ var conditionResolveResult = analysis.context.Resolve(conditionalExpression.Condition);
+
+ if (tentativeBaseResult.KnownBoolResult == true || true.Equals(conditionResolveResult.ConstantValue)) {
+ return HandleExpressionResult(conditionalExpression, conditionalExpression.TrueExpression.AcceptVisitor(this, tentativeBaseResult.TruePathVariables));
+ }
+ if (tentativeBaseResult.KnownBoolResult == false || false.Equals(conditionResolveResult.ConstantValue)) {
+ return HandleExpressionResult(conditionalExpression, conditionalExpression.FalseExpression.AcceptVisitor(this, tentativeBaseResult.FalsePathVariables));
+ }
+
+ //No known bool result
+ var trueCaseResult = conditionalExpression.TrueExpression.AcceptVisitor(this, tentativeBaseResult.TruePathVariables);
+ if (trueCaseResult.ThrowsException) {
+ //We know that the true case will never be completed, then the right case is the only possible route.
+ return HandleExpressionResult(conditionalExpression, conditionalExpression.FalseExpression.AcceptVisitor(this, tentativeBaseResult.FalsePathVariables));
+ }
+ var falseCaseResult = conditionalExpression.FalseExpression.AcceptVisitor(this, tentativeBaseResult.FalsePathVariables);
+ if (falseCaseResult.ThrowsException) {
+ return HandleExpressionResult(conditionalExpression, trueCaseResult.Variables, true);
+ }
+
+ return HandleExpressionResult(conditionalExpression, VisitorResult.OrOperation(trueCaseResult, falseCaseResult));
+ }
+
+ public override VisitorResult VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, VariableStatusInfo data)
+ {
+ //Let's not evaluate the sides just yet because of ??, && and ||
+
+ //We'll register the results here (with HandleExpressionResult)
+ //so each Visit*Expression won't have to do it itself
+ switch (binaryOperatorExpression.Operator) {
+ case BinaryOperatorType.ConditionalAnd:
+ return HandleExpressionResult(binaryOperatorExpression, VisitConditionalAndExpression(binaryOperatorExpression, data));
+ case BinaryOperatorType.ConditionalOr:
+ return HandleExpressionResult(binaryOperatorExpression, VisitConditionalOrExpression(binaryOperatorExpression, data));
+ case BinaryOperatorType.NullCoalescing:
+ return HandleExpressionResult(binaryOperatorExpression, VisitNullCoalescing(binaryOperatorExpression, data));
+ case BinaryOperatorType.Equality:
+ return HandleExpressionResult(binaryOperatorExpression, VisitEquality(binaryOperatorExpression, data));
+ case BinaryOperatorType.InEquality:
+ return HandleExpressionResult(binaryOperatorExpression, VisitEquality(binaryOperatorExpression, data).Negated);
+ default:
+ return HandleExpressionResult(binaryOperatorExpression, VisitOtherBinaryExpression(binaryOperatorExpression, data));
+ }
+ }
+
+ VisitorResult VisitOtherBinaryExpression(BinaryOperatorExpression binaryOperatorExpression, VariableStatusInfo data)
+ {
+ var leftTentativeResult = binaryOperatorExpression.Left.AcceptVisitor(this, data);
+ if (leftTentativeResult.ThrowsException)
+ return leftTentativeResult;
+ var rightTentativeResult = binaryOperatorExpression.Right.AcceptVisitor(this, leftTentativeResult.Variables);
+ if (rightTentativeResult.ThrowsException)
+ return rightTentativeResult;
+
+ //TODO: Assuming operators are not overloaded by users
+ // (or, if they are, that they retain similar behavior to the default ones)
+
+ switch (binaryOperatorExpression.Operator) {
+ case BinaryOperatorType.LessThan:
+ case BinaryOperatorType.GreaterThan:
+ //Operations < and > with nulls always return false
+ //Those same operations will other values may or may not return false
+ if (leftTentativeResult.NullableReturnResult == NullValueStatus.DefinitelyNull &&
+ rightTentativeResult.NullableReturnResult == NullValueStatus.DefinitelyNull) {
+ return VisitorResult.ForBoolValue(rightTentativeResult.Variables, false);
+ }
+ //We don't know what the value is, but we know that both true and false are != null.
+ return VisitorResult.ForValue(rightTentativeResult.Variables, NullValueStatus.DefinitelyNotNull);
+ case BinaryOperatorType.LessThanOrEqual:
+ case BinaryOperatorType.GreaterThanOrEqual:
+ if (leftTentativeResult.NullableReturnResult == NullValueStatus.DefinitelyNull) {
+ if (rightTentativeResult.NullableReturnResult == NullValueStatus.DefinitelyNull)
+ return VisitorResult.ForBoolValue(rightTentativeResult.Variables, true);
+ if (rightTentativeResult.NullableReturnResult == NullValueStatus.DefinitelyNotNull)
+ return VisitorResult.ForBoolValue(rightTentativeResult.Variables, false);
+ } else if (leftTentativeResult.NullableReturnResult == NullValueStatus.DefinitelyNotNull) {
+ if (rightTentativeResult.NullableReturnResult == NullValueStatus.DefinitelyNull)
+ return VisitorResult.ForBoolValue(rightTentativeResult.Variables, false);
+ }
+
+ return VisitorResult.ForValue(rightTentativeResult.Variables, NullValueStatus.Unknown);
+ default:
+ //Anything else: null + anything == anything + null == null.
+ //not null + not null = not null
+ if (leftTentativeResult.NullableReturnResult == NullValueStatus.DefinitelyNull) {
+ return VisitorResult.ForValue(rightTentativeResult.Variables, NullValueStatus.DefinitelyNull);
+ }
+ if (leftTentativeResult.NullableReturnResult == NullValueStatus.DefinitelyNotNull) {
+ if (rightTentativeResult.NullableReturnResult == NullValueStatus.DefinitelyNull)
+ return VisitorResult.ForValue(rightTentativeResult.Variables, NullValueStatus.DefinitelyNull);
+ if (rightTentativeResult.NullableReturnResult == NullValueStatus.DefinitelyNotNull)
+ return VisitorResult.ForValue(rightTentativeResult.Variables, NullValueStatus.DefinitelyNotNull);
+ }
+
+ return VisitorResult.ForValue(rightTentativeResult.Variables, NullValueStatus.Unknown);
+ }
+ }
+
+ VisitorResult WithVariableValue(VisitorResult result, IdentifierExpression identifier, bool isNull)
+ {
+ var localVariableResult = analysis.context.Resolve(identifier) as LocalResolveResult;
+ if (localVariableResult != null) {
+ result.ConditionalBranchInfo.TrueResultVariableNullStates[identifier.Identifier] = isNull;
+ if (isNull) {
+ result.ConditionalBranchInfo.FalseResultVariableNullStates[identifier.Identifier] = false;
+ }
+ }
+ return result;
+ }
+
+ VisitorResult VisitEquality(BinaryOperatorExpression binaryOperatorExpression, VariableStatusInfo data)
+ {
+ //TODO: Should this check for user operators?
+
+ var tentativeLeftResult = binaryOperatorExpression.Left.AcceptVisitor(this, data);
+ if (tentativeLeftResult.ThrowsException)
+ return tentativeLeftResult;
+ var tentativeRightResult = binaryOperatorExpression.Right.AcceptVisitor(this, tentativeLeftResult.Variables);
+ if (tentativeRightResult.ThrowsException)
+ return tentativeRightResult;
+
+ if (tentativeLeftResult.KnownBoolResult != null && tentativeLeftResult.KnownBoolResult == tentativeRightResult.KnownBoolResult) {
+ return VisitorResult.ForBoolValue(tentativeRightResult.Variables, true);
+ }
+
+ if (tentativeLeftResult.KnownBoolResult != null && tentativeLeftResult.KnownBoolResult == !tentativeRightResult.KnownBoolResult) {
+ return VisitorResult.ForBoolValue(tentativeRightResult.Variables, false);
+ }
+
+ if (tentativeLeftResult.NullableReturnResult.IsDefiniteValue()) {
+ if (tentativeRightResult.NullableReturnResult.IsDefiniteValue()) {
+ if (tentativeLeftResult.NullableReturnResult == NullValueStatus.DefinitelyNull || tentativeRightResult.NullableReturnResult == NullValueStatus.DefinitelyNull) {
+ return VisitorResult.ForBoolValue(tentativeRightResult.Variables, tentativeLeftResult.NullableReturnResult == tentativeRightResult.NullableReturnResult);
+ }
+ }
+ }
+
+ var result = new VisitorResult();
+ result.Variables = tentativeRightResult.Variables;
+ result.NullableReturnResult = NullValueStatus.Unknown;
+ result.ConditionalBranchInfo = new ConditionalBranchInfo();
+
+ if (tentativeRightResult.NullableReturnResult.IsDefiniteValue()) {
+ var identifier = CSharpUtil.GetInnerMostExpression(binaryOperatorExpression.Left) as IdentifierExpression;
+
+ if (identifier != null) {
+ bool isNull = (tentativeRightResult.NullableReturnResult == NullValueStatus.DefinitelyNull);
+
+ WithVariableValue(result, identifier, isNull);
+ }
+ }
+
+ if (tentativeLeftResult.NullableReturnResult.IsDefiniteValue()) {
+ var identifier = CSharpUtil.GetInnerMostExpression(binaryOperatorExpression.Right) as IdentifierExpression;
+
+ if (identifier != null) {
+ bool isNull = (tentativeLeftResult.NullableReturnResult == NullValueStatus.DefinitelyNull);
+
+ WithVariableValue(result, identifier, isNull);
+ }
+ }
+
+ return result;
+ }
+
+ VisitorResult VisitConditionalAndExpression(BinaryOperatorExpression binaryOperatorExpression, VariableStatusInfo data)
+ {
+ var tentativeLeftResult = binaryOperatorExpression.Left.AcceptVisitor(this, data);
+ if (tentativeLeftResult.KnownBoolResult == false || tentativeLeftResult.ThrowsException) {
+ return tentativeLeftResult;
+ }
+
+ var truePath = tentativeLeftResult.TruePathVariables;
+ var tentativeRightResult = binaryOperatorExpression.Right.AcceptVisitor(this, truePath);
+ if (tentativeRightResult.ThrowsException) {
+ //If the true path throws an exception, then the only way for the expression to complete
+ //successfully is if the left expression is false
+ return VisitorResult.ForBoolValue(tentativeLeftResult.FalsePathVariables, false);
+ }
+
+ return VisitorResult.AndOperation(tentativeLeftResult, tentativeRightResult);
+ }
+
+ VisitorResult VisitConditionalOrExpression(BinaryOperatorExpression binaryOperatorExpression, VariableStatusInfo data)
+ {
+ var tentativeLeftResult = binaryOperatorExpression.Left.AcceptVisitor(this, data);
+ if (tentativeLeftResult.KnownBoolResult == true || tentativeLeftResult.ThrowsException) {
+ return tentativeLeftResult;
+ }
+
+ var falsePath = tentativeLeftResult.FalsePathVariables;
+ var tentativeRightResult = binaryOperatorExpression.Right.AcceptVisitor(this, falsePath);
+ if (tentativeRightResult.ThrowsException) {
+ //If the false path throws an exception, then the only way for the expression to complete
+ //successfully is if the left expression is true
+ return VisitorResult.ForBoolValue(tentativeLeftResult.TruePathVariables, true);
+ }
+
+ return VisitorResult.OrOperation(tentativeLeftResult, tentativeRightResult);
+ }
+
+ VisitorResult VisitNullCoalescing(BinaryOperatorExpression binaryOperatorExpression, VariableStatusInfo data)
+ {
+ var leftTentativeResult = binaryOperatorExpression.Left.AcceptVisitor(this, data);
+ if (leftTentativeResult.NullableReturnResult == NullValueStatus.DefinitelyNotNull || leftTentativeResult.ThrowsException) {
+ return leftTentativeResult;
+ }
+
+ //If the right side is found, then the left side is known to be null
+ var newData = leftTentativeResult.Variables;
+ var leftIdentifier = CSharpUtil.GetInnerMostExpression(binaryOperatorExpression.Left) as IdentifierExpression;
+ if (leftIdentifier != null) {
+ newData = newData.Clone();
+ analysis.SetLocalVariableValue(newData, leftIdentifier, NullValueStatus.DefinitelyNull);
+ }
+
+ var rightTentativeResult = binaryOperatorExpression.Right.AcceptVisitor(this, newData);
+ if (rightTentativeResult.ThrowsException) {
+ //This means the left expression was not null all along (or else the expression will throw an exception)
+
+ if (leftIdentifier != null) {
+ newData = newData.Clone();
+ analysis.SetLocalVariableValue(newData, leftIdentifier, NullValueStatus.DefinitelyNotNull);
+ return VisitorResult.ForValue(newData, NullValueStatus.DefinitelyNotNull);
+ }
+
+ return VisitorResult.ForValue(leftTentativeResult.Variables, NullValueStatus.DefinitelyNotNull);
+ }
+
+ var mergedVariables = rightTentativeResult.Variables;
+ var nullValue = rightTentativeResult.NullableReturnResult;
+
+ if (leftTentativeResult.NullableReturnResult != NullValueStatus.DefinitelyNull) {
+ mergedVariables = mergedVariables.Clone();
+ mergedVariables.ReceiveIncoming(leftTentativeResult.Variables);
+ if (nullValue == NullValueStatus.DefinitelyNull) {
+ nullValue = NullValueStatus.PotentiallyNull;
+ }
+ }
+
+ return VisitorResult.ForValue(mergedVariables, nullValue);
+ }
+
+ public override VisitorResult VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, VariableStatusInfo data)
+ {
+ //TODO: Again, what to do when overloaded operators are found?
+
+ var tentativeResult = unaryOperatorExpression.Expression.AcceptVisitor(this, data);
+ if (tentativeResult.ThrowsException)
+ return HandleExpressionResult(unaryOperatorExpression, tentativeResult);
+
+ if (unaryOperatorExpression.Operator == UnaryOperatorType.Not) {
+ return HandleExpressionResult(unaryOperatorExpression, tentativeResult.Negated);
+ }
+ return HandleExpressionResult(unaryOperatorExpression, tentativeResult);
+ }
+
+ public override VisitorResult VisitInvocationExpression(InvocationExpression invocationExpression, VariableStatusInfo data)
+ {
+ //TODO: Handle some common methods such as string.IsNullOrEmpty
+
+ var targetResult = invocationExpression.Target.AcceptVisitor(this, data);
+ if (targetResult.ThrowsException)
+ return HandleExpressionResult(invocationExpression, targetResult);
+
+ data = targetResult.Variables;
+
+ var methodResolveResult = analysis.context.Resolve(invocationExpression) as CSharpInvocationResolveResult;
+
+ List parameterResults = new List();
+
+ foreach (var argumentToHandle in invocationExpression.Arguments.Select((argument, parameterIndex) => new { argument, parameterIndex })) {
+ var argument = argumentToHandle.argument;
+ var parameterIndex = argumentToHandle.parameterIndex;
+
+ var result = argument.AcceptVisitor(this, data);
+ if (result.ThrowsException)
+ return HandleExpressionResult(invocationExpression, result);
+ parameterResults.Add(result);
+
+ var namedArgument = argument as NamedArgumentExpression;
+
+ var directionExpression = (namedArgument == null ? argument : namedArgument.Expression) as DirectionExpression;
+ if (directionExpression != null && methodResolveResult != null) {
+ var identifier = directionExpression.Expression as IdentifierExpression;
+ if (identifier != null) {
+ //out and ref parameters do *NOT* capture the variable (since they must stop changing it by the time they return)
+ var identifierResolveResult = analysis.context.Resolve(identifier) as LocalResolveResult;
+ if (identifierResolveResult != null && IsTypeNullable(identifierResolveResult.Type)) {
+ data = data.Clone();
+
+ FixParameter(argument, methodResolveResult.Member.Parameters, parameterIndex, identifier, data);
+ }
+ }
+
+
+ continue;
+ }
+
+ data = result.Variables;
+ }
+
+ var identifierExpression = CSharpUtil.GetInnerMostExpression(invocationExpression.Target) as IdentifierExpression;
+ if (identifierExpression != null) {
+ if (targetResult.NullableReturnResult == NullValueStatus.DefinitelyNull) {
+ return HandleExpressionResult(invocationExpression, VisitorResult.ForException(data));
+ }
+
+ var descendentIdentifiers = invocationExpression.Arguments.SelectMany(argument => argument.DescendantsAndSelf).OfType();
+ if (!descendentIdentifiers.Any(identifier => identifier.Identifier == identifierExpression.Identifier)) {
+ //TODO: We can make this check better (see VisitIndexerExpression for more details)
+ data = data.Clone();
+ analysis.SetLocalVariableValue(data, identifierExpression, NullValueStatus.DefinitelyNotNull);
+ }
+ }
+
+ return HandleExpressionResult(invocationExpression, GetMethodVisitorResult(methodResolveResult, data, parameterResults));
+ }
+
+ static VisitorResult GetMethodVisitorResult(CSharpInvocationResolveResult methodResolveResult, VariableStatusInfo data, List parameterResults)
+ {
+ if (methodResolveResult == null)
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+
+ var method = methodResolveResult.Member as IMethod;
+ if (method != null) {
+ if (method.GetAttribute(new FullTypeName(AnnotationNames.AssertionMethodAttribute)) != null) {
+ var assertionParameters = method.Parameters.Select((parameter, index) => new { index, parameter })
+ .Select(parameter => new { parameter.index, parameter.parameter, attributes = parameter.parameter.Attributes.Where(attribute => attribute.AttributeType.FullName == AnnotationNames.AssertionConditionAttribute).ToList() })
+ .Where(parameter => parameter.attributes.Count() == 1)
+ .Select(parameter => new { parameter.index, parameter.parameter, attribute = parameter.attributes[0] })
+ .ToList();
+
+ //Unclear what should be done if there are multiple assertion conditions
+ if (assertionParameters.Count() == 1) {
+ Debug.Assert(methodResolveResult.Arguments.Count == parameterResults.Count);
+
+ var assertionParameter = assertionParameters [0];
+ VisitorResult assertionParameterResult = null;
+
+ object intendedResult = true;
+ var positionalArgument = assertionParameter.attribute.PositionalArguments.FirstOrDefault() as MemberResolveResult;
+ if (positionalArgument != null && positionalArgument.Type.FullName == AnnotationNames.AssertionConditionTypeAttribute) {
+ switch (positionalArgument.Member.FullName) {
+ case AnnotationNames.AssertionConditionTypeIsTrue:
+ intendedResult = true;
+ break;
+ case AnnotationNames.AssertionConditionTypeIsFalse:
+ intendedResult = false;
+ break;
+ case AnnotationNames.AssertionConditionTypeIsNull:
+ intendedResult = null;
+ break;
+ case AnnotationNames.AssertionConditionTypeIsNotNull:
+ intendedResult = "";
+ break;
+ }
+ }
+
+ int parameterIndex = assertionParameter.index;
+ if (assertionParameter.index < methodResolveResult.Arguments.Count && !(methodResolveResult.Arguments [assertionParameter.index] is NamedArgumentResolveResult)) {
+ //Use index
+ assertionParameterResult = parameterResults [assertionParameter.index];
+ } else {
+ //Use named argument
+ int? nameIndex = methodResolveResult.Arguments.Select((argument, index) => new { argument, index})
+ .Where(argument => {
+ var namedArgument = argument.argument as NamedArgumentResolveResult;
+ return namedArgument != null && namedArgument.ParameterName == assertionParameter.parameter.Name;
+ }).Select(argument => (int?)argument.index).FirstOrDefault();
+
+ if (nameIndex != null) {
+ parameterIndex = nameIndex.Value;
+ assertionParameterResult = parameterResults [nameIndex.Value];
+ } else if (assertionParameter.parameter.IsOptional) {
+ //Try to use default value
+
+ if (intendedResult is string) {
+ if (assertionParameter.parameter.ConstantValue == null) {
+ return VisitorResult.ForException(data);
+ }
+ } else {
+ if (!object.Equals(assertionParameter.parameter.ConstantValue, intendedResult)) {
+ return VisitorResult.ForException(data);
+ }
+ }
+ } else {
+ //The parameter was not specified, yet it is not optional?
+ return VisitorResult.ForException(data);
+ }
+ }
+
+ //Now check assertion
+ if (assertionParameterResult != null) {
+ if (intendedResult is bool) {
+ if (assertionParameterResult.KnownBoolResult == !(bool)intendedResult) {
+ return VisitorResult.ForException(data);
+ }
+
+ data = (bool)intendedResult ? assertionParameterResult.TruePathVariables : assertionParameterResult.FalsePathVariables;
+ } else {
+ bool shouldBeNull = intendedResult == null;
+
+ if (assertionParameterResult.NullableReturnResult == (shouldBeNull ? NullValueStatus.DefinitelyNotNull : NullValueStatus.DefinitelyNull)) {
+ return VisitorResult.ForException(data);
+ }
+
+ var parameterResolveResult = methodResolveResult.Arguments [parameterIndex];
+
+ LocalResolveResult localVariableResult = null;
+
+ var conversionResolveResult = parameterResolveResult as ConversionResolveResult;
+ if (conversionResolveResult != null) {
+ if (!IsTypeNullable(conversionResolveResult.Type)) {
+ if (intendedResult == null) {
+ return VisitorResult.ForException(data);
+ }
+ } else {
+ localVariableResult = conversionResolveResult.Input as LocalResolveResult;
+ }
+ } else {
+ localVariableResult = parameterResolveResult as LocalResolveResult;
+ }
+
+ if (localVariableResult != null && data[localVariableResult.Variable.Name] != NullValueStatus.CapturedUnknown) {
+ data = data.Clone();
+ data [localVariableResult.Variable.Name] = shouldBeNull ? NullValueStatus.DefinitelyNull : NullValueStatus.DefinitelyNotNull;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ bool isNullable = IsTypeNullable(methodResolveResult.Type);
+ if (!isNullable) {
+ return VisitorResult.ForValue(data, NullValueStatus.DefinitelyNotNull);
+ }
+
+ if (method != null)
+ return VisitorResult.ForValue(data, GetNullableStatus(method));
+
+ return VisitorResult.ForValue(data, GetNullableStatus(methodResolveResult.TargetResult.Type.GetDefinition()));
+ }
+
+ static NullValueStatus GetNullableStatus(IEntity entity)
+ {
+ if (entity.DeclaringType != null && entity.DeclaringType.Kind == TypeKind.Delegate) {
+ //Handle Delegate.Invoke method
+ return GetNullableStatus(entity.DeclaringTypeDefinition);
+ }
+
+ return GetNullableStatus(fullTypeName => entity.GetAttribute(new FullTypeName(fullTypeName)));
+ }
+
+ static NullValueStatus GetNullableStatus(IParameter parameter)
+ {
+ return GetNullableStatus(fullTypeName => parameter.Attributes.FirstOrDefault(attribute => attribute.AttributeType.FullName == fullTypeName));
+ }
+
+ static NullValueStatus GetNullableStatus(Func attributeGetter)
+ {
+ if (attributeGetter(AnnotationNames.NotNullAttribute) != null) {
+ return NullValueStatus.DefinitelyNotNull;
+ }
+ if (attributeGetter(AnnotationNames.CanBeNullAttribute) != null) {
+ return NullValueStatus.PotentiallyNull;
+ }
+ return NullValueStatus.Unknown;
+ }
+
+ public override VisitorResult VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, VariableStatusInfo data)
+ {
+ var targetResult = memberReferenceExpression.Target.AcceptVisitor(this, data);
+ if (targetResult.ThrowsException)
+ return HandleExpressionResult(memberReferenceExpression, targetResult);
+
+ var variables = targetResult.Variables;
+
+ var memberResolveResult = analysis.context.Resolve(memberReferenceExpression) as MemberResolveResult;
+
+ var targetIdentifier = CSharpUtil.GetInnerMostExpression(memberReferenceExpression.Target) as IdentifierExpression;
+ if (targetIdentifier != null) {
+ if (memberResolveResult == null) {
+ var invocation = memberReferenceExpression.Parent as InvocationExpression;
+ if (invocation != null) {
+ memberResolveResult = analysis.context.Resolve(invocation) as MemberResolveResult;
+ }
+ }
+
+ if (memberResolveResult != null && memberResolveResult.Member.FullName != "System.Nullable.HasValue") {
+ var method = memberResolveResult.Member as IMethod;
+ if (method == null || !method.IsExtensionMethod) {
+ if (targetResult.NullableReturnResult == NullValueStatus.DefinitelyNull) {
+ return HandleExpressionResult(memberReferenceExpression, VisitorResult.ForException(variables));
+ }
+ if (variables [targetIdentifier.Identifier] != NullValueStatus.CapturedUnknown) {
+ variables = variables.Clone();
+ analysis.SetLocalVariableValue(variables, targetIdentifier, NullValueStatus.DefinitelyNotNull);
+ }
+ }
+ }
+ }
+
+ var returnValue = GetFieldReturnValue(memberResolveResult, data);
+ return HandleExpressionResult(memberReferenceExpression, variables, returnValue);
+ }
+
+ static NullValueStatus GetFieldReturnValue(MemberResolveResult memberResolveResult, VariableStatusInfo data)
+ {
+ bool isNullable = memberResolveResult == null || IsTypeNullable(memberResolveResult.Type);
+ if (!isNullable) {
+ return NullValueStatus.DefinitelyNotNull;
+ }
+
+ if (memberResolveResult != null) {
+ return GetNullableStatus(memberResolveResult.Member);
+ }
+
+ return NullValueStatus.Unknown;
+ }
+
+ public override VisitorResult VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression, VariableStatusInfo data)
+ {
+ return HandleExpressionResult(typeReferenceExpression, data, NullValueStatus.Unknown);
+
+ }
+
+ void FixParameter(Expression argument, IList parameters, int parameterIndex, IdentifierExpression identifier, VariableStatusInfo data)
+ {
+ NullValueStatus newValue = NullValueStatus.Unknown;
+ if (argument is NamedArgumentExpression) {
+ var namedResolveResult = analysis.context.Resolve(argument) as NamedArgumentResolveResult;
+ if (namedResolveResult != null) {
+ newValue = GetNullableStatus(namedResolveResult.Parameter);
+ }
+ }
+ else {
+ var parameter = parameters[parameterIndex];
+ newValue = GetNullableStatus(parameter);
+ }
+ analysis.SetLocalVariableValue(data, identifier, newValue);
+ }
+
+ public override VisitorResult VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression, VariableStatusInfo data)
+ {
+ foreach (var argumentToHandle in objectCreateExpression.Arguments.Select((argument, parameterIndex) => new { argument, parameterIndex })) {
+ var argument = argumentToHandle.argument;
+ var parameterIndex = argumentToHandle.parameterIndex;
+
+ var namedArgument = argument as NamedArgumentExpression;
+
+ var directionExpression = (namedArgument == null ? argument : namedArgument.Expression) as DirectionExpression;
+ if (directionExpression != null) {
+ var identifier = directionExpression.Expression as IdentifierExpression;
+ if (identifier != null && data [identifier.Identifier] != NullValueStatus.CapturedUnknown) {
+ //out and ref parameters do *NOT* capture the variable (since they must stop changing it by the time they return)
+ data = data.Clone();
+
+ var constructorResolveResult = analysis.context.Resolve(objectCreateExpression) as CSharpInvocationResolveResult;
+ if (constructorResolveResult != null)
+ FixParameter(argument, constructorResolveResult.Member.Parameters, parameterIndex, identifier, data);
+ }
+ continue;
+ }
+
+ var argumentResult = argument.AcceptVisitor(this, data);
+ if (argumentResult.ThrowsException)
+ return argumentResult;
+
+ data = argumentResult.Variables;
+ }
+
+ //Constructors never return null
+ return HandleExpressionResult(objectCreateExpression, data, NullValueStatus.DefinitelyNotNull);
+ }
+
+ public override VisitorResult VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression, VariableStatusInfo data)
+ {
+ foreach (var argument in arrayCreateExpression.Arguments) {
+ var result = argument.AcceptVisitor(this, data);
+ if (result.ThrowsException)
+ return result;
+ data = result.Variables.Clone();
+ }
+
+ if (arrayCreateExpression.Initializer.IsNull) {
+ return HandleExpressionResult(arrayCreateExpression, data, NullValueStatus.DefinitelyNotNull);
+ }
+
+ return HandleExpressionResult(arrayCreateExpression, arrayCreateExpression.Initializer.AcceptVisitor(this, data));
+ }
+
+ public override VisitorResult VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression, VariableStatusInfo data)
+ {
+ if (arrayInitializerExpression.IsSingleElement) {
+ return HandleExpressionResult(arrayInitializerExpression, arrayInitializerExpression.Elements.Single().AcceptVisitor(this, data));
+ }
+ if (!arrayInitializerExpression.Elements.Any()) {
+ //Empty array
+ return HandleExpressionResult(arrayInitializerExpression, VisitorResult.ForValue(data, NullValueStatus.Unknown));
+ }
+
+ NullValueStatus enumeratedValue = NullValueStatus.UnreachableOrInexistent;
+ foreach (var element in arrayInitializerExpression.Elements) {
+ var result = element.AcceptVisitor(this, data);
+ if (result.ThrowsException)
+ return result;
+ data = result.Variables.Clone();
+ enumeratedValue = VariableStatusInfo.CombineStatus(enumeratedValue, result.NullableReturnResult);
+
+ }
+ return HandleExpressionResult(arrayInitializerExpression, VisitorResult.ForEnumeratedValue(data, enumeratedValue));
+ }
+
+ public override VisitorResult VisitAnonymousTypeCreateExpression(AnonymousTypeCreateExpression anonymousTypeCreateExpression, VariableStatusInfo data)
+ {
+ foreach (var initializer in anonymousTypeCreateExpression.Initializers) {
+ var result = initializer.AcceptVisitor(this, data);
+ if (result.ThrowsException)
+ return result;
+ data = result.Variables;
+ }
+
+ return HandleExpressionResult(anonymousTypeCreateExpression, data, NullValueStatus.DefinitelyNotNull);
+ }
+
+ public override VisitorResult VisitLambdaExpression(LambdaExpression lambdaExpression, VariableStatusInfo data)
+ {
+ var newData = data.Clone();
+
+ var identifiers = lambdaExpression.Descendants.OfType();
+ foreach (var identifier in identifiers) {
+ //Check if it is in a "change-null-state" context
+ //For instance, x++ does not change the null state
+ //but `x = y` does.
+ if (identifier.Parent is AssignmentExpression && identifier.Role == AssignmentExpression.LeftRole) {
+ var parent = (AssignmentExpression)identifier.Parent;
+ if (parent.Operator != AssignmentOperatorType.Assign) {
+ continue;
+ }
+ } else {
+ //No other context matters
+ //Captured variables are never passed by reference (out/ref)
+ continue;
+ }
+
+ //At this point, we know there's a good chance the variable has been changed
+ var identifierResolveResult = analysis.context.Resolve(identifier) as LocalResolveResult;
+ if (identifierResolveResult != null && IsTypeNullable(identifierResolveResult.Type)) {
+ analysis.SetLocalVariableValue(newData, identifier, NullValueStatus.CapturedUnknown);
+ }
+ }
+
+ //The lambda itself is known not to be null
+ return HandleExpressionResult(lambdaExpression, newData, NullValueStatus.DefinitelyNotNull);
+ }
+
+ public override VisitorResult VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression, VariableStatusInfo data)
+ {
+ var newData = data.Clone();
+
+ var identifiers = anonymousMethodExpression.Descendants.OfType();
+ foreach (var identifier in identifiers) {
+ //Check if it is in a "change-null-state" context
+ //For instance, x++ does not change the null state
+ //but `x = y` does.
+ if (identifier.Parent is AssignmentExpression && identifier.Role == AssignmentExpression.LeftRole) {
+ var parent = (AssignmentExpression)identifier.Parent;
+ if (parent.Operator != AssignmentOperatorType.Assign) {
+ continue;
+ }
+ } else {
+ //No other context matters
+ //Captured variables are never passed by reference (out/ref)
+ continue;
+ }
+
+ //At this point, we know there's a good chance the variable has been changed
+ var identifierResolveResult = analysis.context.Resolve(identifier) as LocalResolveResult;
+ if (identifierResolveResult != null && IsTypeNullable(identifierResolveResult.Type)) {
+ analysis.SetLocalVariableValue(newData, identifier, NullValueStatus.CapturedUnknown);
+ }
+ }
+
+ //The anonymous method itself is known not to be null
+ return HandleExpressionResult(anonymousMethodExpression, newData, NullValueStatus.DefinitelyNotNull);
+ }
+
+
+ public override VisitorResult VisitNamedExpression(NamedExpression namedExpression, VariableStatusInfo data)
+ {
+ return HandleExpressionResult(namedExpression, namedExpression.Expression.AcceptVisitor(this, data));
+ }
+
+ public override VisitorResult VisitAsExpression(AsExpression asExpression, VariableStatusInfo data)
+ {
+ var tentativeResult = asExpression.Expression.AcceptVisitor(this, data);
+ if (tentativeResult.ThrowsException)
+ return tentativeResult;
+
+ NullValueStatus result;
+ if (tentativeResult.NullableReturnResult == NullValueStatus.DefinitelyNull) {
+ result = NullValueStatus.DefinitelyNull;
+ } else {
+ var asResolveResult = analysis.context.Resolve(asExpression) as CastResolveResult;
+ if (asResolveResult == null ||
+ asResolveResult.IsError ||
+ asResolveResult.Input.Type.Kind == TypeKind.Unknown ||
+ asResolveResult.Type.Kind == TypeKind.Unknown) {
+
+ result = NullValueStatus.Unknown;
+ } else {
+ var conversion = new CSharpConversions(analysis.context.Compilation);
+ var foundConversion = conversion.ExplicitConversion(asResolveResult.Input.Type, asResolveResult.Type);
+
+ if (foundConversion == Conversion.None) {
+ result = NullValueStatus.DefinitelyNull;
+ } else if (foundConversion == Conversion.IdentityConversion) {
+ result = tentativeResult.NullableReturnResult;
+ } else {
+ result = NullValueStatus.PotentiallyNull;
+ }
+ }
+ }
+ return HandleExpressionResult(asExpression, tentativeResult.Variables, result);
+ }
+
+ public override VisitorResult VisitCastExpression(CastExpression castExpression, VariableStatusInfo data)
+ {
+ var tentativeResult = castExpression.Expression.AcceptVisitor(this, data);
+ if (tentativeResult.ThrowsException)
+ return tentativeResult;
+
+ NullValueStatus result;
+ if (tentativeResult.NullableReturnResult == NullValueStatus.DefinitelyNull) {
+ result = NullValueStatus.DefinitelyNull;
+ } else {
+ result = NullValueStatus.Unknown;
+ }
+
+ VariableStatusInfo variables = tentativeResult.Variables;
+
+ var resolveResult = analysis.context.Resolve(castExpression) as CastResolveResult;
+ if (resolveResult != null && !IsTypeNullable(resolveResult.Type)) {
+ if (result == NullValueStatus.DefinitelyNull) {
+ return HandleExpressionResult(castExpression, VisitorResult.ForException(tentativeResult.Variables));
+ }
+
+ var identifierExpression = CSharpUtil.GetInnerMostExpression(castExpression.Expression) as IdentifierExpression;
+ if (identifierExpression != null) {
+ var currentValue = variables [identifierExpression.Identifier];
+ if (currentValue != NullValueStatus.CapturedUnknown &&
+ currentValue != NullValueStatus.UnreachableOrInexistent &&
+ currentValue != NullValueStatus.DefinitelyNotNull) {
+ //DefinitelyNotNull is included in this list because if that's the status
+ // then we don't need to change anything
+
+ variables = variables.Clone();
+ variables [identifierExpression.Identifier] = NullValueStatus.DefinitelyNotNull;
+ }
+ }
+
+ result = NullValueStatus.DefinitelyNotNull;
+ }
+
+ return HandleExpressionResult(castExpression, variables, result);
+ }
+
+ public override VisitorResult VisitIsExpression(IsExpression isExpression, VariableStatusInfo data)
+ {
+ var tentativeResult = isExpression.Expression.AcceptVisitor(this, data);
+ if (tentativeResult.ThrowsException)
+ return tentativeResult;
+
+ //TODO: Consider, for instance: new X() is X. The result is known to be true, so we can use KnownBoolValue
+ return HandleExpressionResult(isExpression, tentativeResult.Variables, NullValueStatus.DefinitelyNotNull);
+ }
+
+ public override VisitorResult VisitDirectionExpression(DirectionExpression directionExpression, VariableStatusInfo data)
+ {
+ return HandleExpressionResult(directionExpression, directionExpression.Expression.AcceptVisitor(this, data));
+ }
+
+ public override VisitorResult VisitCheckedExpression(CheckedExpression checkedExpression, VariableStatusInfo data)
+ {
+ return HandleExpressionResult(checkedExpression, checkedExpression.Expression.AcceptVisitor(this, data));
+ }
+
+ public override VisitorResult VisitUncheckedExpression(UncheckedExpression uncheckedExpression, VariableStatusInfo data)
+ {
+ return HandleExpressionResult(uncheckedExpression, uncheckedExpression.Expression.AcceptVisitor(this, data));
+ }
+
+ public override VisitorResult VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression, VariableStatusInfo data)
+ {
+ return HandleExpressionResult(thisReferenceExpression, data, NullValueStatus.DefinitelyNotNull);
+ }
+
+ public override VisitorResult VisitIndexerExpression(IndexerExpression indexerExpression, VariableStatusInfo data)
+ {
+ var tentativeResult = indexerExpression.Target.AcceptVisitor(this, data);
+ if (tentativeResult.ThrowsException)
+ return tentativeResult;
+
+ data = tentativeResult.Variables;
+
+ foreach (var argument in indexerExpression.Arguments) {
+ var result = argument.AcceptVisitor(this, data);
+ if (result.ThrowsException)
+ return result;
+ data = result.Variables.Clone();
+ }
+
+ IdentifierExpression targetAsIdentifier = CSharpUtil.GetInnerMostExpression(indexerExpression.Target) as IdentifierExpression;
+ if (targetAsIdentifier != null) {
+ if (tentativeResult.NullableReturnResult == NullValueStatus.DefinitelyNull)
+ return HandleExpressionResult(indexerExpression, VisitorResult.ForException(data));
+
+ //If this doesn't cause an exception, then the target is not null
+ //But we won't set it if it has been changed
+ var descendentIdentifiers = indexerExpression.Arguments
+ .SelectMany(argument => argument.DescendantsAndSelf).OfType();
+ if (!descendentIdentifiers.Any(identifier => identifier.Identifier == targetAsIdentifier.Identifier)) {
+ //TODO: this check might be improved to include more legitimate cases
+ //A good check will necessarily have to consider captured variables
+ data = data.Clone();
+ analysis.SetLocalVariableValue(data, targetAsIdentifier, NullValueStatus.DefinitelyNotNull);
+ }
+ }
+
+ var indexerResolveResult = analysis.context.Resolve(indexerExpression) as CSharpInvocationResolveResult;
+ bool isNullable = indexerResolveResult == null || IsTypeNullable(indexerResolveResult.Type);
+
+ var returnValue = isNullable ? NullValueStatus.Unknown : NullValueStatus.DefinitelyNotNull;
+ return HandleExpressionResult(indexerExpression, data, returnValue);
+ }
+
+ public override VisitorResult VisitBaseReferenceExpression(BaseReferenceExpression baseReferenceExpression, VariableStatusInfo data)
+ {
+ return HandleExpressionResult(baseReferenceExpression, data, NullValueStatus.DefinitelyNotNull);
+ }
+
+ public override VisitorResult VisitTypeOfExpression(TypeOfExpression typeOfExpression, VariableStatusInfo data)
+ {
+ return HandleExpressionResult(typeOfExpression, data, NullValueStatus.DefinitelyNotNull);
+ }
+
+ public override VisitorResult VisitSizeOfExpression(SizeOfExpression sizeOfExpression, VariableStatusInfo data)
+ {
+ return HandleExpressionResult(sizeOfExpression, data, NullValueStatus.DefinitelyNotNull);
+ }
+
+ public override VisitorResult VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression, VariableStatusInfo data)
+ {
+ var targetResult = pointerReferenceExpression.Target.AcceptVisitor(this, data);
+ if (targetResult.ThrowsException)
+ return targetResult;
+ return HandleExpressionResult(pointerReferenceExpression, targetResult.Variables, NullValueStatus.DefinitelyNotNull);
+ }
+
+ public override VisitorResult VisitStackAllocExpression(StackAllocExpression stackAllocExpression, VariableStatusInfo data)
+ {
+ var countResult = stackAllocExpression.CountExpression.AcceptVisitor(this, data);
+ if (countResult.ThrowsException)
+ return countResult;
+ return HandleExpressionResult(stackAllocExpression, countResult.Variables, NullValueStatus.DefinitelyNotNull);
+ }
+
+ public override VisitorResult VisitNamedArgumentExpression(NamedArgumentExpression namedArgumentExpression, VariableStatusInfo data)
+ {
+ return HandleExpressionResult(namedArgumentExpression, namedArgumentExpression.Expression.AcceptVisitor(this, data));
+ }
+
+ public override VisitorResult VisitUndocumentedExpression(UndocumentedExpression undocumentedExpression, VariableStatusInfo data)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override VisitorResult VisitQueryExpression(QueryExpression queryExpression, VariableStatusInfo data)
+ {
+ VariableStatusInfo outgoingData = data.Clone();
+ NullValueStatus? outgoingEnumeratedValue = null;
+ var clauses = queryExpression.Clauses.ToList();
+
+ var backtracingClauses = (from item in clauses.Select((clause, i) => new { clause, i })
+ where item.clause is QueryFromClause || item.clause is QueryJoinClause || item.clause is QueryContinuationClause
+ select item.i).ToList();
+
+ var beforeClauseVariableStates = Enumerable.Range(0, clauses.Count).ToDictionary(clauseIndex => clauseIndex,
+ clauseIndex => new VariableStatusInfo());
+ var afterClauseVariableStates = Enumerable.Range(0, clauses.Count).ToDictionary(clauseIndex => clauseIndex,
+ clauseIndex => new VariableStatusInfo());
+
+ VisitorResult lastValidResult = null;
+ int currentClauseIndex = 0;
+ for (;;) {
+ VisitorResult result = null;
+ QueryClause clause = null;
+ bool backtrack = false;
+
+ if (currentClauseIndex >= clauses.Count) {
+ backtrack = true;
+ } else {
+ clause = clauses [currentClauseIndex];
+ beforeClauseVariableStates [currentClauseIndex].ReceiveIncoming(data);
+ result = clause.AcceptVisitor(this, data);
+ data = result.Variables;
+ lastValidResult = result;
+ if (result.KnownBoolResult == false) {
+ backtrack = true;
+ }
+ if (result.ThrowsException) {
+ //Don't backtrack. Exceptions completely stop the query.
+ break;
+ }
+ else {
+ afterClauseVariableStates [currentClauseIndex].ReceiveIncoming(data);
+ }
+ }
+
+ if (backtrack) {
+ int? newIndex;
+ for (;;) {
+ newIndex = backtracingClauses.LastOrDefault(index => index < currentClauseIndex);
+ if (newIndex == null) {
+ //We've reached the end
+ break;
+ }
+
+ currentClauseIndex = (int)newIndex + 1;
+
+ if (!beforeClauseVariableStates[currentClauseIndex].ReceiveIncoming(lastValidResult.Variables)) {
+ newIndex = null;
+ break;
+ }
+ }
+
+ if (newIndex == null) {
+ break;
+ }
+
+ } else {
+ if (clause is QuerySelectClause) {
+ outgoingData.ReceiveIncoming(data);
+ if (outgoingEnumeratedValue == null)
+ outgoingEnumeratedValue = result.EnumeratedValueResult;
+ else
+ outgoingEnumeratedValue = VariableStatusInfo.CombineStatus(outgoingEnumeratedValue.Value, result.EnumeratedValueResult);
+ }
+
+ ++currentClauseIndex;
+ }
+ }
+
+ var finalData = new VariableStatusInfo();
+ var endingClauseIndices = from item in clauses.Select((clause, i) => new { clause, i })
+ let clause = item.clause
+ where clause is QueryFromClause ||
+ clause is QueryContinuationClause ||
+ clause is QueryJoinClause ||
+ clause is QuerySelectClause ||
+ clause is QueryWhereClause
+ select item.i;
+ foreach (var clauseIndex in endingClauseIndices) {
+ finalData.ReceiveIncoming(afterClauseVariableStates [clauseIndex]);
+ }
+
+ return VisitorResult.ForEnumeratedValue(finalData, outgoingEnumeratedValue ?? NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitQueryContinuationClause(QueryContinuationClause queryContinuationClause, VariableStatusInfo data)
+ {
+ return IntroduceVariableFromEnumeratedValue(queryContinuationClause.Identifier, queryContinuationClause.PrecedingQuery, data);
+ }
+
+ VisitorResult IntroduceVariableFromEnumeratedValue(string newVariable, Expression expression, VariableStatusInfo data)
+ {
+ var result = expression.AcceptVisitor(this, data);
+ var newVariables = result.Variables.Clone();
+ newVariables[newVariable] = result.EnumeratedValueResult;
+ return VisitorResult.ForValue(newVariables, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitQueryFromClause(QueryFromClause queryFromClause, VariableStatusInfo data)
+ {
+ return IntroduceVariableFromEnumeratedValue(queryFromClause.Identifier, queryFromClause.Expression, data);
+ }
+
+ public override VisitorResult VisitQueryJoinClause(QueryJoinClause queryJoinClause, VariableStatusInfo data)
+ {
+ //TODO: Check if this really works in weird edge-cases.
+ var tentativeResult = IntroduceVariableFromEnumeratedValue(queryJoinClause.JoinIdentifier, queryJoinClause.InExpression, data);
+ tentativeResult = queryJoinClause.OnExpression.AcceptVisitor(this, tentativeResult.Variables);
+ tentativeResult = queryJoinClause.EqualsExpression.AcceptVisitor(this, tentativeResult.Variables);
+
+ if (queryJoinClause.IsGroupJoin) {
+ var newVariables = tentativeResult.Variables.Clone();
+ analysis.SetLocalVariableValue(newVariables, queryJoinClause.IntoIdentifierToken, NullValueStatus.DefinitelyNotNull);
+ return VisitorResult.ForValue(newVariables, NullValueStatus.Unknown);
+ }
+
+ return tentativeResult;
+ }
+
+ public override VisitorResult VisitQueryLetClause(QueryLetClause queryLetClause, VariableStatusInfo data)
+ {
+ var result = queryLetClause.Expression.AcceptVisitor(this, data);
+
+ string newVariable = queryLetClause.Identifier;
+ var newVariables = result.Variables.Clone();
+ newVariables [newVariable] = result.NullableReturnResult;
+
+ return VisitorResult.ForValue(newVariables, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitQuerySelectClause(QuerySelectClause querySelectClause, VariableStatusInfo data)
+ {
+ var result = querySelectClause.Expression.AcceptVisitor(this, data);
+
+ //The value of the expression in select becomes the "enumerated" value
+ return VisitorResult.ForEnumeratedValue(result.Variables, result.NullableReturnResult);
+ }
+
+ public override VisitorResult VisitQueryWhereClause(QueryWhereClause queryWhereClause, VariableStatusInfo data)
+ {
+ var result = queryWhereClause.Condition.AcceptVisitor(this, data);
+
+ return VisitorResult.ForEnumeratedValue(result.TruePathVariables, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitQueryOrderClause(QueryOrderClause queryOrderClause, VariableStatusInfo data)
+ {
+ foreach (var ordering in queryOrderClause.Orderings) {
+ data = ordering.AcceptVisitor(this, data).Variables;
+ }
+
+ return VisitorResult.ForValue(data, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitQueryOrdering(QueryOrdering queryOrdering, VariableStatusInfo data)
+ {
+ return VisitorResult.ForValue(queryOrdering.Expression.AcceptVisitor(this, data).Variables, NullValueStatus.Unknown);
+ }
+
+ public override VisitorResult VisitQueryGroupClause(QueryGroupClause queryGroupClause, VariableStatusInfo data)
+ {
+ var projectionResult = queryGroupClause.Projection.AcceptVisitor(this, data);
+ data = projectionResult.Variables;
+ data = queryGroupClause.Key.AcceptVisitor(this, data).Variables;
+
+ return VisitorResult.ForEnumeratedValue(data, projectionResult.NullableReturnResult);
+ }
+ }
+ }
+}
+
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/NullValueStatus.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/NullValueStatus.cs
new file mode 100644
index 000000000..f6816dfd5
--- /dev/null
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/NullValueStatus.cs
@@ -0,0 +1,84 @@
+//
+// NullValueAnalysis.cs
+//
+// Author:
+// Luís Reis
+//
+// Copyright (c) 2013 Luís Reis
+//
+// 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;
+
+namespace ICSharpCode.NRefactory.CSharp.Analysis
+{
+ ///
+ /// Represents the null value status of a variable at a specific location.
+ ///
+ public enum NullValueStatus
+ {
+ ///
+ /// The value of the variable is unknown, possibly due to limitations
+ /// of the null value analysis.
+ ///
+ Unknown = 0,
+ ///
+ /// The value of the variable is unknown and even assigning it to a
+ /// value won't change its state, since it has been captured by a lambda
+ /// that may change it at any time (potentially even from a different thread).
+ /// Only going out of scope and creating a new variable may change the value
+ /// of this variable.
+ ///
+ CapturedUnknown,
+ ///
+ /// This variable is potentially unassigned.
+ ///
+ Unassigned,
+ ///
+ /// The value of the variable is provably null.
+ ///
+ DefinitelyNull,
+ ///
+ /// The value of the variable might or might not be null
+ ///
+ PotentiallyNull,
+ ///
+ /// The value of the variable is provably not null
+ ///
+ DefinitelyNotNull,
+ ///
+ /// The position of this node is unreachable, therefore the value
+ /// of the variable is not meaningful.
+ /// Alternatively, it might mean no local variable exists with the requested name.
+ ///
+ UnreachableOrInexistent,
+ ///
+ /// The analyser has encountered an error when attempting to find the value
+ /// of this variable.
+ ///
+ Error
+ }
+
+ public static class NullValueStatusExtensions
+ {
+ public static bool IsDefiniteValue (this NullValueStatus self) {
+ return self == NullValueStatus.DefinitelyNull || self == NullValueStatus.DefinitelyNotNull;
+ }
+ }
+}
+
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ReachabilityAnalysis.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ReachabilityAnalysis.cs
index ebb8d419d..ce64f5f3b 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ReachabilityAnalysis.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ReachabilityAnalysis.cs
@@ -1,4 +1,4 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
+// Copyright (c) 2010-2013 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
@@ -18,10 +18,12 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Threading;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.CSharp.TypeSystem;
using ICSharpCode.NRefactory.Semantics;
+using ICSharpCode.NRefactory.CSharp;
namespace ICSharpCode.NRefactory.CSharp.Analysis
{
@@ -34,32 +36,37 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
HashSet reachableEndPoints = new HashSet();
HashSet visitedNodes = new HashSet();
Stack stack = new Stack();
+ RecursiveDetectorVisitor recursiveDetectorVisitor = null;
private ReachabilityAnalysis() {}
- public static ReachabilityAnalysis Create(Statement statement, CSharpAstResolver resolver = null, CancellationToken cancellationToken = default(CancellationToken))
+ public static ReachabilityAnalysis Create(Statement statement, CSharpAstResolver resolver = null, RecursiveDetectorVisitor recursiveDetectorVisitor = null, CancellationToken cancellationToken = default(CancellationToken))
{
var cfgBuilder = new ControlFlowGraphBuilder();
var cfg = cfgBuilder.BuildControlFlowGraph(statement, resolver, cancellationToken);
- return Create(cfg, cancellationToken);
+ return Create(cfg, recursiveDetectorVisitor, cancellationToken);
}
internal static ReachabilityAnalysis Create(Statement statement, Func resolver, CSharpTypeResolveContext typeResolveContext, CancellationToken cancellationToken)
{
var cfgBuilder = new ControlFlowGraphBuilder();
var cfg = cfgBuilder.BuildControlFlowGraph(statement, resolver, typeResolveContext, cancellationToken);
- return Create(cfg, cancellationToken);
+ return Create(cfg, null, cancellationToken);
}
- public static ReachabilityAnalysis Create(IList controlFlowGraph, CancellationToken cancellationToken = default(CancellationToken))
+ public static ReachabilityAnalysis Create(IList controlFlowGraph, RecursiveDetectorVisitor recursiveDetectorVisitor = null, CancellationToken cancellationToken = default(CancellationToken))
{
if (controlFlowGraph == null)
throw new ArgumentNullException("controlFlowGraph");
ReachabilityAnalysis ra = new ReachabilityAnalysis();
- ra.stack.Push(controlFlowGraph[0]);
- while (ra.stack.Count > 0) {
- cancellationToken.ThrowIfCancellationRequested();
- ra.MarkReachable(ra.stack.Pop());
+ ra.recursiveDetectorVisitor = recursiveDetectorVisitor;
+ // Analysing a null node can result in an empty control flow graph
+ if (controlFlowGraph.Count > 0) {
+ ra.stack.Push(controlFlowGraph[0]);
+ while (ra.stack.Count > 0) {
+ cancellationToken.ThrowIfCancellationRequested();
+ ra.MarkReachable(ra.stack.Pop());
+ }
}
ra.stack = null;
ra.visitedNodes = null;
@@ -68,15 +75,32 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
void MarkReachable(ControlFlowNode node)
{
- if (node.PreviousStatement != null)
+ if (node.PreviousStatement != null) {
+ if (node.PreviousStatement is LabelStatement) {
+ reachableStatements.Add(node.PreviousStatement);
+ }
reachableEndPoints.Add(node.PreviousStatement);
- if (node.NextStatement != null)
+ }
+ if (node.NextStatement != null) {
reachableStatements.Add(node.NextStatement);
+ if (IsRecursive(node.NextStatement)) {
+ return;
+ }
+ }
foreach (var edge in node.Outgoing) {
if (visitedNodes.Add(edge.To))
stack.Push(edge.To);
}
}
+
+ bool IsRecursive(Statement statement)
+ {
+ return recursiveDetectorVisitor != null && statement.AcceptVisitor(recursiveDetectorVisitor);
+ }
+
+ public IEnumerable ReachableStatements {
+ get { return reachableStatements; }
+ }
public bool IsReachable(Statement statement)
{
@@ -87,5 +111,99 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
{
return reachableEndPoints.Contains(statement);
}
+
+ public class RecursiveDetectorVisitor : DepthFirstAstVisitor
+ {
+ public override bool VisitConditionalExpression(ConditionalExpression conditionalExpression)
+ {
+ if (conditionalExpression.Condition.AcceptVisitor(this))
+ return true;
+
+ if (!conditionalExpression.TrueExpression.AcceptVisitor(this))
+ return false;
+
+ return conditionalExpression.FalseExpression.AcceptVisitor(this);
+ }
+
+ public override bool VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression)
+ {
+ if (binaryOperatorExpression.Operator == BinaryOperatorType.NullCoalescing) {
+ return binaryOperatorExpression.Left.AcceptVisitor(this);
+ }
+ return base.VisitBinaryOperatorExpression(binaryOperatorExpression);
+ }
+
+ public override bool VisitIfElseStatement(IfElseStatement ifElseStatement)
+ {
+ if (ifElseStatement.Condition.AcceptVisitor(this))
+ return true;
+
+ if (!ifElseStatement.TrueStatement.AcceptVisitor(this))
+ return false;
+
+ //No need to worry about null ast nodes, since AcceptVisitor will just
+ //return false in those cases
+ return ifElseStatement.FalseStatement.AcceptVisitor(this);
+ }
+
+ public override bool VisitForeachStatement(ForeachStatement foreachStatement)
+ {
+ //Even if the body is always recursive, the function may stop if the collection
+ // is empty.
+ return foreachStatement.InExpression.AcceptVisitor(this);
+ }
+
+ public override bool VisitForStatement(ForStatement forStatement)
+ {
+ if (forStatement.Initializers.Any(initializer => initializer.AcceptVisitor(this)))
+ return true;
+
+ return forStatement.Condition.AcceptVisitor(this);
+ }
+
+ public override bool VisitSwitchStatement(SwitchStatement switchStatement)
+ {
+ if (switchStatement.Expression.AcceptVisitor(this)) {
+ return true;
+ }
+
+ bool foundDefault = false;
+ foreach (var section in switchStatement.SwitchSections) {
+ foundDefault = foundDefault || section.CaseLabels.Any(label => label.Expression.IsNull);
+ if (!section.AcceptVisitor(this))
+ return false;
+ }
+
+ return foundDefault;
+ }
+
+ public override bool VisitBlockStatement(BlockStatement blockStatement)
+ {
+ //If the block has a recursive statement, then that statement will be visited
+ //individually by the CFG construction algorithm later.
+ return false;
+ }
+
+ protected override bool VisitChildren(AstNode node)
+ {
+ return VisitNodeList(node.Children);
+ }
+
+ bool VisitNodeList(IEnumerable nodes) {
+ return nodes.Any(node => node.AcceptVisitor(this));
+ }
+
+ public override bool VisitQueryExpression(QueryExpression queryExpression)
+ {
+ //We only care about the first from clause because:
+ //in "from x in Method() select x", Method() might be recursive
+ //but in "from x in Bar() from y in Method() select x + y", even if Method() is recursive
+ //Bar might still be empty.
+ var queryFromClause = queryExpression.Clauses.OfType().FirstOrDefault();
+ if (queryFromClause == null)
+ return true;
+ return queryFromClause.AcceptVisitor(this);
+ }
+ }
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/SemanticHighlightingVisitor.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/SemanticHighlightingVisitor.cs
new file mode 100644
index 000000000..b0ef67743
--- /dev/null
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/SemanticHighlightingVisitor.cs
@@ -0,0 +1,691 @@
+// Copyright (c) 2010-2013 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 System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using ICSharpCode.NRefactory.CSharp.Resolver;
+using ICSharpCode.NRefactory.Semantics;
+using ICSharpCode.NRefactory.TypeSystem;
+using System.Threading;
+using ICSharpCode.NRefactory.CSharp.Completion;
+using System.Collections.ObjectModel;
+
+namespace ICSharpCode.NRefactory.CSharp.Analysis
+{
+ ///
+ /// C# Semantic highlighter.
+ ///
+ public abstract class SemanticHighlightingVisitor : DepthFirstAstVisitor
+ {
+ protected CancellationToken cancellationToken = default (CancellationToken);
+
+ protected TColor defaultTextColor;
+ protected TColor referenceTypeColor;
+ protected TColor valueTypeColor;
+ protected TColor interfaceTypeColor;
+ protected TColor enumerationTypeColor;
+ protected TColor typeParameterTypeColor;
+ protected TColor delegateTypeColor;
+
+ protected TColor methodCallColor;
+ protected TColor methodDeclarationColor;
+
+ protected TColor eventDeclarationColor;
+ protected TColor eventAccessColor;
+
+ protected TColor propertyDeclarationColor;
+ protected TColor propertyAccessColor;
+
+ protected TColor fieldDeclarationColor;
+ protected TColor fieldAccessColor;
+
+ protected TColor variableDeclarationColor;
+ protected TColor variableAccessColor;
+
+ protected TColor parameterDeclarationColor;
+ protected TColor parameterAccessColor;
+
+ protected TColor valueKeywordColor;
+ protected TColor externAliasKeywordColor;
+ protected TColor varKeywordTypeColor;
+
+ ///
+ /// Used for 'in' modifiers on type parameters.
+ ///
+ ///
+ /// 'in' may have a different color when used with 'foreach'.
+ /// 'out' is not colored by semantic highlighting, as syntax highlighting can already detect it as a parameter modifier.
+ ///
+ protected TColor parameterModifierColor;
+
+ ///
+ /// Used for inactive code (excluded by preprocessor or ConditionalAttribute)
+ ///
+ protected TColor inactiveCodeColor;
+
+ protected TColor stringFormatItemColor;
+
+
+ protected TColor syntaxErrorColor;
+
+ protected TextLocation regionStart;
+ protected TextLocation regionEnd;
+
+ protected CSharpAstResolver resolver;
+ bool isInAccessorContainingValueParameter;
+
+ protected abstract void Colorize(TextLocation start, TextLocation end, TColor color);
+
+ #region Colorize helper methods
+ protected void Colorize(Identifier identifier, ResolveResult rr)
+ {
+ if (identifier.IsNull)
+ return;
+ if (rr.IsError) {
+ Colorize(identifier, syntaxErrorColor);
+ return;
+ }
+ if (rr is TypeResolveResult) {
+ if (blockDepth > 0 && identifier.Name == "var" && rr.Type.Kind != TypeKind.Null && rr.Type.Name != "var" ) {
+ Colorize(identifier, varKeywordTypeColor);
+ return;
+ }
+
+ TColor color;
+ if (TryGetTypeHighlighting (rr.Type.Kind, out color)) {
+ Colorize(identifier, color);
+ }
+ return;
+ }
+ var mrr = rr as MemberResolveResult;
+ if (mrr != null) {
+ TColor color;
+ if (TryGetMemberColor (mrr.Member, out color)) {
+ Colorize(identifier, color);
+ return;
+ }
+ }
+
+ if (rr is MethodGroupResolveResult) {
+ Colorize (identifier, methodCallColor);
+ return;
+ }
+
+ var localResult = rr as LocalResolveResult;
+ if (localResult != null) {
+ if (localResult.Variable is IParameter) {
+ Colorize (identifier, parameterAccessColor);
+ } else {
+ Colorize (identifier, variableAccessColor);
+ }
+ }
+
+
+ VisitIdentifier(identifier); // un-colorize contextual keywords
+ }
+
+ protected void Colorize(AstNode node, TColor color)
+ {
+ if (node.IsNull)
+ return;
+ Colorize(node.StartLocation, node.EndLocation, color);
+ }
+ #endregion
+
+ protected override void VisitChildren(AstNode node)
+ {
+ for (var child = node.FirstChild; child != null; child = child.NextSibling) {
+ if (child.StartLocation < regionEnd && child.EndLocation > regionStart)
+ child.AcceptVisitor(this);
+ }
+ }
+
+ ///
+ /// Visit all children of node until (but excluding) end.
+ /// If end is a null node, nothing will be visited.
+ ///
+ protected void VisitChildrenUntil(AstNode node, AstNode end)
+ {
+ if (end.IsNull)
+ return;
+ Debug.Assert(node == end.Parent);
+ for (var child = node.FirstChild; child != end; child = child.NextSibling) {
+ cancellationToken.ThrowIfCancellationRequested();
+ if (child.StartLocation < regionEnd && child.EndLocation > regionStart)
+ child.AcceptVisitor(this);
+ }
+ }
+
+ ///
+ /// Visit all children of node after (excluding) start.
+ /// If start is a null node, all children will be visited.
+ ///
+ protected void VisitChildrenAfter(AstNode node, AstNode start)
+ {
+ Debug.Assert(start.IsNull || start.Parent == node);
+ for (var child = (start.IsNull ? node.FirstChild : start.NextSibling); child != null; child = child.NextSibling) {
+ cancellationToken.ThrowIfCancellationRequested();
+ if (child.StartLocation < regionEnd && child.EndLocation > regionStart)
+ child.AcceptVisitor(this);
+ }
+ }
+
+ public override void VisitIdentifier(Identifier identifier)
+ {
+ switch (identifier.Name) {
+ case "add":
+ case "async":
+ case "await":
+ case "get":
+ case "partial":
+ case "remove":
+ case "set":
+ case "where":
+ case "yield":
+ case "from":
+ case "select":
+ case "group":
+ case "into":
+ case "orderby":
+ case "join":
+ case "let":
+ case "on":
+ case "equals":
+ case "by":
+ case "ascending":
+ case "descending":
+ case "dynamic":
+ case "var":
+ // Reset color of contextual keyword to default if it's used as an identifier.
+ // Note that this method does not get called when 'var' or 'dynamic' is used as a type,
+ // because types get highlighted with valueTypeColor/referenceTypeColor instead.
+ Colorize(identifier, defaultTextColor);
+ break;
+ case "global":
+ // Reset color of 'global' keyword to default unless its used as part of 'global::'.
+ MemberType parentMemberType = identifier.Parent as MemberType;
+ if (parentMemberType == null || !parentMemberType.IsDoubleColon)
+ Colorize(identifier, defaultTextColor);
+ break;
+ }
+ // "value" is handled in VisitIdentifierExpression()
+ // "alias" is handled in VisitExternAliasDeclaration()
+ }
+
+ public override void VisitSimpleType(SimpleType simpleType)
+ {
+ var identifierToken = simpleType.IdentifierToken;
+ VisitChildrenUntil(simpleType, identifierToken);
+ Colorize(identifierToken, resolver.Resolve(simpleType, cancellationToken));
+ VisitChildrenAfter(simpleType, identifierToken);
+ }
+
+ public override void VisitMemberType(MemberType memberType)
+ {
+ var memberNameToken = memberType.MemberNameToken;
+ VisitChildrenUntil(memberType, memberNameToken);
+ Colorize(memberNameToken, resolver.Resolve(memberType, cancellationToken));
+ VisitChildrenAfter(memberType, memberNameToken);
+ }
+
+ public override void VisitIdentifierExpression(IdentifierExpression identifierExpression)
+ {
+ var identifier = identifierExpression.IdentifierToken;
+ VisitChildrenUntil(identifierExpression, identifier);
+ if (isInAccessorContainingValueParameter && identifierExpression.Identifier == "value") {
+ Colorize(identifier, valueKeywordColor);
+ } else {
+ Colorize(identifier, resolver.Resolve(identifierExpression, cancellationToken));
+ }
+ VisitChildrenAfter(identifierExpression, identifier);
+ }
+
+ public override void VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression)
+ {
+ var memberNameToken = memberReferenceExpression.MemberNameToken;
+ VisitChildrenUntil(memberReferenceExpression, memberNameToken);
+ ResolveResult rr = resolver.Resolve(memberReferenceExpression, cancellationToken);
+ Colorize(memberNameToken, rr);
+ VisitChildrenAfter(memberReferenceExpression, memberNameToken);
+ }
+
+ void HighlightStringFormatItems(PrimitiveExpression expr)
+ {
+ if (!(expr.Value is string))
+ return;
+ int line = expr.StartLocation.Line;
+ int col = expr.StartLocation.Column;
+ TextLocation start = TextLocation.Empty;
+ for (int i = 0; i < expr.LiteralValue.Length; i++) {
+ char ch = expr.LiteralValue [i];
+
+ if (NewLine.GetDelimiterType(ch, i + 1 < expr.LiteralValue.Length ? expr.LiteralValue [i + 1] : '\0') != UnicodeNewline.Unknown) {
+ line++;
+ col = 1;
+ continue;
+ }
+
+
+ if (ch == '{' && start.IsEmpty) {
+ char next = i + 1 < expr.LiteralValue.Length ? expr.LiteralValue [i + 1] : '\0';
+ if (next == '{') {
+ i++;
+ col += 2;
+ continue;
+ }
+ start = new TextLocation(line, col);
+ }
+ col++;
+ if (ch == '}' &&!start.IsEmpty) {
+ char next = i + 1 < expr.LiteralValue.Length ? expr.LiteralValue [i + 1] : '\0';
+ if (next == '}') {
+ i++;
+ col += 2;
+ continue;
+ }
+ Colorize(start, new TextLocation(line, col), stringFormatItemColor);
+ start = TextLocation.Empty;
+ }
+ }
+
+ }
+
+ public override void VisitInvocationExpression(InvocationExpression invocationExpression)
+ {
+ Expression target = invocationExpression.Target;
+ if (target is IdentifierExpression || target is MemberReferenceExpression || target is PointerReferenceExpression) {
+ var invocationRR = resolver.Resolve(invocationExpression, cancellationToken) as CSharpInvocationResolveResult;
+ if (invocationRR != null) {
+ if (invocationExpression.Parent is ExpressionStatement && (IsInactiveConditionalMethod(invocationRR.Member) || IsEmptyPartialMethod(invocationRR.Member))) {
+ // mark the whole invocation statement as inactive code
+ Colorize(invocationExpression.Parent, inactiveCodeColor);
+ return;
+ }
+
+ Expression fmtArgumets;
+ IList args;
+ if (invocationRR.Arguments.Count > 1 && FormatStringHelper.TryGetFormattingParameters(invocationRR, invocationExpression, out fmtArgumets, out args, null)) {
+ var expr = invocationExpression.Arguments.First() as PrimitiveExpression;
+ if (expr != null)
+ HighlightStringFormatItems(expr);
+ }
+ }
+
+ VisitChildrenUntil(invocationExpression, target);
+
+ // highlight the method call
+ var identifier = target.GetChildByRole(Roles.Identifier);
+ VisitChildrenUntil(target, identifier);
+ if (invocationRR != null && !invocationRR.IsDelegateInvocation) {
+ Colorize(identifier, methodCallColor);
+ } else {
+ ResolveResult targetRR = resolver.Resolve(target, cancellationToken);
+ Colorize(identifier, targetRR);
+ }
+ VisitChildrenAfter(target, identifier);
+ VisitChildrenAfter(invocationExpression, target);
+ } else {
+ VisitChildren(invocationExpression);
+ }
+ }
+
+ #region IsInactiveConditional helper methods
+ bool IsInactiveConditionalMethod(IParameterizedMember member)
+ {
+ if (member.SymbolKind != SymbolKind.Method || member.ReturnType.Kind != TypeKind.Void)
+ return false;
+ foreach (var baseMember in InheritanceHelper.GetBaseMembers(member, false)) {
+ if (IsInactiveConditional (baseMember.Attributes))
+ return true;
+ }
+ return IsInactiveConditional(member.Attributes);
+ }
+
+ static bool IsEmptyPartialMethod(IParameterizedMember member)
+ {
+ if (member.SymbolKind != SymbolKind.Method || member.ReturnType.Kind != TypeKind.Void)
+ return false;
+ var method = (IMethod)member;
+ return method.IsPartial && !method.HasBody;
+ }
+
+ bool IsInactiveConditional(IList attributes)
+ {
+ bool hasConditionalAttribute = false;
+ foreach (var attr in attributes) {
+ if (attr.AttributeType.Name == "ConditionalAttribute" && attr.AttributeType.Namespace == "System.Diagnostics" && attr.PositionalArguments.Count == 1) {
+ string symbol = attr.PositionalArguments[0].ConstantValue as string;
+ if (symbol != null) {
+ hasConditionalAttribute = true;
+ var cu = this.resolver.RootNode as SyntaxTree;
+ if (cu != null) {
+ if (cu.ConditionalSymbols.Contains(symbol))
+ return false; // conditional is active
+ }
+ }
+ }
+ }
+
+ return hasConditionalAttribute;
+ }
+ #endregion
+
+ public override void VisitExternAliasDeclaration (ExternAliasDeclaration externAliasDeclaration)
+ {
+ var aliasToken = externAliasDeclaration.AliasToken;
+ VisitChildrenUntil(externAliasDeclaration, aliasToken);
+ Colorize (aliasToken, externAliasKeywordColor);
+ VisitChildrenAfter(externAliasDeclaration, aliasToken);
+ }
+
+ public override void VisitAccessor(Accessor accessor)
+ {
+ isInAccessorContainingValueParameter = accessor.Role != PropertyDeclaration.GetterRole;
+ try {
+ VisitChildren(accessor);
+ } finally {
+ isInAccessorContainingValueParameter = false;
+ }
+ }
+
+ bool CheckInterfaceImplementation (EntityDeclaration entityDeclaration)
+ {
+ var result = resolver.Resolve (entityDeclaration, cancellationToken) as MemberResolveResult;
+ if (result == null)
+ return false;
+ if (result.Member.ImplementedInterfaceMembers.Count == 0) {
+ Colorize (entityDeclaration.NameToken, syntaxErrorColor);
+ return false;
+ }
+ return true;
+ }
+
+ public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration)
+ {
+ var nameToken = methodDeclaration.NameToken;
+ VisitChildrenUntil(methodDeclaration, nameToken);
+ if (!methodDeclaration.PrivateImplementationType.IsNull) {
+ if (!CheckInterfaceImplementation (methodDeclaration)) {
+ VisitChildrenAfter(methodDeclaration, nameToken);
+ return;
+ }
+ }
+ Colorize(nameToken, methodDeclarationColor);
+ VisitChildrenAfter(methodDeclaration, nameToken);
+ }
+
+ public override void VisitParameterDeclaration(ParameterDeclaration parameterDeclaration)
+ {
+ var nameToken = parameterDeclaration.NameToken;
+ VisitChildrenUntil(parameterDeclaration, nameToken);
+ Colorize(nameToken, parameterDeclarationColor);
+ VisitChildrenAfter(parameterDeclaration, nameToken);
+ }
+
+ public override void VisitEventDeclaration(EventDeclaration eventDeclaration)
+ {
+ var nameToken = eventDeclaration.NameToken;
+ VisitChildrenUntil(eventDeclaration, nameToken);
+ Colorize(nameToken, eventDeclarationColor);
+ VisitChildrenAfter(eventDeclaration, nameToken);
+ }
+
+ public override void VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration)
+ {
+ var nameToken = eventDeclaration.NameToken;
+ VisitChildrenUntil(eventDeclaration, nameToken);
+ if (!eventDeclaration.PrivateImplementationType.IsNull) {
+ if (!CheckInterfaceImplementation (eventDeclaration)) {
+ VisitChildrenAfter(eventDeclaration, nameToken);
+ return;
+ }
+ }
+ Colorize(nameToken, eventDeclarationColor);
+ VisitChildrenAfter(eventDeclaration, nameToken);
+ }
+
+ public override void VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration)
+ {
+ var nameToken = propertyDeclaration.NameToken;
+ VisitChildrenUntil(propertyDeclaration, nameToken);
+ if (!propertyDeclaration.PrivateImplementationType.IsNull) {
+ if (!CheckInterfaceImplementation (propertyDeclaration)) {
+ VisitChildrenAfter(propertyDeclaration, nameToken);
+ return;
+ }
+ }
+ Colorize(nameToken, propertyDeclarationColor);
+ VisitChildrenAfter(propertyDeclaration, nameToken);
+ }
+
+ public override void VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration)
+ {
+ base.VisitIndexerDeclaration(indexerDeclaration);
+ if (!indexerDeclaration.PrivateImplementationType.IsNull) {
+ CheckInterfaceImplementation (indexerDeclaration);
+ }
+ }
+
+ public override void VisitFieldDeclaration(FieldDeclaration fieldDeclaration)
+ {
+ fieldDeclaration.ReturnType.AcceptVisitor (this);
+ foreach (var init in fieldDeclaration.Variables) {
+ Colorize (init.NameToken, fieldDeclarationColor);
+ init.Initializer.AcceptVisitor (this);
+ }
+ }
+
+ public override void VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration)
+ {
+ fixedFieldDeclaration.ReturnType.AcceptVisitor (this);
+ foreach (var init in fixedFieldDeclaration.Variables) {
+ Colorize (init.NameToken, fieldDeclarationColor);
+ init.CountExpression.AcceptVisitor (this);
+ }
+ }
+
+ public override void VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration)
+ {
+ HandleConstructorOrDestructor(constructorDeclaration);
+ }
+
+ public override void VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration)
+ {
+ HandleConstructorOrDestructor(destructorDeclaration);
+ }
+
+ void HandleConstructorOrDestructor(AstNode constructorDeclaration)
+ {
+ Identifier nameToken = constructorDeclaration.GetChildByRole(Roles.Identifier);
+ VisitChildrenUntil(constructorDeclaration, nameToken);
+ var currentTypeDef = resolver.GetResolverStateBefore(constructorDeclaration).CurrentTypeDefinition;
+ if (currentTypeDef != null && nameToken.Name == currentTypeDef.Name) {
+ TColor color;
+ if (TryGetTypeHighlighting (currentTypeDef.Kind, out color))
+ Colorize(nameToken, color);
+ }
+ VisitChildrenAfter(constructorDeclaration, nameToken);
+ }
+
+ bool TryGetMemberColor(IMember member, out TColor color)
+ {
+ switch (member.SymbolKind) {
+ case SymbolKind.Field:
+ color = fieldAccessColor;
+ return true;
+ case SymbolKind.Property:
+ color = propertyAccessColor;
+ return true;
+ case SymbolKind.Event:
+ color = eventAccessColor;
+ return true;
+ case SymbolKind.Method:
+ color = methodCallColor;
+ return true;
+ case SymbolKind.Constructor:
+ case SymbolKind.Destructor:
+ return TryGetTypeHighlighting (member.DeclaringType.Kind, out color);
+ default:
+ color = default (TColor);
+ return false;
+ }
+ }
+
+ TColor GetTypeHighlighting (ClassType classType)
+ {
+ switch (classType) {
+ case ClassType.Class:
+ return referenceTypeColor;
+ case ClassType.Struct:
+ return valueTypeColor;
+ case ClassType.Interface:
+ return interfaceTypeColor;
+ case ClassType.Enum:
+ return enumerationTypeColor;
+ default:
+ throw new InvalidOperationException ("Unknown class type :" + classType);
+ }
+ }
+
+ bool TryGetTypeHighlighting (TypeKind kind, out TColor color)
+ {
+ switch (kind) {
+ case TypeKind.Class:
+ color = referenceTypeColor;
+ return true;
+ case TypeKind.Struct:
+ color = valueTypeColor;
+ return true;
+ case TypeKind.Interface:
+ color = interfaceTypeColor;
+ return true;
+ case TypeKind.Enum:
+ color = enumerationTypeColor;
+ return true;
+ case TypeKind.TypeParameter:
+ color = typeParameterTypeColor;
+ return true;
+ case TypeKind.Delegate:
+ color = delegateTypeColor;
+ return true;
+ case TypeKind.Unknown:
+ case TypeKind.Null:
+ color = syntaxErrorColor;
+ return true;
+ default:
+ color = default (TColor);
+ return false;
+ }
+ }
+
+ public override void VisitTypeDeclaration(TypeDeclaration typeDeclaration)
+ {
+ var nameToken = typeDeclaration.NameToken;
+ VisitChildrenUntil(typeDeclaration, nameToken);
+ Colorize(nameToken, GetTypeHighlighting (typeDeclaration.ClassType));
+ VisitChildrenAfter(typeDeclaration, nameToken);
+ }
+
+ public override void VisitTypeParameterDeclaration(TypeParameterDeclaration typeParameterDeclaration)
+ {
+ if (typeParameterDeclaration.Variance == VarianceModifier.Contravariant)
+ Colorize(typeParameterDeclaration.VarianceToken, parameterModifierColor);
+
+ // bool isValueType = false;
+ // if (typeParameterDeclaration.Parent != null) {
+ // foreach (var constraint in typeParameterDeclaration.Parent.GetChildrenByRole(Roles.Constraint)) {
+ // if (constraint.TypeParameter.Identifier == typeParameterDeclaration.Name) {
+ // isValueType = constraint.BaseTypes.OfType().Any(p => p.Keyword == "struct");
+ // }
+ // }
+ // }
+ var nameToken = typeParameterDeclaration.NameToken;
+ VisitChildrenUntil(typeParameterDeclaration, nameToken);
+ Colorize(nameToken, typeParameterTypeColor); /*isValueType ? valueTypeColor : referenceTypeColor*/
+ VisitChildrenAfter(typeParameterDeclaration, nameToken);
+ }
+
+ public override void VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration)
+ {
+ var nameToken = delegateDeclaration.NameToken;
+ VisitChildrenUntil(delegateDeclaration, nameToken);
+ Colorize(nameToken, delegateTypeColor);
+ VisitChildrenAfter(delegateDeclaration, nameToken);
+ }
+
+ public override void VisitVariableInitializer(VariableInitializer variableInitializer)
+ {
+ var nameToken = variableInitializer.NameToken;
+ VisitChildrenUntil(variableInitializer, nameToken);
+ if (variableInitializer.Parent is FieldDeclaration) {
+ Colorize(nameToken, fieldDeclarationColor);
+ } else if (variableInitializer.Parent is EventDeclaration) {
+ Colorize(nameToken, eventDeclarationColor);
+ } else {
+ Colorize(nameToken, variableDeclarationColor);
+ }
+ VisitChildrenAfter(variableInitializer, nameToken);
+ }
+
+ public override void VisitComment(Comment comment)
+ {
+ if (comment.CommentType == CommentType.InactiveCode) {
+ Colorize(comment, inactiveCodeColor);
+ }
+ }
+
+ public override void VisitPreProcessorDirective(PreProcessorDirective preProcessorDirective)
+ {
+ }
+
+ public override void VisitAttribute(ICSharpCode.NRefactory.CSharp.Attribute attribute)
+ {
+ ITypeDefinition attrDef = resolver.Resolve(attribute.Type, cancellationToken).Type.GetDefinition();
+ if (attrDef != null && IsInactiveConditional(attrDef.Attributes)) {
+ Colorize(attribute, inactiveCodeColor);
+ } else {
+ VisitChildren(attribute);
+ }
+ }
+
+ public override void VisitArrayInitializerExpression (ArrayInitializerExpression arrayInitializerExpression)
+ {
+ foreach (var a in arrayInitializerExpression.Elements) {
+ var namedElement = a as NamedExpression;
+ if (namedElement != null) {
+ var result = resolver.Resolve (namedElement, cancellationToken);
+ if (result.IsError)
+ Colorize (namedElement.NameToken, syntaxErrorColor);
+ namedElement.Expression.AcceptVisitor (this);
+ } else {
+ a.AcceptVisitor (this);
+ }
+ }
+ }
+
+ int blockDepth;
+ public override void VisitBlockStatement(BlockStatement blockStatement)
+ {
+ blockDepth++;
+ base.VisitBlockStatement(blockStatement);
+ blockDepth--;
+ }
+ }
+}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs
index 5d73c90db..8676beb67 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs
@@ -31,10 +31,11 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
+using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp
{
- public abstract class AstNode : AbstractAnnotatable, ICSharpCode.NRefactory.TypeSystem.IFreezable, PatternMatching.INode
+ public abstract class AstNode : AbstractAnnotatable, ICSharpCode.NRefactory.TypeSystem.IFreezable, PatternMatching.INode, ICloneable
{
// the Root role must be available when creating the null nodes, so we can't put it in the Roles class
internal static readonly Role RootRole = new Role ("Root");
@@ -58,16 +59,17 @@ namespace ICSharpCode.NRefactory.CSharp
public override void AcceptVisitor (IAstVisitor visitor)
{
+ visitor.VisitNullNode(this);
}
public override T AcceptVisitor (IAstVisitor visitor)
{
- return default (T);
+ return visitor.VisitNullNode(this);
}
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
- return default (S);
+ return visitor.VisitNullNode(this, data);
}
protected internal override bool DoMatch (AstNode other, PatternMatching.Match match)
@@ -192,6 +194,12 @@ namespace ICSharpCode.NRefactory.CSharp
return child.EndLocation;
}
}
+
+ public DomRegion Region {
+ get {
+ return new DomRegion (StartLocation, EndLocation);
+ }
+ }
///
/// Gets the region from StartLocation to EndLocation for this node.
@@ -223,6 +231,10 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
+ internal uint RoleIndex {
+ get { return flags & roleIndexMask; }
+ }
+
void SetRole(Role role)
{
flags = (flags & ~roleIndexMask) | role.Index;
@@ -286,31 +298,67 @@ namespace ICSharpCode.NRefactory.CSharp
}
///
- /// Gets all descendants of this node (excluding this node itself).
+ /// Gets all descendants of this node (excluding this node itself) in pre-order.
///
public IEnumerable Descendants {
- get { return GetDescendants(false); }
+ get { return GetDescendantsImpl(false); }
}
///
- /// Gets all descendants of this node (including this node itself).
+ /// Gets all descendants of this node (including this node itself) in pre-order.
///
public IEnumerable DescendantsAndSelf {
- get { return GetDescendants(true); }
+ get { return GetDescendantsImpl(true); }
}
-
- IEnumerable GetDescendants(bool includeSelf)
+
+ static bool IsInsideRegion(DomRegion region, AstNode pos)
+ {
+ if (region.IsEmpty)
+ return true;
+ var nodeRegion = pos.Region;
+ return region.IntersectsWith(nodeRegion) || region.OverlapsWith(nodeRegion);
+ }
+
+ public IEnumerable DescendantNodes (Func descendIntoChildren = null)
{
- if (includeSelf)
- yield return this;
+ return GetDescendantsImpl(false, new DomRegion (), descendIntoChildren);
+ }
+
+ public IEnumerable DescendantNodes (DomRegion region, Func descendIntoChildren = null)
+ {
+ return GetDescendantsImpl(false, region, descendIntoChildren);
+ }
+
+ public IEnumerable DescendantNodesAndSelf (Func descendIntoChildren = null)
+ {
+ return GetDescendantsImpl(true, new DomRegion (), descendIntoChildren);
+ }
+
+ public IEnumerable DescendantNodesAndSelf (DomRegion region, Func descendIntoChildren = null)
+ {
+ return GetDescendantsImpl(true, region, descendIntoChildren);
+ }
+
+ IEnumerable GetDescendantsImpl(bool includeSelf, DomRegion region = new DomRegion (), Func descendIntoChildren = null)
+ {
+ if (includeSelf) {
+ if (IsInsideRegion (region, this))
+ yield return this;
+ if (descendIntoChildren != null && !descendIntoChildren(this))
+ yield break;
+ }
+
Stack nextStack = new Stack();
nextStack.Push(null);
AstNode pos = firstChild;
while (pos != null) {
+ // Remember next before yielding pos.
+ // This allows removing/replacing nodes while iterating through the list.
if (pos.nextSibling != null)
nextStack.Push(pos.nextSibling);
- yield return pos;
- if (pos.firstChild != null)
+ if (IsInsideRegion(region, pos))
+ yield return pos;
+ if (pos.firstChild != null && (descendIntoChildren == null || descendIntoChildren(pos)))
pos = pos.firstChild;
else
pos = nextStack.Pop();
@@ -337,7 +385,12 @@ namespace ICSharpCode.NRefactory.CSharp
{
return Ancestors.OfType().FirstOrDefault();
}
-
+
+ public AstNode GetParent(Func pred)
+ {
+ return Ancestors.FirstOrDefault(pred);
+ }
+
public AstNodeCollection GetChildrenByRole (Role role) where T : AstNode
{
return new AstNodeCollection (this, role);
@@ -359,6 +412,8 @@ namespace ICSharpCode.NRefactory.CSharp
if (child == null || child.IsNull)
return;
ThrowIfFrozen();
+ if (child == this)
+ throw new ArgumentException ("Cannot add a node to itself as a child.", "child");
if (child.parent != null)
throw new ArgumentException ("Node is already used in another tree.", "child");
if (child.IsFrozen)
@@ -366,10 +421,24 @@ namespace ICSharpCode.NRefactory.CSharp
AddChildUnsafe (child, role);
}
+ public void AddChildWithExistingRole (AstNode child)
+ {
+ if (child == null || child.IsNull)
+ return;
+ ThrowIfFrozen();
+ if (child == this)
+ throw new ArgumentException ("Cannot add a node to itself as a child.", "child");
+ if (child.parent != null)
+ throw new ArgumentException ("Node is already used in another tree.", "child");
+ if (child.IsFrozen)
+ throw new ArgumentException ("Cannot add a frozen node.", "child");
+ AddChildUnsafe (child, child.Role);
+ }
+
///
/// Adds a child without performing any safety checks.
///
- void AddChildUnsafe (AstNode child, Role role)
+ internal void AddChildUnsafe (AstNode child, Role role)
{
child.parent = this;
child.SetRole(role);
@@ -405,7 +474,7 @@ namespace ICSharpCode.NRefactory.CSharp
InsertChildBeforeUnsafe (nextSibling, child, role);
}
- void InsertChildBeforeUnsafe (AstNode nextSibling, AstNode child, Role role)
+ internal void InsertChildBeforeUnsafe (AstNode nextSibling, AstNode child, Role role)
{
child.parent = this;
child.SetRole(role);
@@ -566,6 +635,11 @@ namespace ICSharpCode.NRefactory.CSharp
return copy;
}
+ object ICloneable.Clone()
+ {
+ return Clone();
+ }
+
public abstract void AcceptVisitor (IAstVisitor visitor);
public abstract T AcceptVisitor (IAstVisitor visitor);
@@ -612,6 +686,19 @@ namespace ICSharpCode.NRefactory.CSharp
return null;
}
+ ///
+ /// Gets the next node which fullfills a given predicate
+ ///
+ /// The next node.
+ /// The predicate.
+ public AstNode GetNextNode (Func pred)
+ {
+ var next = GetNextNode();
+ while (next != null && !pred (next))
+ next = next.GetNextNode();
+ return next;
+ }
+
public AstNode GetPrevNode ()
{
if (PrevSibling != null)
@@ -620,6 +707,19 @@ namespace ICSharpCode.NRefactory.CSharp
return Parent.GetPrevNode ();
return null;
}
+
+ ///
+ /// Gets the previous node which fullfills a given predicate
+ ///
+ /// The next node.
+ /// The predicate.
+ public AstNode GetPrevNode (Func pred)
+ {
+ var prev = GetPrevNode();
+ while (prev != null && !pred (prev))
+ prev = prev.GetPrevNode();
+ return prev;
+ }
// filters all non c# nodes (comments, white spaces or pre processor directives)
public AstNode GetCSharpNodeBefore (AstNode node)
{
@@ -631,6 +731,32 @@ namespace ICSharpCode.NRefactory.CSharp
}
return null;
}
+
+ ///
+ /// Gets the next sibling which fullfills a given predicate
+ ///
+ /// The next node.
+ /// The predicate.
+ public AstNode GetNextSibling (Func pred)
+ {
+ var next = NextSibling;
+ while (next != null && !pred (next))
+ next = next.NextSibling;
+ return next;
+ }
+
+ ///
+ /// Gets the next sibling which fullfills a given predicate
+ ///
+ /// The next node.
+ /// The predicate.
+ public AstNode GetPrevSibling (Func pred)
+ {
+ var prev = PrevSibling;
+ while (prev != null && !pred (prev))
+ prev = prev.PrevSibling;
+ return prev;
+ }
#region GetNodeAt
///
@@ -652,20 +778,18 @@ namespace ICSharpCode.NRefactory.CSharp
{
AstNode result = null;
AstNode node = this;
- while (node.FirstChild != null) {
- var child = node.FirstChild;
- while (child != null) {
- if (child.StartLocation <= location && location < child.EndLocation) {
- if (pred == null || pred (child))
- result = child;
- node = child;
- break;
- }
- child = child.NextSibling;
- }
- // found no better child node - therefore the parent is the right one.
- if (child == null)
+ while (node.LastChild != null) {
+ var child = node.LastChild;
+ while (child != null && child.StartLocation > location)
+ child = child.prevSibling;
+ if (child != null && location < child.EndLocation) {
+ if (pred == null || pred (child))
+ result = child;
+ node = child;
+ } else {
+ // found no better child node - therefore the parent is the right one.
break;
+ }
}
return result;
}
@@ -689,20 +813,18 @@ namespace ICSharpCode.NRefactory.CSharp
{
T result = null;
AstNode node = this;
- while (node.FirstChild != null) {
- var child = node.FirstChild;
- while (child != null) {
- if (child.StartLocation <= location && location < child.EndLocation) {
- if (child is T)
- result = (T)child;
- node = child;
- break;
- }
- child = child.NextSibling;
- }
- // found no better child node - therefore the parent is the right one.
- if (child == null)
+ while (node.LastChild != null) {
+ var child = node.LastChild;
+ while (child != null && child.StartLocation > location)
+ child = child.prevSibling;
+ if (child != null && location < child.EndLocation) {
+ if (child is T)
+ result = (T)child;
+ node = child;
+ } else {
+ // found no better child node - therefore the parent is the right one.
break;
+ }
}
return result;
}
@@ -729,20 +851,18 @@ namespace ICSharpCode.NRefactory.CSharp
{
AstNode result = null;
AstNode node = this;
- while (node.FirstChild != null) {
- var child = node.FirstChild;
- while (child != null) {
- if (child.StartLocation <= location && location <= child.EndLocation) {
- if (pred == null || pred (child))
- result = child;
- node = child;
- break;
- }
- child = child.NextSibling;
- }
- // found no better child node - therefore the parent is the right one.
- if (child == null)
+ while (node.LastChild != null) {
+ var child = node.LastChild;
+ while (child != null && child.StartLocation > location)
+ child = child.prevSibling;
+ if (child != null && location <= child.EndLocation) {
+ if (pred == null || pred (child))
+ result = child;
+ node = child;
+ } else {
+ // found no better child node - therefore the parent is the right one.
break;
+ }
}
return result;
}
@@ -766,20 +886,18 @@ namespace ICSharpCode.NRefactory.CSharp
{
T result = null;
AstNode node = this;
- while (node.FirstChild != null) {
- var child = node.FirstChild;
- while (child != null) {
- if (child.StartLocation <= location && location < child.EndLocation) {
- if (child is T)
- result = (T)child;
- node = child;
- break;
- }
- child = child.NextSibling;
- }
- // found no better child node - therefore the parent is the right one.
- if (child == null)
+ while (node.LastChild != null) {
+ var child = node.LastChild;
+ while (child != null && child.StartLocation > location)
+ child = child.prevSibling;
+ if (child != null && location <= child.EndLocation) {
+ if (child is T)
+ result = (T)child;
+ node = child;
+ } else {
+ // found no better child node - therefore the parent is the right one.
break;
+ }
}
return result;
}
@@ -798,11 +916,17 @@ namespace ICSharpCode.NRefactory.CSharp
return this;
}
+ ///
+ /// Returns the root nodes of all subtrees that are fully contained in the specified region.
+ ///
public IEnumerable GetNodesBetween (int startLine, int startColumn, int endLine, int endColumn)
{
return GetNodesBetween (new TextLocation (startLine, startColumn), new TextLocation (endLine, endColumn));
}
+ ///
+ /// Returns the root nodes of all subtrees that are fully contained between and (inclusive).
+ ///
public IEnumerable GetNodesBetween (TextLocation start, TextLocation end)
{
AstNode node = this;
@@ -811,11 +935,11 @@ namespace ICSharpCode.NRefactory.CSharp
if (start <= node.StartLocation && node.EndLocation <= end) {
// Remember next before yielding node.
// This allows iteration to continue when the caller removes/replaces the node.
- next = node.NextSibling;
+ next = node.GetNextNode();
yield return node;
} else {
if (node.EndLocation <= start) {
- next = node.NextSibling;
+ next = node.GetNextNode();
} else {
next = node.FirstChild;
}
@@ -826,14 +950,19 @@ namespace ICSharpCode.NRefactory.CSharp
node = next;
}
}
-
+ [Obsolete("Use ToString(options).")]
+ public string GetText (CSharpFormattingOptions formattingOptions = null)
+ {
+ return ToString(formattingOptions);
+ }
+
///
/// Gets the node as formatted C# output.
///
///
/// Formatting options.
///
- public virtual string GetText (CSharpFormattingOptions formattingOptions = null)
+ public virtual string ToString (CSharpFormattingOptions formattingOptions)
{
if (IsNull)
return "";
@@ -841,7 +970,12 @@ namespace ICSharpCode.NRefactory.CSharp
AcceptVisitor (new CSharpOutputVisitor (w, formattingOptions ?? FormattingOptionsFactory.CreateMono ()));
return w.ToString ();
}
-
+
+ public sealed override string ToString()
+ {
+ return ToString(null);
+ }
+
///
/// Returns true, if the given coordinates (line, column) are in the node.
///
@@ -897,7 +1031,7 @@ namespace ICSharpCode.NRefactory.CSharp
{
if (IsNull)
return "Null";
- string text = GetText();
+ string text = ToString();
text = text.TrimEnd().Replace("\t", "").Replace(Environment.NewLine, " ");
if (text.Length > 100)
return text.Substring(0, 97) + "...";
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNodeCollection.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNodeCollection.cs
index b727dc211..32d08b2e4 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNodeCollection.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNodeCollection.cs
@@ -1,4 +1,4 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
+// Copyright (c) 2010-2013 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
@@ -28,7 +28,11 @@ namespace ICSharpCode.NRefactory.CSharp
///
/// Represents the children of an AstNode that have a specific role.
///
- public class AstNodeCollection : ICollection where T : AstNode
+ public class AstNodeCollection : ICollection
+ #if NET_4_5
+ , IReadOnlyCollection
+ #endif
+ where T : AstNode
{
readonly AstNode node;
readonly Role role;
@@ -46,8 +50,9 @@ namespace ICSharpCode.NRefactory.CSharp
public int Count {
get {
int count = 0;
+ uint roleIndex = role.Index;
for (AstNode cur = node.FirstChild; cur != null; cur = cur.NextSibling) {
- if (cur.Role == role)
+ if (cur.RoleIndex == roleIndex)
count++;
}
return count;
@@ -103,7 +108,7 @@ namespace ICSharpCode.NRefactory.CSharp
public bool Contains(T element)
{
- return element != null && element.Parent == node && element.Role == role;
+ return element != null && element.Parent == node && element.RoleIndex == role.Index;
}
public bool Remove(T element)
@@ -159,13 +164,14 @@ namespace ICSharpCode.NRefactory.CSharp
public IEnumerator GetEnumerator()
{
+ uint roleIndex = role.Index;
AstNode next;
for (AstNode cur = node.FirstChild; cur != null; cur = next) {
Debug.Assert(cur.Parent == node);
// Remember next before yielding cur.
// This allows removing/replacing nodes while iterating through the list.
next = cur.NextSibling;
- if (cur.Role == role)
+ if (cur.RoleIndex == roleIndex)
yield return (T)cur;
}
}
@@ -210,13 +216,14 @@ namespace ICSharpCode.NRefactory.CSharp
///
public void AcceptVisitor(IAstVisitor visitor)
{
+ uint roleIndex = role.Index;
AstNode next;
for (AstNode cur = node.FirstChild; cur != null; cur = next) {
Debug.Assert(cur.Parent == node);
// Remember next before yielding cur.
// This allows removing/replacing nodes while iterating through the list.
next = cur.NextSibling;
- if (cur.Role == role)
+ if (cur.RoleIndex == roleIndex)
cur.AcceptVisitor(visitor);
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstType.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstType.cs
index 022f3cc07..2f13f0fdd 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstType.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstType.cs
@@ -1,4 +1,4 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
+// Copyright (c) 2010-2013 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
@@ -41,16 +41,17 @@ namespace ICSharpCode.NRefactory.CSharp
public override void AcceptVisitor (IAstVisitor visitor)
{
+ visitor.VisitNullNode(this);
}
public override T AcceptVisitor (IAstVisitor visitor)
{
- return default (T);
+ return visitor.VisitNullNode(this);
}
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
- return default (S);
+ return visitor.VisitNullNode(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
@@ -58,7 +59,7 @@ namespace ICSharpCode.NRefactory.CSharp
return other == null || other.IsNull;
}
- public override ITypeReference ToTypeReference(NameLookupMode lookupMode)
+ public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider)
{
return SpecialType.UnknownType;
}
@@ -99,7 +100,7 @@ namespace ICSharpCode.NRefactory.CSharp
return visitor.VisitPatternPlaceholder (this, child, data);
}
- public override ITypeReference ToTypeReference(NameLookupMode lookupMode)
+ public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider)
{
throw new NotSupportedException();
}
@@ -125,8 +126,18 @@ namespace ICSharpCode.NRefactory.CSharp
return (AstType)base.Clone();
}
+ ///
+ /// Gets whether this type is a SimpleType "var".
+ ///
+ public bool IsVar()
+ {
+ SimpleType st = this as SimpleType;
+ return st != null && st.Identifier == "var" && st.TypeArguments.Count == 0;
+ }
+
///
/// Create an ITypeReference for this AstType.
+ /// Uses the context (ancestors of this node) to determine the correct .
///
///
/// The resulting type reference will read the context information from the
@@ -135,7 +146,42 @@ namespace ICSharpCode.NRefactory.CSharp
/// For resolving simple names, the current namespace and usings from the CurrentUsingScope
/// (on CSharpTypeResolveContext only) is used.
///
- public abstract ITypeReference ToTypeReference(NameLookupMode lookupMode = NameLookupMode.Type);
+ public ITypeReference ToTypeReference(InterningProvider interningProvider = null)
+ {
+ return ToTypeReference(GetNameLookupMode(), interningProvider);
+ }
+
+ ///
+ /// Create an ITypeReference for this AstType.
+ ///
+ ///
+ /// The resulting type reference will read the context information from the
+ /// :
+ /// For resolving type parameters, the CurrentTypeDefinition/CurrentMember is used.
+ /// For resolving simple names, the current namespace and usings from the CurrentUsingScope
+ /// (on CSharpTypeResolveContext only) is used.
+ ///
+ public abstract ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null);
+
+ ///
+ /// Gets the name lookup mode from the context (looking at the ancestors of this ).
+ ///
+ public NameLookupMode GetNameLookupMode()
+ {
+ AstType outermostType = this;
+ while (outermostType.Parent is AstType)
+ outermostType = (AstType)outermostType.Parent;
+
+ if (outermostType.Parent is UsingDeclaration || outermostType.Parent is UsingAliasDeclaration) {
+ return NameLookupMode.TypeInUsingDeclaration;
+ } else if (outermostType.Role == Roles.BaseType) {
+ // Use BaseTypeReference for a type's base type, and for a constraint on a type.
+ // Do not use it for a constraint on a method.
+ if (outermostType.Parent is TypeDeclaration || (outermostType.Parent is Constraint && outermostType.Parent.Parent is TypeDeclaration))
+ return NameLookupMode.BaseTypeReference;
+ }
+ return NameLookupMode.Type;
+ }
///
/// Creates a pointer type from this type by nesting it in a .
@@ -215,5 +261,20 @@ namespace ICSharpCode.NRefactory.CSharp
{
return new TypeReferenceExpression { Type = this }.Invoke(methodName, typeArguments, arguments);
}
+
+ ///
+ /// Creates a simple AstType from a dotted name.
+ /// Does not support generics, arrays, etc. - just simple dotted names,
+ /// e.g. namespace names.
+ ///
+ public static AstType Create(string dottedName)
+ {
+ string[] parts = dottedName.Split('.');
+ AstType type = new SimpleType(parts[0]);
+ for (int i = 1; i < parts.Length; i++) {
+ type = new MemberType(type, parts[i]);
+ }
+ return type;
+ }
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpModifierToken.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpModifierToken.cs
index ac59c7246..1a46006f2 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpModifierToken.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpModifierToken.cs
@@ -40,14 +40,14 @@ namespace ICSharpCode.NRefactory.CSharp
this.modifier = value;
}
}
-
- protected override int TokenLength {
+
+ public override TextLocation EndLocation {
get {
- return GetModifierName (modifier).Length;
+ return new TextLocation (StartLocation.Line, StartLocation.Column + GetModifierLength (Modifier));
}
}
-
- public override string GetText (CSharpFormattingOptions formattingOptions = null)
+
+ public override string ToString(CSharpFormattingOptions formattingOptions)
{
return GetModifierName (Modifier);
}
@@ -75,7 +75,7 @@ namespace ICSharpCode.NRefactory.CSharp
get { return allModifiers; }
}
- public CSharpModifierToken (TextLocation location, Modifiers modifier) : base (location)
+ public CSharpModifierToken (TextLocation location, Modifiers modifier) : base (location, null)
{
this.Modifier = modifier;
}
@@ -124,5 +124,95 @@ namespace ICSharpCode.NRefactory.CSharp
throw new NotSupportedException("Invalid value for Modifiers");
}
}
+
+ public static int GetModifierLength(Modifiers modifier)
+ {
+ switch (modifier) {
+ case Modifiers.Private:
+ return "private".Length;
+ case Modifiers.Internal:
+ return "internal".Length;
+ case Modifiers.Protected:
+ return "protected".Length;
+ case Modifiers.Public:
+ return "public".Length;
+ case Modifiers.Abstract:
+ return "abstract".Length;
+ case Modifiers.Virtual:
+ return "virtual".Length;
+ case Modifiers.Sealed:
+ return "sealed".Length;
+ case Modifiers.Static:
+ return "static".Length;
+ case Modifiers.Override:
+ return "override".Length;
+ case Modifiers.Readonly:
+ return "readonly".Length;
+ case Modifiers.Const:
+ return "const".Length;
+ case Modifiers.New:
+ return "new".Length;
+ case Modifiers.Partial:
+ return "partial".Length;
+ case Modifiers.Extern:
+ return "extern".Length;
+ case Modifiers.Volatile:
+ return "volatile".Length;
+ case Modifiers.Unsafe:
+ return "unsafe".Length;
+ case Modifiers.Async:
+ return "async".Length;
+ case Modifiers.Any:
+ // even though it's used for pattern matching only, 'any' needs to be in this list to be usable in the AST
+ return "any".Length;
+ default:
+ throw new NotSupportedException("Invalid value for Modifiers");
+ }
+ }
+
+ public static Modifiers GetModifierValue(string modifier)
+ {
+ switch (modifier) {
+ case "private":
+ return Modifiers.Private;
+ case "internal":
+ return Modifiers.Internal;
+ case "protected":
+ return Modifiers.Protected;
+ case "public":
+ return Modifiers.Public;
+ case "abstract":
+ return Modifiers.Abstract;
+ case "virtual":
+ return Modifiers.Virtual;
+ case "sealed":
+ return Modifiers.Sealed;
+ case "static":
+ return Modifiers.Static;
+ case "override":
+ return Modifiers.Override;
+ case "readonly":
+ return Modifiers.Readonly;
+ case "const":
+ return Modifiers.Const;
+ case "new":
+ return Modifiers.New;
+ case "partial":
+ return Modifiers.Partial;
+ case "extern":
+ return Modifiers.Extern;
+ case "volatile":
+ return Modifiers.Volatile;
+ case "unsafe":
+ return Modifiers.Unsafe;
+ case "async":
+ return Modifiers.Async;
+ case "any":
+ // even though it's used for pattern matching only, 'any' needs to be in this list to be usable in the AST
+ return Modifiers.Any;
+ default:
+ throw new NotSupportedException("Invalid value for Modifiers");
+ }
+ }
}
}
\ No newline at end of file
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpTokenNode.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpTokenNode.cs
index 04910ae18..713f664b3 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpTokenNode.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpTokenNode.cs
@@ -44,22 +44,23 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
- public NullCSharpTokenNode () : base (TextLocation.Empty)
+ public NullCSharpTokenNode () : base (TextLocation.Empty, null)
{
}
public override void AcceptVisitor (IAstVisitor visitor)
{
+ visitor.VisitNullNode(this);
}
-
+
public override T AcceptVisitor (IAstVisitor visitor)
{
- return default (T);
+ return visitor.VisitNullNode(this);
}
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
- return default (S);
+ return visitor.VisitNullNode(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
@@ -80,12 +81,10 @@ namespace ICSharpCode.NRefactory.CSharp
return startLocation;
}
}
-
- protected virtual int TokenLength {
+
+ int TokenLength {
get {
- if (!(Role is TokenRole))
- return 0;
- return ((TokenRole)Role).Length;
+ return TokenRole.TokenLengths [(int)(this.flags >> AstNodeFlagsUsedBits)];
}
}
@@ -94,17 +93,17 @@ namespace ICSharpCode.NRefactory.CSharp
return new TextLocation (StartLocation.Line, StartLocation.Column + TokenLength);
}
}
-
- public CSharpTokenNode (TextLocation location)
+
+ public CSharpTokenNode (TextLocation location, TokenRole role)
{
this.startLocation = location;
+ if (role != null)
+ this.flags |= role.TokenIndex << AstNodeFlagsUsedBits;
}
-
- public override string GetText (CSharpFormattingOptions formattingOptions = null)
+
+ public override string ToString(CSharpFormattingOptions formattingOptions)
{
- if (!(Role is TokenRole))
- return null;
- return ((TokenRole)Role).Token;
+ return TokenRole.Tokens [(int)(this.flags >> AstNodeFlagsUsedBits)];
}
public override void AcceptVisitor (IAstVisitor visitor)
@@ -127,11 +126,6 @@ namespace ICSharpCode.NRefactory.CSharp
CSharpTokenNode o = other as CSharpTokenNode;
return o != null && !o.IsNull && !(o is CSharpModifierToken);
}
-
- public override string ToString ()
- {
- return string.Format ("[CSharpTokenNode: StartLocation={0}, EndLocation={1}, Role={2}]", StartLocation, EndLocation, Role);
- }
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpUtil.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpUtil.cs
index e266c1a71..a2a07ad6e 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpUtil.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpUtil.cs
@@ -25,51 +25,87 @@
// THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.CSharp;
+using ICSharpCode.NRefactory.PatternMatching;
namespace ICSharpCode.NRefactory.CSharp
{
public static class CSharpUtil
{
- public static Expression InvertCondition (Expression condition)
+ ///
+ /// Inverts a boolean condition. Note: The condition object can be frozen (from AST) it's cloned internally.
+ ///
+ /// The condition to invert.
+ public static Expression InvertCondition(Expression condition)
{
- return InvertConditionInternal (condition.Clone ());
+ return InvertConditionInternal(condition);
}
- static Expression InvertConditionInternal (Expression condition)
+ static Expression InvertConditionInternal(Expression condition)
{
if (condition is ParenthesizedExpression) {
- ((ParenthesizedExpression)condition).Expression = InvertCondition (((ParenthesizedExpression)condition).Expression);
- return condition;
+ return new ParenthesizedExpression(InvertCondition(((ParenthesizedExpression)condition).Expression));
}
if (condition is UnaryOperatorExpression) {
var uOp = (UnaryOperatorExpression)condition;
- if (uOp.Operator == UnaryOperatorType.Not)
- return uOp.Expression;
- return new UnaryOperatorExpression (UnaryOperatorType.Not, uOp);
+ if (uOp.Operator == UnaryOperatorType.Not) {
+ if (!(uOp.Parent is Expression))
+ return GetInnerMostExpression(uOp.Expression).Clone();
+ return uOp.Expression.Clone();
+ }
+ return new UnaryOperatorExpression(UnaryOperatorType.Not, uOp.Clone());
}
if (condition is BinaryOperatorExpression) {
var bOp = (BinaryOperatorExpression)condition;
- var negatedOp = NegateRelationalOperator (bOp.Operator);
- if (negatedOp == BinaryOperatorType.Any)
- return new UnaryOperatorExpression (UnaryOperatorType.Not, new ParenthesizedExpression (condition));
- bOp.Operator = negatedOp;
- return bOp;
+
+ if ((bOp.Operator == BinaryOperatorType.ConditionalAnd) || (bOp.Operator == BinaryOperatorType.ConditionalOr)) {
+ return new BinaryOperatorExpression(InvertCondition(bOp.Left), NegateConditionOperator(bOp.Operator), InvertCondition(bOp.Right));
+ } else if ((bOp.Operator == BinaryOperatorType.Equality) || (bOp.Operator == BinaryOperatorType.InEquality) || (bOp.Operator == BinaryOperatorType.GreaterThan)
+ || (bOp.Operator == BinaryOperatorType.GreaterThanOrEqual) || (bOp.Operator == BinaryOperatorType.LessThan) ||
+ (bOp.Operator == BinaryOperatorType.LessThanOrEqual)) {
+ return new BinaryOperatorExpression(bOp.Left.Clone(), NegateRelationalOperator(bOp.Operator), bOp.Right.Clone());
+ } else {
+ var negatedOp = NegateRelationalOperator(bOp.Operator);
+ if (negatedOp == BinaryOperatorType.Any)
+ return new UnaryOperatorExpression(UnaryOperatorType.Not, new ParenthesizedExpression(condition.Clone()));
+ bOp = (BinaryOperatorExpression)bOp.Clone();
+ bOp.Operator = negatedOp;
+ return bOp;
+ }
}
if (condition is ConditionalExpression) {
- var cEx = condition as ConditionalExpression;
- cEx.Condition = InvertCondition (cEx.Condition);
+ var cEx = condition.Clone() as ConditionalExpression;
+ cEx.Condition = InvertCondition(cEx.Condition);
return cEx;
}
if (condition is PrimitiveExpression) {
var pex = condition as PrimitiveExpression;
if (pex.Value is bool) {
- return new PrimitiveExpression (!((bool)pex.Value));
+ return new PrimitiveExpression(!((bool)pex.Value));
}
}
- return new UnaryOperatorExpression (UnaryOperatorType.Not, condition);
+ return new UnaryOperatorExpression(UnaryOperatorType.Not, AddParensForUnaryExpressionIfRequired(condition.Clone()));
+ }
+
+ ///
+ /// When negating an expression this is required, otherwise you would end up with
+ /// a or b -> !a or b
+ ///
+ internal static Expression AddParensForUnaryExpressionIfRequired(Expression expression)
+ {
+ if ((expression is BinaryOperatorExpression) ||
+ (expression is AssignmentExpression) ||
+ (expression is CastExpression) ||
+ (expression is AsExpression) ||
+ (expression is IsExpression) ||
+ (expression is LambdaExpression) ||
+ (expression is ConditionalExpression)) {
+ return new ParenthesizedExpression(expression);
+ }
+
+ return expression;
}
///
@@ -78,7 +114,7 @@ namespace ICSharpCode.NRefactory.CSharp
///
/// negation of the specified relational operator, or BinaryOperatorType.Any if it's not a relational operator
///
- public static BinaryOperatorType NegateRelationalOperator (BinaryOperatorType op)
+ public static BinaryOperatorType NegateRelationalOperator(BinaryOperatorType op)
{
switch (op) {
case BinaryOperatorType.GreaterThan:
@@ -93,9 +129,52 @@ namespace ICSharpCode.NRefactory.CSharp
return BinaryOperatorType.GreaterThanOrEqual;
case BinaryOperatorType.LessThanOrEqual:
return BinaryOperatorType.GreaterThan;
+ case BinaryOperatorType.ConditionalOr:
+ return BinaryOperatorType.ConditionalAnd;
+ case BinaryOperatorType.ConditionalAnd:
+ return BinaryOperatorType.ConditionalOr;
}
return BinaryOperatorType.Any;
}
+
+ ///
+ /// Returns true, if the specified operator is a relational operator
+ ///
+ public static bool IsRelationalOperator(BinaryOperatorType op)
+ {
+ return NegateRelationalOperator(op) != BinaryOperatorType.Any;
+ }
+
+ ///
+ /// Get negation of the condition operator
+ ///
+ ///
+ /// negation of the specified condition operator, or BinaryOperatorType.Any if it's not a condition operator
+ ///
+ public static BinaryOperatorType NegateConditionOperator(BinaryOperatorType op)
+ {
+ switch (op) {
+ case BinaryOperatorType.ConditionalOr:
+ return BinaryOperatorType.ConditionalAnd;
+ case BinaryOperatorType.ConditionalAnd:
+ return BinaryOperatorType.ConditionalOr;
+ }
+ return BinaryOperatorType.Any;
+ }
+
+ public static bool AreConditionsEqual(Expression cond1, Expression cond2)
+ {
+ if (cond1 == null || cond2 == null)
+ return false;
+ return GetInnerMostExpression(cond1).IsMatch(GetInnerMostExpression(cond2));
+ }
+
+ public static Expression GetInnerMostExpression(Expression target)
+ {
+ while (target is ParenthesizedExpression)
+ target = ((ParenthesizedExpression)target).Expression;
+ return target;
+ }
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/ComposedType.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/ComposedType.cs
index 0103937a6..0c0f96c62 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/ComposedType.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/ComposedType.cs
@@ -47,7 +47,13 @@ namespace ICSharpCode.NRefactory.CSharp
return !GetChildByRole(NullableRole).IsNull;
}
set {
- SetChildByRole(NullableRole, value ? new CSharpTokenNode(TextLocation.Empty) : null);
+ SetChildByRole(NullableRole, value ? new CSharpTokenNode(TextLocation.Empty, null) : null);
+ }
+ }
+
+ public CSharpTokenNode NullableSpecifierToken {
+ get {
+ return GetChildByRole(NullableRole);
}
}
@@ -64,7 +70,7 @@ namespace ICSharpCode.NRefactory.CSharp
d--;
}
while (d < value) {
- InsertChildBefore(GetChildByRole(PointerRole), new CSharpTokenNode(TextLocation.Empty), PointerRole);
+ InsertChildBefore(GetChildByRole(PointerRole), new CSharpTokenNode(TextLocation.Empty, PointerRole), PointerRole);
d++;
}
}
@@ -73,12 +79,16 @@ namespace ICSharpCode.NRefactory.CSharp
public AstNodeCollection ArraySpecifiers {
get { return GetChildrenByRole (ArraySpecifierRole); }
}
+
+ public AstNodeCollection PointerTokens {
+ get { return GetChildrenByRole (PointerRole); }
+ }
public override void AcceptVisitor (IAstVisitor visitor)
{
visitor.VisitComposedType (this);
}
-
+
public override T AcceptVisitor (IAstVisitor visitor)
{
return visitor.VisitComposedType (this);
@@ -92,10 +102,12 @@ namespace ICSharpCode.NRefactory.CSharp
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
ComposedType o = other as ComposedType;
- return o != null && this.HasNullableSpecifier == o.HasNullableSpecifier && this.PointerRank == o.PointerRank && this.ArraySpecifiers.DoMatch(o.ArraySpecifiers, match);
+ return o != null && this.HasNullableSpecifier == o.HasNullableSpecifier && this.PointerRank == o.PointerRank
+ && this.BaseType.DoMatch(o.BaseType, match)
+ && this.ArraySpecifiers.DoMatch(o.ArraySpecifiers, match);
}
-
- public override string ToString()
+
+ public override string ToString(CSharpFormattingOptions formattingOptions)
{
StringBuilder b = new StringBuilder();
b.Append(this.BaseType.ToString());
@@ -126,18 +138,20 @@ namespace ICSharpCode.NRefactory.CSharp
return this;
}
- public override ITypeReference ToTypeReference(NameLookupMode lookupMode = NameLookupMode.Type)
+ public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null)
{
- ITypeReference t = this.BaseType.ToTypeReference(lookupMode);
+ if (interningProvider == null)
+ interningProvider = InterningProvider.Dummy;
+ ITypeReference t = this.BaseType.ToTypeReference(lookupMode, interningProvider);
if (this.HasNullableSpecifier) {
- t = NullableType.Create(t);
+ t = interningProvider.Intern(NullableType.Create(t));
}
int pointerRank = this.PointerRank;
for (int i = 0; i < pointerRank; i++) {
- t = new PointerTypeReference(t);
+ t = interningProvider.Intern(new PointerTypeReference(t));
}
foreach (var a in this.ArraySpecifiers.Reverse()) {
- t = new ArrayTypeReference(t, a.Dimensions);
+ t = interningProvider.Intern(new ArrayTypeReference(t, a.Dimensions));
}
return t;
}
@@ -176,7 +190,7 @@ namespace ICSharpCode.NRefactory.CSharp
d--;
}
while (d < value) {
- InsertChildBefore(GetChildByRole(Roles.Comma), new CSharpTokenNode(TextLocation.Empty), Roles.Comma);
+ InsertChildBefore(GetChildByRole(Roles.Comma), new CSharpTokenNode(TextLocation.Empty, Roles.Comma), Roles.Comma);
d++;
}
}
@@ -190,7 +204,7 @@ namespace ICSharpCode.NRefactory.CSharp
{
visitor.VisitArraySpecifier (this);
}
-
+
public override T AcceptVisitor (IAstVisitor visitor)
{
return visitor.VisitArraySpecifier (this);
@@ -206,8 +220,8 @@ namespace ICSharpCode.NRefactory.CSharp
ArraySpecifier o = other as ArraySpecifier;
return o != null && this.Dimensions == o.Dimensions;
}
-
- public override string ToString()
+
+ public override string ToString(CSharpFormattingOptions formattingOptions)
{
return "[" + new string(',', this.Dimensions - 1) + "]";
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/DepthFirstAstVisitor.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/DepthFirstAstVisitor.cs
index 81982caf5..59f006cda 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/DepthFirstAstVisitor.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/DepthFirstAstVisitor.cs
@@ -44,6 +44,14 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
+ public virtual void VisitNullNode(AstNode nullNode)
+ {
+ // Should we call VisitChildren here?
+ // We usually want to ignore null nodes.
+ // Older NR versions (before VisitNullNode was introduced) didn't call VisitChildren() with null nodes;
+ // so changing this might break VisitChildren() overrides that expect the node to be part of the AST.
+ }
+
public virtual void VisitSyntaxTree (SyntaxTree syntaxTree)
{
VisitChildren (syntaxTree);
@@ -613,12 +621,7 @@ namespace ICSharpCode.NRefactory.CSharp
{
VisitChildren (namedExpression);
}
-
- public virtual void VisitEmptyExpression (EmptyExpression emptyExpression)
- {
- VisitChildren (emptyExpression);
- }
-
+
public virtual void VisitPatternPlaceholder(AstNode placeholder, PatternMatching.Pattern pattern)
{
VisitChildren (placeholder);
@@ -642,6 +645,15 @@ namespace ICSharpCode.NRefactory.CSharp
return default (T);
}
+ public virtual T VisitNullNode(AstNode nullNode)
+ {
+ // Should we call VisitChildren here?
+ // We usually want to ignore null nodes.
+ // Older NR versions (before VisitNullNode was introduced) didn't call VisitChildren() with null nodes;
+ // so changing this might break VisitChildren() overrides that expect the node to be part of the AST.
+ return default (T);
+ }
+
public virtual T VisitSyntaxTree (SyntaxTree unit)
{
return VisitChildren (unit);
@@ -1212,11 +1224,6 @@ namespace ICSharpCode.NRefactory.CSharp
return VisitChildren (namedExpression);
}
- public virtual T VisitEmptyExpression (EmptyExpression emptyExpression)
- {
- return VisitChildren (emptyExpression);
- }
-
public virtual T VisitPatternPlaceholder(AstNode placeholder, PatternMatching.Pattern pattern)
{
return VisitChildren (placeholder);
@@ -1240,6 +1247,15 @@ namespace ICSharpCode.NRefactory.CSharp
return default (S);
}
+ public virtual S VisitNullNode(AstNode nullNode, T data)
+ {
+ // Should we call VisitChildren here?
+ // We usually want to ignore null nodes.
+ // Older NR versions (before VisitNullNode was introduced) didn't call VisitChildren() with null nodes;
+ // so changing this might break VisitChildren() overrides that expect the node to be part of the AST.
+ return default (S);
+ }
+
public virtual S VisitSyntaxTree (SyntaxTree unit, T data)
{
return VisitChildren (unit, data);
@@ -1810,11 +1826,6 @@ namespace ICSharpCode.NRefactory.CSharp
return VisitChildren (namedExpression, data);
}
- public virtual S VisitEmptyExpression (EmptyExpression emptyExpression, T data)
- {
- return VisitChildren (emptyExpression, data);
- }
-
public virtual S VisitPatternPlaceholder(AstNode placeholder, PatternMatching.Pattern pattern, T data)
{
return VisitChildren (placeholder, data);
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/DocumentationReference.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/DocumentationReference.cs
index 9c599ce6b..633f921b2 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/DocumentationReference.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/DocumentationReference.cs
@@ -1,4 +1,4 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
+// Copyright (c) 2010-2013 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
@@ -29,29 +29,29 @@ namespace ICSharpCode.NRefactory.CSharp
public static readonly Role DeclaringTypeRole = new Role("DeclaringType", AstType.Null);
public static readonly Role ConversionOperatorReturnTypeRole = new Role("ConversionOperatorReturnType", AstType.Null);
- EntityType entityType;
+ SymbolKind symbolKind;
OperatorType operatorType;
bool hasParameterList;
///
/// Gets/Sets the entity type.
/// Possible values are:
- /// EntityType.Operator for operators,
- /// EntityType.Indexer for indexers,
- /// EntityType.TypeDefinition for references to primitive types,
- /// and EntityType.None for everything else.
+ /// SymbolKind.Operator for operators,
+ /// SymbolKind.Indexer for indexers,
+ /// SymbolKind.TypeDefinition for references to primitive types,
+ /// and SymbolKind.None for everything else.
///
- public EntityType EntityType {
- get { return entityType; }
+ public SymbolKind SymbolKind {
+ get { return symbolKind; }
set {
ThrowIfFrozen();
- entityType = value;
+ symbolKind = value;
}
}
///
/// Gets/Sets the operator type.
- /// This property is only used when EntityType==Operator.
+ /// This property is only used when SymbolKind==Operator.
///
public OperatorType OperatorType {
get { return operatorType; }
@@ -86,7 +86,7 @@ namespace ICSharpCode.NRefactory.CSharp
///
/// Gets/sets the member name.
- /// This property is only used when EntityType==None.
+ /// This property is only used when SymbolKind==None.
///
public string MemberName {
get { return GetChildByRole(Roles.Identifier).Name; }
@@ -95,7 +95,7 @@ namespace ICSharpCode.NRefactory.CSharp
///
/// Gets/Sets the return type of conversion operators.
- /// This property is only used when EntityType==Operator and OperatorType is explicit or implicit.
+ /// This property is only used when SymbolKind==Operator and OperatorType is explicit or implicit.
///
public AstType ConversionOperatorReturnType {
get { return GetChildByRole(ConversionOperatorReturnTypeRole); }
@@ -113,16 +113,16 @@ namespace ICSharpCode.NRefactory.CSharp
protected internal override bool DoMatch(AstNode other, ICSharpCode.NRefactory.PatternMatching.Match match)
{
DocumentationReference o = other as DocumentationReference;
- if (!(o != null && this.EntityType == o.EntityType && this.HasParameterList == o.HasParameterList))
+ if (!(o != null && this.SymbolKind == o.SymbolKind && this.HasParameterList == o.HasParameterList))
return false;
- if (this.EntityType == EntityType.Operator) {
+ if (this.SymbolKind == SymbolKind.Operator) {
if (this.OperatorType != o.OperatorType)
return false;
if (this.OperatorType == OperatorType.Implicit || this.OperatorType == OperatorType.Explicit) {
if (!this.ConversionOperatorReturnType.DoMatch(o.ConversionOperatorReturnType, match))
return false;
}
- } else if (this.EntityType == EntityType.None) {
+ } else if (this.SymbolKind == SymbolKind.None) {
if (!MatchString(this.MemberName, o.MemberName))
return false;
if (!this.TypeArguments.DoMatch(o.TypeArguments, match))
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/ErrorNode.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/ErrorNode.cs
index ee5f88521..e402a8047 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/ErrorNode.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/ErrorNode.cs
@@ -78,8 +78,8 @@ namespace ICSharpCode.NRefactory.CSharp
var o = other as ErrorNode;
return o != null;
}
-
- public override string ToString ()
+
+ public override string ToString(CSharpFormattingOptions formattingOptions)
{
return "[ErrorNode]";
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AnonymousMethodExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AnonymousMethodExpression.cs
index 07de16197..e8de95431 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AnonymousMethodExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AnonymousMethodExpression.cs
@@ -48,7 +48,7 @@ namespace ICSharpCode.NRefactory.CSharp
bool hasParameterList;
public bool HasParameterList {
- get { return hasParameterList; }
+ get { return hasParameterList || Parameters.Any(); }
set { ThrowIfFrozen(); hasParameterList = value; }
}
@@ -80,6 +80,7 @@ namespace ICSharpCode.NRefactory.CSharp
public AnonymousMethodExpression (BlockStatement body, IEnumerable parameters = null)
{
if (parameters != null) {
+ hasParameterList = true;
foreach (var parameter in parameters) {
AddChild (parameter, Roles.Parameter);
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ArrayCreateExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ArrayCreateExpression.cs
index c9f1b2a62..3720a3fc8 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ArrayCreateExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ArrayCreateExpression.cs
@@ -1,4 +1,4 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
+// Copyright (c) 2010-2013 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
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ArrayInitializerExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ArrayInitializerExpression.cs
index 0bfc1c1d7..fa3246f92 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ArrayInitializerExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ArrayInitializerExpression.cs
@@ -72,16 +72,17 @@ namespace ICSharpCode.NRefactory.CSharp
public override void AcceptVisitor (IAstVisitor visitor)
{
+ visitor.VisitNullNode(this);
}
public override T AcceptVisitor (IAstVisitor visitor)
{
- return default (T);
+ return visitor.VisitNullNode(this);
}
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
- return default (S);
+ return visitor.VisitNullNode(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AsExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AsExpression.cs
index cf9cfb4f9..5a7b5ac5d 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AsExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AsExpression.cs
@@ -23,6 +23,8 @@
// 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.Collections.Generic;
+using System;
namespace ICSharpCode.NRefactory.CSharp
{
@@ -56,7 +58,7 @@ namespace ICSharpCode.NRefactory.CSharp
AddChild (expression, Roles.Expression);
AddChild (type, Roles.Type);
}
-
+
public override void AcceptVisitor (IAstVisitor visitor)
{
visitor.VisitAsExpression (this);
@@ -77,6 +79,72 @@ namespace ICSharpCode.NRefactory.CSharp
AsExpression o = other as AsExpression;
return o != null && this.Expression.DoMatch(o.Expression, match) && this.Type.DoMatch(o.Type, match);
}
+
+ #region Builder methods
+ public override MemberReferenceExpression Member(string memberName)
+ {
+ return new MemberReferenceExpression { Target = this, MemberName = memberName };
+ }
+
+ public override IndexerExpression Indexer(IEnumerable arguments)
+ {
+ IndexerExpression expr = new IndexerExpression();
+ expr.Target = new ParenthesizedExpression(this);
+ expr.Arguments.AddRange(arguments);
+ return expr;
+ }
+
+ public override IndexerExpression Indexer(params Expression[] arguments)
+ {
+ IndexerExpression expr = new IndexerExpression();
+ expr.Target = new ParenthesizedExpression(this);
+ expr.Arguments.AddRange(arguments);
+ return expr;
+ }
+
+ public override InvocationExpression Invoke(string methodName, IEnumerable typeArguments, IEnumerable arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ MemberReferenceExpression mre = new MemberReferenceExpression();
+ mre.Target = new ParenthesizedExpression(this);
+ mre.MemberName = methodName;
+ mre.TypeArguments.AddRange(typeArguments);
+ ie.Target = mre;
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override InvocationExpression Invoke(IEnumerable arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ ie.Target = new ParenthesizedExpression(this);
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override InvocationExpression Invoke(params Expression[] arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ ie.Target = new ParenthesizedExpression(this);
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override CastExpression CastTo(AstType type)
+ {
+ return new CastExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+
+ public override AsExpression CastAs(AstType type)
+ {
+ return new AsExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+
+ public override IsExpression IsType(AstType type)
+ {
+ return new IsExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+ #endregion
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AssignmentExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AssignmentExpression.cs
index 14021d323..95d0cdf28 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AssignmentExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AssignmentExpression.cs
@@ -26,6 +26,7 @@
using System;
using System.Linq.Expressions;
+using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp
{
@@ -201,6 +202,72 @@ namespace ICSharpCode.NRefactory.CSharp
throw new NotSupportedException("Invalid value for AssignmentOperatorType");
}
}
+
+ #region Builder methods
+ public override MemberReferenceExpression Member(string memberName)
+ {
+ return new MemberReferenceExpression { Target = this, MemberName = memberName };
+ }
+
+ public override IndexerExpression Indexer(IEnumerable arguments)
+ {
+ IndexerExpression expr = new IndexerExpression();
+ expr.Target = new ParenthesizedExpression(this);
+ expr.Arguments.AddRange(arguments);
+ return expr;
+ }
+
+ public override IndexerExpression Indexer(params Expression[] arguments)
+ {
+ IndexerExpression expr = new IndexerExpression();
+ expr.Target = new ParenthesizedExpression(this);
+ expr.Arguments.AddRange(arguments);
+ return expr;
+ }
+
+ public override InvocationExpression Invoke(string methodName, IEnumerable typeArguments, IEnumerable arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ MemberReferenceExpression mre = new MemberReferenceExpression();
+ mre.Target = new ParenthesizedExpression(this);
+ mre.MemberName = methodName;
+ mre.TypeArguments.AddRange(typeArguments);
+ ie.Target = mre;
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override InvocationExpression Invoke(IEnumerable arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ ie.Target = new ParenthesizedExpression(this);
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override InvocationExpression Invoke(params Expression[] arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ ie.Target = new ParenthesizedExpression(this);
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override CastExpression CastTo(AstType type)
+ {
+ return new CastExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+
+ public override AsExpression CastAs(AstType type)
+ {
+ return new AsExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+
+ public override IsExpression IsType(AstType type)
+ {
+ return new IsExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+ #endregion
}
public enum AssignmentOperatorType
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/BinaryOperatorExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/BinaryOperatorExpression.cs
index 819d90f53..e4408e184 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/BinaryOperatorExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/BinaryOperatorExpression.cs
@@ -26,6 +26,7 @@
using System;
using System.Linq.Expressions;
+using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp
{
@@ -200,6 +201,71 @@ namespace ICSharpCode.NRefactory.CSharp
throw new NotSupportedException("Invalid value for BinaryOperatorType");
}
}
+ #region Builder methods
+ public override MemberReferenceExpression Member(string memberName)
+ {
+ return new MemberReferenceExpression { Target = this, MemberName = memberName };
+ }
+
+ public override IndexerExpression Indexer(IEnumerable arguments)
+ {
+ IndexerExpression expr = new IndexerExpression();
+ expr.Target = new ParenthesizedExpression(this);
+ expr.Arguments.AddRange(arguments);
+ return expr;
+ }
+
+ public override IndexerExpression Indexer(params Expression[] arguments)
+ {
+ IndexerExpression expr = new IndexerExpression();
+ expr.Target = new ParenthesizedExpression(this);
+ expr.Arguments.AddRange(arguments);
+ return expr;
+ }
+
+ public override InvocationExpression Invoke(string methodName, IEnumerable typeArguments, IEnumerable arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ MemberReferenceExpression mre = new MemberReferenceExpression();
+ mre.Target = new ParenthesizedExpression(this);
+ mre.MemberName = methodName;
+ mre.TypeArguments.AddRange(typeArguments);
+ ie.Target = mre;
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override InvocationExpression Invoke(IEnumerable arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ ie.Target = new ParenthesizedExpression(this);
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override InvocationExpression Invoke(params Expression[] arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ ie.Target = new ParenthesizedExpression(this);
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override CastExpression CastTo(AstType type)
+ {
+ return new CastExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+
+ public override AsExpression CastAs(AstType type)
+ {
+ return new AsExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+
+ public override IsExpression IsType(AstType type)
+ {
+ return new IsExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+ #endregion
}
public enum BinaryOperatorType
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/CastExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/CastExpression.cs
index 96f41bcf3..e771d18fe 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/CastExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/CastExpression.cs
@@ -23,6 +23,8 @@
// 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.Collections.Generic;
+using System;
namespace ICSharpCode.NRefactory.CSharp
{
@@ -52,13 +54,13 @@ namespace ICSharpCode.NRefactory.CSharp
public CastExpression ()
{
}
-
+
public CastExpression (AstType castToType, Expression expression)
{
AddChild (castToType, Roles.Type);
AddChild (expression, Roles.Expression);
}
-
+
public override void AcceptVisitor (IAstVisitor visitor)
{
visitor.VisitCastExpression (this);
@@ -79,6 +81,72 @@ namespace ICSharpCode.NRefactory.CSharp
CastExpression o = other as CastExpression;
return o != null && this.Type.DoMatch(o.Type, match) && this.Expression.DoMatch(o.Expression, match);
}
+
+ #region Builder methods
+ public override MemberReferenceExpression Member(string memberName)
+ {
+ return new MemberReferenceExpression { Target = this, MemberName = memberName };
+ }
+
+ public override IndexerExpression Indexer(IEnumerable arguments)
+ {
+ IndexerExpression expr = new IndexerExpression();
+ expr.Target = new ParenthesizedExpression(this);
+ expr.Arguments.AddRange(arguments);
+ return expr;
+ }
+
+ public override IndexerExpression Indexer(params Expression[] arguments)
+ {
+ IndexerExpression expr = new IndexerExpression();
+ expr.Target = new ParenthesizedExpression(this);
+ expr.Arguments.AddRange(arguments);
+ return expr;
+ }
+
+ public override InvocationExpression Invoke(string methodName, IEnumerable typeArguments, IEnumerable arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ MemberReferenceExpression mre = new MemberReferenceExpression();
+ mre.Target = new ParenthesizedExpression(this);
+ mre.MemberName = methodName;
+ mre.TypeArguments.AddRange(typeArguments);
+ ie.Target = mre;
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override InvocationExpression Invoke(IEnumerable arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ ie.Target = new ParenthesizedExpression(this);
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override InvocationExpression Invoke(params Expression[] arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ ie.Target = new ParenthesizedExpression(this);
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override CastExpression CastTo(AstType type)
+ {
+ return new CastExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+
+ public override AsExpression CastAs(AstType type)
+ {
+ return new AsExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+
+ public override IsExpression IsType(AstType type)
+ {
+ return new IsExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+ #endregion
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ConditionalExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ConditionalExpression.cs
index fb2d5cb59..4367a0cce 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ConditionalExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ConditionalExpression.cs
@@ -23,6 +23,7 @@
// 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.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp
{
@@ -91,5 +92,71 @@ namespace ICSharpCode.NRefactory.CSharp
ConditionalExpression o = other as ConditionalExpression;
return o != null && this.Condition.DoMatch(o.Condition, match) && this.TrueExpression.DoMatch(o.TrueExpression, match) && this.FalseExpression.DoMatch(o.FalseExpression, match);
}
+
+ #region Builder methods
+ public override MemberReferenceExpression Member(string memberName)
+ {
+ return new MemberReferenceExpression { Target = this, MemberName = memberName };
+ }
+
+ public override IndexerExpression Indexer(IEnumerable arguments)
+ {
+ IndexerExpression expr = new IndexerExpression();
+ expr.Target = new ParenthesizedExpression(this);
+ expr.Arguments.AddRange(arguments);
+ return expr;
+ }
+
+ public override IndexerExpression Indexer(params Expression[] arguments)
+ {
+ IndexerExpression expr = new IndexerExpression();
+ expr.Target = new ParenthesizedExpression(this);
+ expr.Arguments.AddRange(arguments);
+ return expr;
+ }
+
+ public override InvocationExpression Invoke(string methodName, IEnumerable typeArguments, IEnumerable arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ MemberReferenceExpression mre = new MemberReferenceExpression();
+ mre.Target = new ParenthesizedExpression(this);
+ mre.MemberName = methodName;
+ mre.TypeArguments.AddRange(typeArguments);
+ ie.Target = mre;
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override InvocationExpression Invoke(IEnumerable arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ ie.Target = new ParenthesizedExpression(this);
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override InvocationExpression Invoke(params Expression[] arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ ie.Target = new ParenthesizedExpression(this);
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override CastExpression CastTo(AstType type)
+ {
+ return new CastExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+
+ public override AsExpression CastAs(AstType type)
+ {
+ return new AsExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+
+ public override IsExpression IsType(AstType type)
+ {
+ return new IsExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+ #endregion
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ErrorExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ErrorExpression.cs
index bd6506c81..163204448 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ErrorExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ErrorExpression.cs
@@ -27,6 +27,42 @@ using System;
namespace ICSharpCode.NRefactory.CSharp
{
+ [Obsolete("This class is obsolete. Remove all referencing code.")]
+ public class EmptyExpression : AstNode
+ {
+ #region implemented abstract members of AstNode
+
+ public override void AcceptVisitor(IAstVisitor visitor)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override T AcceptVisitor(IAstVisitor visitor)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override S AcceptVisitor(IAstVisitor visitor, T data)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected internal override bool DoMatch(AstNode other, ICSharpCode.NRefactory.PatternMatching.Match match)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override NodeType NodeType {
+ get {
+ throw new NotImplementedException();
+ }
+ }
+
+ #endregion
+
+
+ }
+
public class ErrorExpression : Expression
{
TextLocation location;
@@ -43,6 +79,11 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
+ public string Error {
+ get;
+ private set;
+ }
+
public ErrorExpression ()
{
}
@@ -51,7 +92,18 @@ namespace ICSharpCode.NRefactory.CSharp
{
this.location = location;
}
-
+
+ public ErrorExpression (string error)
+ {
+ this.Error = error;
+ }
+
+ public ErrorExpression (string error, TextLocation location)
+ {
+ this.location = location;
+ this.Error = error;
+ }
+
public override void AcceptVisitor (IAstVisitor visitor)
{
// nothing
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/Expression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/Expression.cs
index d9bbed466..22962a606 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/Expression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/Expression.cs
@@ -1,4 +1,4 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
+// Copyright (c) 2010-2013 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
@@ -43,16 +43,17 @@ namespace ICSharpCode.NRefactory.CSharp
public override void AcceptVisitor (IAstVisitor visitor)
{
+ visitor.VisitNullNode(this);
}
public override T AcceptVisitor (IAstVisitor visitor)
{
- return default (T);
+ return visitor.VisitNullNode(this);
}
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
- return default (S);
+ return visitor.VisitNullNode(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
@@ -118,13 +119,7 @@ namespace ICSharpCode.NRefactory.CSharp
{
return (Expression)base.Clone();
}
-
- // Make debugging easier by giving Expressions a ToString() implementation
- public override string ToString()
- {
- return DebugToString();
- }
-
+
public Expression ReplaceWith(Func replaceFunction)
{
if (replaceFunction == null)
@@ -136,7 +131,7 @@ namespace ICSharpCode.NRefactory.CSharp
///
/// Builds an member reference expression using this expression as target.
///
- public MemberReferenceExpression Member(string memberName)
+ public virtual MemberReferenceExpression Member(string memberName)
{
return new MemberReferenceExpression { Target = this, MemberName = memberName };
}
@@ -144,7 +139,7 @@ namespace ICSharpCode.NRefactory.CSharp
///
/// Builds an indexer expression using this expression as target.
///
- public IndexerExpression Indexer(IEnumerable arguments)
+ public virtual IndexerExpression Indexer(IEnumerable arguments)
{
IndexerExpression expr = new IndexerExpression();
expr.Target = this;
@@ -155,7 +150,7 @@ namespace ICSharpCode.NRefactory.CSharp
///
/// Builds an indexer expression using this expression as target.
///
- public IndexerExpression Indexer(params Expression[] arguments)
+ public virtual IndexerExpression Indexer(params Expression[] arguments)
{
IndexerExpression expr = new IndexerExpression();
expr.Target = this;
@@ -166,7 +161,7 @@ namespace ICSharpCode.NRefactory.CSharp
///
/// Builds an invocation expression using this expression as target.
///
- public InvocationExpression Invoke(string methodName, IEnumerable arguments)
+ public virtual InvocationExpression Invoke(string methodName, IEnumerable arguments)
{
return Invoke(methodName, null, arguments);
}
@@ -174,7 +169,7 @@ namespace ICSharpCode.NRefactory.CSharp
///
/// Builds an invocation expression using this expression as target.
///
- public InvocationExpression Invoke(string methodName, params Expression[] arguments)
+ public virtual InvocationExpression Invoke(string methodName, params Expression[] arguments)
{
return Invoke(methodName, null, arguments);
}
@@ -182,7 +177,7 @@ namespace ICSharpCode.NRefactory.CSharp
///
/// Builds an invocation expression using this expression as target.
///
- public InvocationExpression Invoke(string methodName, IEnumerable typeArguments, IEnumerable arguments)
+ public virtual InvocationExpression Invoke(string methodName, IEnumerable typeArguments, IEnumerable arguments)
{
InvocationExpression ie = new InvocationExpression();
MemberReferenceExpression mre = new MemberReferenceExpression();
@@ -197,7 +192,7 @@ namespace ICSharpCode.NRefactory.CSharp
///
/// Builds an invocation expression using this expression as target.
///
- public InvocationExpression Invoke(IEnumerable arguments)
+ public virtual InvocationExpression Invoke(IEnumerable arguments)
{
InvocationExpression ie = new InvocationExpression();
ie.Target = this;
@@ -208,7 +203,7 @@ namespace ICSharpCode.NRefactory.CSharp
///
/// Builds an invocation expression using this expression as target.
///
- public InvocationExpression Invoke(params Expression[] arguments)
+ public virtual InvocationExpression Invoke(params Expression[] arguments)
{
InvocationExpression ie = new InvocationExpression();
ie.Target = this;
@@ -216,17 +211,17 @@ namespace ICSharpCode.NRefactory.CSharp
return ie;
}
- public CastExpression CastTo(AstType type)
+ public virtual CastExpression CastTo(AstType type)
{
return new CastExpression { Type = type, Expression = this };
}
- public AsExpression CastAs(AstType type)
+ public virtual AsExpression CastAs(AstType type)
{
return new AsExpression { Type = type, Expression = this };
}
- public IsExpression IsType(AstType type)
+ public virtual IsExpression IsType(AstType type)
{
return new IsExpression { Type = type, Expression = this };
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/IsExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/IsExpression.cs
index 163cef041..791ab25d7 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/IsExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/IsExpression.cs
@@ -23,6 +23,7 @@
// 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.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp
{
@@ -46,6 +47,17 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole(Roles.Type); }
set { SetChildByRole(Roles.Type, value); }
}
+
+ public IsExpression()
+ {
+ }
+
+ public IsExpression (Expression expression, AstType type)
+ {
+ AddChild (expression, Roles.Expression);
+ AddChild (type, Roles.Type);
+ }
+
public override void AcceptVisitor (IAstVisitor visitor)
{
@@ -67,6 +79,72 @@ namespace ICSharpCode.NRefactory.CSharp
IsExpression o = other as IsExpression;
return o != null && this.Expression.DoMatch(o.Expression, match) && this.Type.DoMatch(o.Type, match);
}
+
+ #region Builder methods
+ public override MemberReferenceExpression Member(string memberName)
+ {
+ return new MemberReferenceExpression { Target = this, MemberName = memberName };
+ }
+
+ public override IndexerExpression Indexer(IEnumerable arguments)
+ {
+ IndexerExpression expr = new IndexerExpression();
+ expr.Target = new ParenthesizedExpression(this);
+ expr.Arguments.AddRange(arguments);
+ return expr;
+ }
+
+ public override IndexerExpression Indexer(params Expression[] arguments)
+ {
+ IndexerExpression expr = new IndexerExpression();
+ expr.Target = new ParenthesizedExpression(this);
+ expr.Arguments.AddRange(arguments);
+ return expr;
+ }
+
+ public override InvocationExpression Invoke(string methodName, IEnumerable typeArguments, IEnumerable arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ MemberReferenceExpression mre = new MemberReferenceExpression();
+ mre.Target = new ParenthesizedExpression(this);
+ mre.MemberName = methodName;
+ mre.TypeArguments.AddRange(typeArguments);
+ ie.Target = mre;
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override InvocationExpression Invoke(IEnumerable arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ ie.Target = new ParenthesizedExpression(this);
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override InvocationExpression Invoke(params Expression[] arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ ie.Target = new ParenthesizedExpression(this);
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override CastExpression CastTo(AstType type)
+ {
+ return new CastExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+
+ public override AsExpression CastAs(AstType type)
+ {
+ return new AsExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+
+ public override IsExpression IsType(AstType type)
+ {
+ return new IsExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+ #endregion
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/LambdaExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/LambdaExpression.cs
index 001ffcb32..e85902d84 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/LambdaExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/LambdaExpression.cs
@@ -44,10 +44,18 @@ namespace ICSharpCode.NRefactory.CSharp
set { ThrowIfFrozen(); isAsync = value; }
}
+ public CSharpTokenNode LParToken {
+ get { return GetChildByRole (Roles.LPar); }
+ }
+
public AstNodeCollection Parameters {
get { return GetChildrenByRole (Roles.Parameter); }
}
+ public CSharpTokenNode RParToken {
+ get { return GetChildByRole (Roles.RPar); }
+ }
+
public CSharpTokenNode ArrowToken {
get { return GetChildByRole (ArrowRole); }
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/MemberReferenceExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/MemberReferenceExpression.cs
index 4a433b46d..334c6a260 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/MemberReferenceExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/MemberReferenceExpression.cs
@@ -93,7 +93,7 @@ namespace ICSharpCode.NRefactory.CSharp
public MemberReferenceExpression (Expression target, string memberName, params AstType[] arguments) : this (target, memberName, (IEnumerable)arguments)
{
- }
+ }
public override void AcceptVisitor (IAstVisitor visitor)
{
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NamedArgumentExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NamedArgumentExpression.cs
index 0751afe1e..6b485f015 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NamedArgumentExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NamedArgumentExpression.cs
@@ -1,4 +1,4 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
+// Copyright (c) 2010-2013 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
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NullReferenceExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NullReferenceExpression.cs
index a7a3ab7b5..fbfeb6f91 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NullReferenceExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NullReferenceExpression.cs
@@ -1,6 +1,6 @@
//
// NullReferenceExpression.cs
-//
+//
// Author:
// Mike Krüger
//
@@ -38,6 +38,12 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
+ internal void SetStartLocation(TextLocation value)
+ {
+ ThrowIfFrozen();
+ this.location = value;
+ }
+
public override TextLocation EndLocation {
get {
return new TextLocation (location.Line, location.Column + "null".Length);
@@ -57,7 +63,7 @@ namespace ICSharpCode.NRefactory.CSharp
{
visitor.VisitNullReferenceExpression (this);
}
-
+
public override T AcceptVisitor (IAstVisitor visitor)
{
return visitor.VisitNullReferenceExpression (this);
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/PrimitiveExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/PrimitiveExpression.cs
index 9f867fe1e..adfe7c3ba 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/PrimitiveExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/PrimitiveExpression.cs
@@ -1,6 +1,6 @@
//
// PrimitiveExpression.cs
-//
+//
// Author:
// Mike Krüger
//
@@ -42,10 +42,22 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
+ internal void SetStartLocation(TextLocation value)
+ {
+ ThrowIfFrozen();
+ this.startLocation = value;
+ this.endLocation = null;
+ }
+
string literalValue;
+ TextLocation? endLocation;
public override TextLocation EndLocation {
get {
- return new TextLocation (StartLocation.Line, StartLocation.Column + literalValue.Length);
+ if (!endLocation.HasValue) {
+ endLocation = value is string ? AdvanceLocation (StartLocation, literalValue ?? "") :
+ new TextLocation (StartLocation.Line, StartLocation.Column + (literalValue ?? "").Length);
+ }
+ return endLocation.Value;
}
}
@@ -53,46 +65,56 @@ namespace ICSharpCode.NRefactory.CSharp
public object Value {
get { return this.value; }
- set {
- ThrowIfFrozen();
+ set {
+ ThrowIfFrozen();
this.value = value;
+ literalValue = null;
}
}
+ /// Never returns null.
public string LiteralValue {
+ get { return literalValue ?? ""; }
+ }
+
+ /// Can be null.
+ public string UnsafeLiteralValue {
get { return literalValue; }
- set {
- if (value == null)
- throw new ArgumentNullException();
- ThrowIfFrozen();
- literalValue = value;
- }
+ }
+
+ public void SetValue(object value, string literalValue)
+ {
+ if (value == null)
+ throw new ArgumentNullException();
+ ThrowIfFrozen();
+ this.value = value;
+ this.literalValue = literalValue;
}
public PrimitiveExpression (object value)
{
this.Value = value;
- this.literalValue = "";
+ this.literalValue = null;
}
public PrimitiveExpression (object value, string literalValue)
{
this.Value = value;
- this.literalValue = literalValue ?? "";
+ this.literalValue = literalValue;
}
public PrimitiveExpression (object value, TextLocation startLocation, string literalValue)
{
this.Value = value;
this.startLocation = startLocation;
- this.literalValue = literalValue ?? "";
+ this.literalValue = literalValue;
}
public override void AcceptVisitor (IAstVisitor visitor)
{
visitor.VisitPrimitiveExpression (this);
}
-
+
public override T AcceptVisitor (IAstVisitor visitor)
{
return visitor.VisitPrimitiveExpression (this);
@@ -102,6 +124,34 @@ namespace ICSharpCode.NRefactory.CSharp
{
return visitor.VisitPrimitiveExpression (this, data);
}
+
+ unsafe static TextLocation AdvanceLocation(TextLocation startLocation, string str)
+ {
+ int line = startLocation.Line;
+ int col = startLocation.Column;
+ fixed (char* start = str) {
+ char* p = start;
+ char* endPtr = start + str.Length;
+ while (p < endPtr) {
+ var nl = NewLine.GetDelimiterLength(*p, () => {
+ char* nextp = p + 1;
+ if (nextp < endPtr)
+ return *nextp;
+ return '\0';
+ });
+ if (nl > 0) {
+ line++;
+ col = 1;
+ if (nl == 2)
+ p++;
+ } else {
+ col++;
+ }
+ p++;
+ }
+ }
+ return new TextLocation (line, col);
+ }
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/QueryExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/QueryExpression.cs
index e5f36ae10..b52f50a47 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/QueryExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/QueryExpression.cs
@@ -1,4 +1,4 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
+// Copyright (c) 2010-2013 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
@@ -38,16 +38,17 @@ namespace ICSharpCode.NRefactory.CSharp
public override void AcceptVisitor (IAstVisitor visitor)
{
+ visitor.VisitNullNode(this);
}
-
+
public override T AcceptVisitor (IAstVisitor visitor)
{
- return default (T);
+ return visitor.VisitNullNode(this);
}
-
+
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
- return default (S);
+ return visitor.VisitNullNode(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
@@ -81,6 +82,72 @@ namespace ICSharpCode.NRefactory.CSharp
QueryExpression o = other as QueryExpression;
return o != null && !o.IsNull && this.Clauses.DoMatch(o.Clauses, match);
}
+
+ #region Builder methods
+ public override MemberReferenceExpression Member(string memberName)
+ {
+ return new MemberReferenceExpression { Target = this, MemberName = memberName };
+ }
+
+ public override IndexerExpression Indexer(IEnumerable arguments)
+ {
+ IndexerExpression expr = new IndexerExpression();
+ expr.Target = new ParenthesizedExpression(this);
+ expr.Arguments.AddRange(arguments);
+ return expr;
+ }
+
+ public override IndexerExpression Indexer(params Expression[] arguments)
+ {
+ IndexerExpression expr = new IndexerExpression();
+ expr.Target = new ParenthesizedExpression(this);
+ expr.Arguments.AddRange(arguments);
+ return expr;
+ }
+
+ public override InvocationExpression Invoke(string methodName, IEnumerable typeArguments, IEnumerable arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ MemberReferenceExpression mre = new MemberReferenceExpression();
+ mre.Target = new ParenthesizedExpression(this);
+ mre.MemberName = methodName;
+ mre.TypeArguments.AddRange(typeArguments);
+ ie.Target = mre;
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override InvocationExpression Invoke(IEnumerable arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ ie.Target = new ParenthesizedExpression(this);
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override InvocationExpression Invoke(params Expression[] arguments)
+ {
+ InvocationExpression ie = new InvocationExpression();
+ ie.Target = new ParenthesizedExpression(this);
+ ie.Arguments.AddRange(arguments);
+ return ie;
+ }
+
+ public override CastExpression CastTo(AstType type)
+ {
+ return new CastExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+
+ public override AsExpression CastAs(AstType type)
+ {
+ return new AsExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+
+ public override IsExpression IsType(AstType type)
+ {
+ return new IsExpression { Type = type, Expression = new ParenthesizedExpression(this) };
+ }
+ #endregion
}
public abstract class QueryClause : AstNode
@@ -118,6 +185,10 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole(PrecedingQueryRole, value); }
}
+ public CSharpTokenNode IntoKeyword {
+ get { return GetChildByRole (IntoKeywordRole); }
+ }
+
public string Identifier {
get {
return GetChildByRole (Roles.Identifier).Name;
@@ -158,6 +229,10 @@ namespace ICSharpCode.NRefactory.CSharp
public static readonly TokenRole FromKeywordRole = new TokenRole ("from");
public static readonly TokenRole InKeywordRole = new TokenRole ("in");
+ public CSharpTokenNode FromKeyword {
+ get { return GetChildByRole (FromKeywordRole); }
+ }
+
public AstType Type {
get { return GetChildByRole (Roles.Type); }
set { SetChildByRole (Roles.Type, value); }
@@ -176,6 +251,10 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole(Roles.Identifier); }
}
+ public CSharpTokenNode InKeyword {
+ get { return GetChildByRole (InKeywordRole); }
+ }
+
public Expression Expression {
get { return GetChildByRole (Roles.Expression); }
set { SetChildByRole (Roles.Expression, value); }
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/TypeReferenceExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/TypeReferenceExpression.cs
index 129e1364a..84b2d60dc 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/TypeReferenceExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/TypeReferenceExpression.cs
@@ -1,4 +1,4 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
+// Copyright (c) 2010-2013 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
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/UnaryOperatorExpression.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/UnaryOperatorExpression.cs
index 70d178728..878d6132f 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/UnaryOperatorExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/UnaryOperatorExpression.cs
@@ -62,9 +62,10 @@ namespace ICSharpCode.NRefactory.CSharp
public CSharpTokenNode OperatorToken {
get { return GetChildByRole (GetOperatorRole (Operator)); }
}
-
+
+ static Expression NoUnaryExpressionError = new ErrorExpression ("No unary expression");
public Expression Expression {
- get { return GetChildByRole (Roles.Expression); }
+ get { return GetChildByRole (Roles.Expression) ?? NoUnaryExpressionError; }
set { SetChildByRole (Roles.Expression, value); }
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Attribute.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Attribute.cs
index 74fd9d7e3..cc99936e5 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Attribute.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Attribute.cs
@@ -43,11 +43,19 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.Type); }
set { SetChildByRole (Roles.Type, value); }
}
-
+
+ public CSharpTokenNode LParToken {
+ get { return GetChildByRole (Roles.LPar); }
+ }
+
public AstNodeCollection Arguments {
get { return base.GetChildrenByRole (Roles.Argument); }
}
-
+
+ public CSharpTokenNode RParToken {
+ get { return GetChildByRole (Roles.RPar); }
+ }
+
// HasArgumentList == false: [Empty]
public bool HasArgumentList {
get;
@@ -74,13 +82,12 @@ namespace ICSharpCode.NRefactory.CSharp
Attribute o = other as Attribute;
return o != null && this.Type.DoMatch (o.Type, match) && this.Arguments.DoMatch (o.Arguments, match);
}
-
- public override string ToString ()
+
+ public override string ToString(CSharpFormattingOptions formattingOptions)
{
if (IsNull)
return "Null";
- else
- return GetText();
+ return base.ToString(formattingOptions);
}
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/AttributeSection.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/AttributeSection.cs
index cd065b9c1..67b04412b 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/AttributeSection.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/AttributeSection.cs
@@ -135,7 +135,7 @@ namespace ICSharpCode.NRefactory.CSharp
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
AttributeSection o = other as AttributeSection;
- return o != null && this.AttributeTarget == o.AttributeTarget && this.Attributes.DoMatch(o.Attributes, match);
+ return o != null && MatchString(this.AttributeTarget, o.AttributeTarget) && this.Attributes.DoMatch(o.Attributes, match);
}
public AttributeSection()
@@ -171,17 +171,4 @@ namespace ICSharpCode.NRefactory.CSharp
// }
// }
}
-
- public enum AttributeTarget {
- None,
- Assembly,
- Module,
-
- Type,
- Param,
- Field,
- Return,
- Method,
- Unknown
- }
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Comment.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Comment.cs
index 83c00c9bf..9d53f6e66 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Comment.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Comment.cs
@@ -65,6 +65,15 @@ namespace ICSharpCode.NRefactory.CSharp
set { ThrowIfFrozen(); commentType = value; }
}
+ ///
+ /// Returns true if the is Documentation or MultiLineDocumentation.
+ ///
+ public bool IsDocumentation {
+ get {
+ return commentType == CommentType.Documentation || commentType == CommentType.MultiLineDocumentation;
+ }
+ }
+
bool startsLine;
public bool StartsLine {
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Constraint.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Constraint.cs
index cfd15f7af..c49930427 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Constraint.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Constraint.cs
@@ -41,7 +41,11 @@ namespace ICSharpCode.NRefactory.CSharp
return NodeType.Unknown;
}
}
-
+
+ public CSharpTokenNode WhereKeyword {
+ get { return GetChildByRole (Roles.WhereKeyword); }
+ }
+
public SimpleType TypeParameter {
get {
return GetChildByRole (Roles.ConstraintTypeParameter);
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/DelegateDeclaration.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/DelegateDeclaration.cs
index 088afa90b..68489bc7f 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/DelegateDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/DelegateDeclaration.cs
@@ -37,8 +37,8 @@ namespace ICSharpCode.NRefactory.CSharp
get { return NodeType.TypeDeclaration; }
}
- public override EntityType EntityType {
- get { return EntityType.TypeDefinition; }
+ public override SymbolKind SymbolKind {
+ get { return SymbolKind.TypeDefinition; }
}
public CSharpTokenNode DelegateToken {
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/NamespaceDeclaration.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/NamespaceDeclaration.cs
index a374f490d..dbcf0192d 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/NamespaceDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/NamespaceDeclaration.cs
@@ -23,10 +23,10 @@
// 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.Collections.Generic;
using System.Linq;
using System.Text;
+using System;
namespace ICSharpCode.NRefactory.CSharp
{
@@ -36,36 +36,42 @@ namespace ICSharpCode.NRefactory.CSharp
public class NamespaceDeclaration : AstNode
{
public static readonly Role MemberRole = SyntaxTree.MemberRole;
-
+ public static readonly Role NamespaceNameRole = new Role("NamespaceName", AstType.Null);
+
public override NodeType NodeType {
get {
return NodeType.Unknown;
}
}
-
+
public CSharpTokenNode NamespaceToken {
- get { return GetChildByRole (Roles.NamespaceKeyword); }
+ get { return GetChildByRole(Roles.NamespaceKeyword); }
}
-
+
+ public AstType NamespaceName {
+ get { return GetChildByRole(NamespaceNameRole) ?? AstType.Null; }
+ set { SetChildByRole(NamespaceNameRole, value); }
+ }
+
public string Name {
get {
- StringBuilder builder = new StringBuilder ();
- foreach (Identifier identifier in GetChildrenByRole (Roles.Identifier)) {
- if (builder.Length > 0)
- builder.Append ('.');
- builder.Append (identifier.Name);
- }
- return builder.ToString ();
+ return UsingDeclaration.ConstructNamespace(NamespaceName);
}
set {
- GetChildrenByRole(Roles.Identifier).ReplaceWith(value.Split('.').Select(ident => Identifier.Create (ident)));
+ var arr = value.Split('.');
+ NamespaceName = ConstructType(arr, arr.Length - 1);
}
}
-
- public AstNodeCollection Identifiers {
- get { return GetChildrenByRole (Roles.Identifier); }
+
+ static AstType ConstructType(string[] arr, int i)
+ {
+ if (i < 0 || i >= arr.Length)
+ throw new ArgumentOutOfRangeException("i");
+ if (i == 0)
+ return new SimpleType(arr[i]);
+ return new MemberType(ConstructType(arr, i - 1), arr[i]);
}
-
+
///
/// Gets the full namespace name (including any parent namespaces)
///
@@ -73,65 +79,80 @@ namespace ICSharpCode.NRefactory.CSharp
get {
NamespaceDeclaration parentNamespace = Parent as NamespaceDeclaration;
if (parentNamespace != null)
- return BuildQualifiedName (parentNamespace.FullName, Name);
+ return BuildQualifiedName(parentNamespace.FullName, Name);
return Name;
}
}
-
+
+ public IEnumerable Identifiers {
+ get {
+ var result = new Stack();
+ AstType type = NamespaceName;
+ while (type is MemberType) {
+ var mt = (MemberType)type;
+ result.Push(mt.MemberName);
+ type = mt.Target;
+ }
+ if (type is SimpleType)
+ result.Push(((SimpleType)type).Identifier);
+ return result;
+ }
+ }
+
public CSharpTokenNode LBraceToken {
- get { return GetChildByRole (Roles.LBrace); }
+ get { return GetChildByRole(Roles.LBrace); }
}
-
+
public AstNodeCollection Members {
get { return GetChildrenByRole(MemberRole); }
}
-
+
public CSharpTokenNode RBraceToken {
- get { return GetChildByRole (Roles.RBrace); }
+ get { return GetChildByRole(Roles.RBrace); }
}
-
- public NamespaceDeclaration ()
+
+ public NamespaceDeclaration()
{
}
-
- public NamespaceDeclaration (string name)
+
+ public NamespaceDeclaration(string name)
{
this.Name = name;
}
-
- public static string BuildQualifiedName (string name1, string name2)
+
+ public static string BuildQualifiedName(string name1, string name2)
{
- if (string.IsNullOrEmpty (name1))
+ if (string.IsNullOrEmpty(name1))
return name2;
- if (string.IsNullOrEmpty (name2))
+ if (string.IsNullOrEmpty(name2))
return name1;
return name1 + "." + name2;
}
-
- public void AddMember (AstNode child)
+
+ public void AddMember(AstNode child)
{
- AddChild (child, MemberRole);
+ AddChild(child, MemberRole);
}
-
- public override void AcceptVisitor (IAstVisitor visitor)
+
+ public override void AcceptVisitor(IAstVisitor visitor)
{
- visitor.VisitNamespaceDeclaration (this);
+ visitor.VisitNamespaceDeclaration(this);
}
-
- public override T AcceptVisitor (IAstVisitor visitor)
+
+ public override T AcceptVisitor(IAstVisitor visitor)
{
- return visitor.VisitNamespaceDeclaration (this);
+ return visitor.VisitNamespaceDeclaration(this);
}
-
- public override S AcceptVisitor (IAstVisitor visitor, T data)
+
+ public override S AcceptVisitor(IAstVisitor visitor, T data)
{
- return visitor.VisitNamespaceDeclaration (this, data);
+ return visitor.VisitNamespaceDeclaration(this, data);
}
-
+
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
NamespaceDeclaration o = other as NamespaceDeclaration;
return o != null && MatchString(this.Name, o.Name) && this.Members.DoMatch(o.Members, match);
}
}
-};
+} ;
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/NewLineNode.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/NewLineNode.cs
index a2cba46c8..12b004420 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/NewLineNode.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/NewLineNode.cs
@@ -1,16 +1,11 @@
using System;
namespace ICSharpCode.NRefactory.CSharp
{
- public enum NewLineType {
- Unix,
- Windows,
- Mac
- }
///
/// A New line node represents a line break in the text.
///
- public abstract class NewLineNode : AstNode
+ public sealed class NewLineNode : AstNode
{
public override NodeType NodeType {
get {
@@ -18,8 +13,31 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
- public abstract NewLineType NewLineType {
- get;
+ const uint newLineMask = 0xfu << AstNodeFlagsUsedBits;
+ static readonly UnicodeNewline[] newLineTypes = {
+ UnicodeNewline.Unknown,
+ UnicodeNewline.LF,
+ UnicodeNewline.CRLF,
+ UnicodeNewline.CR,
+ UnicodeNewline.NEL,
+ UnicodeNewline.VT,
+ UnicodeNewline.FF,
+ UnicodeNewline.LS,
+ UnicodeNewline.PS
+ };
+
+ public UnicodeNewline NewLineType {
+ get {
+ return newLineTypes[(flags & newLineMask) >> AstNodeFlagsUsedBits];
+ }
+ set {
+ ThrowIfFrozen();
+ int pos = Array.IndexOf(newLineTypes, value);
+ if (pos < 0)
+ pos = 0;
+ flags &= ~newLineMask; // clear old newline type
+ flags |= (uint)pos << AstNodeFlagsUsedBits;
+ }
}
TextLocation startLocation;
@@ -44,6 +62,11 @@ namespace ICSharpCode.NRefactory.CSharp
this.startLocation = startLocation;
}
+ public sealed override string ToString(CSharpFormattingOptions formattingOptions)
+ {
+ return NewLine.GetString (NewLineType);
+ }
+
public override void AcceptVisitor(IAstVisitor visitor)
{
visitor.VisitNewLine (this);
@@ -58,74 +81,10 @@ namespace ICSharpCode.NRefactory.CSharp
{
return visitor.VisitNewLine (this, data);
}
- }
-
- public class UnixNewLine : NewLineNode
- {
- public override NewLineType NewLineType {
- get {
- return NewLineType.Unix;
- }
- }
-
- public UnixNewLine()
- {
- }
-
- public UnixNewLine(TextLocation startLocation) : base (startLocation)
- {
- }
-
- protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
- {
- var o = other as UnixNewLine;
- return o != null;
- }
- }
-
- public class WindowsNewLine : NewLineNode
- {
- public override NewLineType NewLineType {
- get {
- return NewLineType.Windows;
- }
- }
-
- public WindowsNewLine()
- {
- }
-
- public WindowsNewLine(TextLocation startLocation) : base (startLocation)
- {
- }
-
- protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
- {
- var o = other as WindowsNewLine;
- return o != null;
- }
- }
-
- public class MacNewLine : NewLineNode
- {
- public override NewLineType NewLineType {
- get {
- return NewLineType.Mac;
- }
- }
-
- public MacNewLine()
- {
- }
-
- public MacNewLine(TextLocation startLocation) : base (startLocation)
- {
- }
-
- protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
+
+ protected internal override bool DoMatch(AstNode other, ICSharpCode.NRefactory.PatternMatching.Match match)
{
- var o = other as MacNewLine;
- return o != null;
+ return other is NewLineNode;
}
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/PreProcessorDirective.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/PreProcessorDirective.cs
index b630087ab..631f35e98 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/PreProcessorDirective.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/PreProcessorDirective.cs
@@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
+using System.Collections.Generic;
+using System.Linq;
namespace ICSharpCode.NRefactory.CSharp
{
@@ -45,6 +47,85 @@ namespace ICSharpCode.NRefactory.CSharp
Pragma = 11,
Line = 12
}
+
+ public class LinePreprocessorDirective : PreProcessorDirective
+ {
+ public int LineNumber {
+ get;
+ set;
+ }
+
+ public string FileName {
+ get;
+ set;
+ }
+
+ public LinePreprocessorDirective(TextLocation startLocation, TextLocation endLocation) : base (PreProcessorDirectiveType.Line, startLocation, endLocation)
+ {
+ }
+
+ public LinePreprocessorDirective(string argument = null) : base (PreProcessorDirectiveType.Line, argument)
+ {
+ }
+ }
+
+ public class PragmaWarningPreprocessorDirective : PreProcessorDirective
+ {
+ public static readonly Role WarningRole = new Role ("Warning");
+
+ public static readonly TokenRole PragmaKeywordRole = new TokenRole ("#pragma");
+ public static readonly TokenRole WarningKeywordRole = new TokenRole ("warning");
+ public static readonly TokenRole DisableKeywordRole = new TokenRole ("disable");
+ public static readonly TokenRole RestoreKeywordRole = new TokenRole ("restore");
+
+ public bool Disable {
+ get {
+ return !DisableToken.IsNull;
+ }
+ }
+
+ public CSharpTokenNode PragmaToken {
+ get { return GetChildByRole (PragmaKeywordRole); }
+ }
+
+ public CSharpTokenNode WarningToken {
+ get { return GetChildByRole (WarningKeywordRole); }
+ }
+
+ public CSharpTokenNode DisableToken {
+ get { return GetChildByRole (DisableKeywordRole); }
+ }
+
+ public CSharpTokenNode RestoreToken {
+ get { return GetChildByRole (RestoreKeywordRole); }
+ }
+
+ public AstNodeCollection Warnings {
+ get { return GetChildrenByRole(WarningRole); }
+ }
+
+ public override TextLocation EndLocation {
+ get {
+ var child = LastChild;
+ if (child == null)
+ return base.EndLocation;
+ return child.EndLocation;
+ }
+ }
+
+ public PragmaWarningPreprocessorDirective(TextLocation startLocation, TextLocation endLocation) : base (PreProcessorDirectiveType.Pragma, startLocation, endLocation)
+ {
+ }
+
+ public PragmaWarningPreprocessorDirective(string argument = null) : base (PreProcessorDirectiveType.Pragma, argument)
+ {
+ }
+
+ public bool IsDefined(int pragmaWarning)
+ {
+ return Warnings.Select(w => (int)w.Value).Any(n => n == pragmaWarning);
+ }
+ }
public class PreProcessorDirective : AstNode
{
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/TypeDeclaration.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/TypeDeclaration.cs
index d4ac6eaf6..f2dedfa16 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/TypeDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/TypeDeclaration.cs
@@ -47,8 +47,8 @@ namespace ICSharpCode.NRefactory.CSharp
get { return NodeType.TypeDeclaration; }
}
- public override EntityType EntityType {
- get { return EntityType.TypeDefinition; }
+ public override SymbolKind SymbolKind {
+ get { return SymbolKind.TypeDefinition; }
}
ClassType classType;
@@ -78,9 +78,25 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
+ public CSharpTokenNode LChevronToken {
+ get { return GetChildByRole (Roles.LChevron); }
+ }
+
public AstNodeCollection TypeParameters {
get { return GetChildrenByRole (Roles.TypeParameter); }
}
+
+ public CSharpTokenNode RChevronToken {
+ get { return GetChildByRole (Roles.RChevron); }
+ }
+
+
+
+ public CSharpTokenNode ColonToken {
+ get {
+ return GetChildByRole(Roles.Colon);
+ }
+ }
public AstNodeCollection BaseTypes {
get { return GetChildrenByRole(Roles.BaseType); }
@@ -93,7 +109,7 @@ namespace ICSharpCode.NRefactory.CSharp
public CSharpTokenNode LBraceToken {
get { return GetChildByRole (Roles.LBrace); }
}
-
+
public AstNodeCollection Members {
get { return GetChildrenByRole (Roles.TypeMemberRole); }
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs
index ede85f16a..c992b629a 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs
@@ -1,4 +1,4 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
+// Copyright (c) 2010-2013 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
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/UsingDeclaration.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/UsingDeclaration.cs
index c5ae72351..9e0c35a89 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/UsingDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/UsingDeclaration.cs
@@ -27,6 +27,7 @@
using System;
using System.Linq;
using System.Text;
+using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp
{
@@ -54,7 +55,29 @@ namespace ICSharpCode.NRefactory.CSharp
}
public string Namespace {
- get { return this.Import.ToString(); }
+ get { return ConstructNamespace (Import); }
+ }
+
+ internal static string ConstructNamespace (AstType type)
+ {
+ var stack = new Stack();
+ while (type is MemberType) {
+ var mt = (MemberType)type;
+ stack.Push(mt.MemberName);
+ type = mt.Target;
+ if (mt.IsDoubleColon) {
+ stack.Push("::");
+ } else {
+ stack.Push(".");
+ }
+ }
+ if (type is SimpleType)
+ stack.Push(((SimpleType)type).Identifier);
+
+ var result = new StringBuilder();
+ while (stack.Count > 0)
+ result.Append(stack.Pop());
+ return result.ToString();
}
public CSharpTokenNode SemicolonToken {
@@ -67,7 +90,7 @@ namespace ICSharpCode.NRefactory.CSharp
public UsingDeclaration (string nameSpace)
{
- AddChild (new SimpleType (nameSpace), ImportRole);
+ AddChild (AstType.Create (nameSpace), ImportRole);
}
public UsingDeclaration (AstType import)
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/IAstVisitor.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/IAstVisitor.cs
index c375afacf..a14c4fa54 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/IAstVisitor.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/IAstVisitor.cs
@@ -1,4 +1,4 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
+// Copyright (c) 2010-2013 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
@@ -59,8 +59,7 @@ namespace ICSharpCode.NRefactory.CSharp
void VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression);
void VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression);
void VisitUncheckedExpression(UncheckedExpression uncheckedExpression);
- void VisitEmptyExpression (EmptyExpression emptyExpression);
-
+
void VisitQueryExpression(QueryExpression queryExpression);
void VisitQueryContinuationClause(QueryContinuationClause queryContinuationClause);
void VisitQueryFromClause(QueryFromClause queryFromClause);
@@ -148,6 +147,7 @@ namespace ICSharpCode.NRefactory.CSharp
void VisitCSharpTokenNode(CSharpTokenNode cSharpTokenNode);
void VisitIdentifier(Identifier identifier);
+ void VisitNullNode(AstNode nullNode);
void VisitPatternPlaceholder(AstNode placeholder, PatternMatching.Pattern pattern);
}
@@ -190,8 +190,7 @@ namespace ICSharpCode.NRefactory.CSharp
S VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression);
S VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression);
S VisitUncheckedExpression(UncheckedExpression uncheckedExpression);
- S VisitEmptyExpression (EmptyExpression emptyExpression);
-
+
S VisitQueryExpression(QueryExpression queryExpression);
S VisitQueryContinuationClause(QueryContinuationClause queryContinuationClause);
S VisitQueryFromClause(QueryFromClause queryFromClause);
@@ -279,6 +278,7 @@ namespace ICSharpCode.NRefactory.CSharp
S VisitCSharpTokenNode(CSharpTokenNode cSharpTokenNode);
S VisitIdentifier(Identifier identifier);
+ S VisitNullNode(AstNode nullNode);
S VisitPatternPlaceholder(AstNode placeholder, PatternMatching.Pattern pattern);
}
@@ -321,8 +321,7 @@ namespace ICSharpCode.NRefactory.CSharp
S VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression, T data);
S VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, T data);
S VisitUncheckedExpression(UncheckedExpression uncheckedExpression, T data);
- S VisitEmptyExpression (EmptyExpression emptyExpression, T data);
-
+
S VisitQueryExpression(QueryExpression queryExpression, T data);
S VisitQueryContinuationClause(QueryContinuationClause queryContinuationClause, T data);
S VisitQueryFromClause(QueryFromClause queryFromClause, T data);
@@ -410,6 +409,7 @@ namespace ICSharpCode.NRefactory.CSharp
S VisitCSharpTokenNode(CSharpTokenNode cSharpTokenNode, T data);
S VisitIdentifier(Identifier identifier, T data);
+ S VisitNullNode(AstNode nullNode, T data);
S VisitPatternPlaceholder(AstNode placeholder, PatternMatching.Pattern pattern, T data);
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Identifier.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Identifier.cs
index 3321de2a0..cf403afbd 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Identifier.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Identifier.cs
@@ -41,16 +41,17 @@ namespace ICSharpCode.NRefactory.CSharp
public override void AcceptVisitor (IAstVisitor visitor)
{
+ visitor.VisitNullNode(this);
}
public override T AcceptVisitor (IAstVisitor visitor)
{
- return default (T);
+ return visitor.VisitNullNode(this);
}
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
- return default (S);
+ return visitor.VisitNullNode(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
@@ -83,6 +84,12 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
+ internal void SetStartLocation(TextLocation value)
+ {
+ ThrowIfFrozen();
+ this.startLocation = value;
+ }
+
const uint verbatimBit = 1u << AstNodeFlagsUsedBits;
public bool IsVerbatim {
@@ -127,7 +134,7 @@ namespace ICSharpCode.NRefactory.CSharp
if (string.IsNullOrEmpty(name))
return Identifier.Null;
if (name[0] == '@')
- return new Identifier (name.Substring (1), location) { IsVerbatim = true };
+ return new Identifier (name.Substring (1), new TextLocation (location.Line, location.Column + 1)) { IsVerbatim = true };
else
return new Identifier (name, location);
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/IdentifierExpressionBackreference.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/IdentifierExpressionBackreference.cs
index 0ce09e244..7bfacd990 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/IdentifierExpressionBackreference.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/IdentifierExpressionBackreference.cs
@@ -1,4 +1,4 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
+// Copyright (c) 2010-2013 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
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/MemberType.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/MemberType.cs
index 76efbc7a8..2045d00ed 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/MemberType.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/MemberType.cs
@@ -115,46 +115,35 @@ namespace ICSharpCode.NRefactory.CSharp
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
MemberType o = other as MemberType;
- return o != null && this.IsDoubleColon == o.IsDoubleColon && MatchString(this.MemberName, o.MemberName) && this.Target.DoMatch(o.Target, match);
+ return o != null && this.IsDoubleColon == o.IsDoubleColon
+ && MatchString(this.MemberName, o.MemberName) && this.Target.DoMatch(o.Target, match)
+ && this.TypeArguments.DoMatch(o.TypeArguments, match);
}
-
- public override string ToString()
- {
- StringBuilder b = new StringBuilder();
- b.Append(this.Target);
- if (IsDoubleColon)
- b.Append("::");
- else
- b.Append('.');
- b.Append(this.MemberName);
- if (this.TypeArguments.Any()) {
- b.Append('<');
- b.Append(string.Join(", ", this.TypeArguments));
- b.Append('>');
- }
- return b.ToString();
- }
-
- public override ITypeReference ToTypeReference(NameLookupMode lookupMode = NameLookupMode.Type)
+
+ public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null)
{
+ if (interningProvider == null)
+ interningProvider = InterningProvider.Dummy;
+
TypeOrNamespaceReference t;
if (this.IsDoubleColon) {
SimpleType st = this.Target as SimpleType;
if (st != null) {
- t = new AliasNamespaceReference(st.Identifier);
+ t = interningProvider.Intern(new AliasNamespaceReference(interningProvider.Intern(st.Identifier)));
} else {
t = null;
}
} else {
- t = this.Target.ToTypeReference(lookupMode) as TypeOrNamespaceReference;
+ t = this.Target.ToTypeReference(lookupMode, interningProvider) as TypeOrNamespaceReference;
}
if (t == null)
return SpecialType.UnknownType;
var typeArguments = new List();
foreach (var ta in this.TypeArguments) {
- typeArguments.Add(ta.ToTypeReference(lookupMode));
+ typeArguments.Add(ta.ToTypeReference(lookupMode, interningProvider));
}
- return new MemberTypeOrNamespaceReference(t, this.MemberName, typeArguments, lookupMode);
+ string memberName = interningProvider.Intern(this.MemberName);
+ return interningProvider.Intern(new MemberTypeOrNamespaceReference(t, memberName, interningProvider.InternList(typeArguments), lookupMode));
}
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/ObservableAstVisitor.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/ObservableAstVisitor.cs
index 3291bccf7..6ac87439a 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/ObservableAstVisitor.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/ObservableAstVisitor.cs
@@ -44,6 +44,10 @@ namespace ICSharpCode.NRefactory.CSharp
if (leave != null)
leave(node);
}
+
+ void IAstVisitor.VisitNullNode(AstNode nullNode)
+ {
+ }
public event Action EnterSyntaxTree, LeaveSyntaxTree;
@@ -842,13 +846,6 @@ namespace ICSharpCode.NRefactory.CSharp
Visit(EnterNamedExpression, LeaveNamedExpression, namedExpression);
}
- public event Action EnterEmptyExpression, LeaveEmptyExpression;
-
- void IAstVisitor.VisitEmptyExpression(EmptyExpression emptyExpression)
- {
- Visit(EnterEmptyExpression, LeaveEmptyExpression, emptyExpression);
- }
-
void IAstVisitor.VisitPatternPlaceholder(AstNode placeholder, PatternMatching.Pattern pattern)
{
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/PrimitiveType.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/PrimitiveType.cs
index 9d8a575be..5b52a37ac 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/PrimitiveType.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/PrimitiveType.cs
@@ -71,6 +71,13 @@ namespace ICSharpCode.NRefactory.CSharp
return location;
}
}
+
+ internal void SetStartLocation(TextLocation value)
+ {
+ ThrowIfFrozen();
+ this.location = value;
+ }
+
public override TextLocation EndLocation {
get {
return new TextLocation (location.Line, location.Column + keyword.Length);
@@ -97,13 +104,13 @@ namespace ICSharpCode.NRefactory.CSharp
PrimitiveType o = other as PrimitiveType;
return o != null && MatchString(this.Keyword, o.Keyword);
}
-
- public override string ToString()
+
+ public override string ToString(CSharpFormattingOptions formattingOptions)
{
return Keyword;
}
- public override ITypeReference ToTypeReference(NameLookupMode lookupMode = NameLookupMode.Type)
+ public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null)
{
KnownTypeCode typeCode = GetTypeCodeForPrimitiveType(this.Keyword);
if (typeCode == KnownTypeCode.None)
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/SimpleType.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/SimpleType.cs
index 79b4e0f9c..529a62fbe 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/SimpleType.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/SimpleType.cs
@@ -49,16 +49,17 @@ namespace ICSharpCode.NRefactory.CSharp
public override void AcceptVisitor (IAstVisitor visitor)
{
+ visitor.VisitNullNode(this);
}
-
+
public override T AcceptVisitor (IAstVisitor visitor)
{
- return default (T);
+ return visitor.VisitNullNode(this);
}
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
- return default (S);
+ return visitor.VisitNullNode(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
@@ -66,7 +67,7 @@ namespace ICSharpCode.NRefactory.CSharp
return other == null || other.IsNull;
}
- public override ITypeReference ToTypeReference(NameLookupMode lookupMode)
+ public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider)
{
return SpecialType.UnknownType;
}
@@ -130,7 +131,7 @@ namespace ICSharpCode.NRefactory.CSharp
{
visitor.VisitSimpleType (this);
}
-
+
public override T AcceptVisitor (IAstVisitor visitor)
{
return visitor.VisitSimpleType (this);
@@ -147,28 +148,21 @@ namespace ICSharpCode.NRefactory.CSharp
return o != null && MatchString(this.Identifier, o.Identifier) && this.TypeArguments.DoMatch(o.TypeArguments, match);
}
- public override string ToString()
- {
- StringBuilder b = new StringBuilder(this.Identifier);
- if (this.TypeArguments.Any()) {
- b.Append('<');
- b.Append(string.Join(", ", this.TypeArguments));
- b.Append('>');
- }
- return b.ToString();
- }
-
- public override ITypeReference ToTypeReference(NameLookupMode lookupMode = NameLookupMode.Type)
+ public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null)
{
+ if (interningProvider == null)
+ interningProvider = InterningProvider.Dummy;
var typeArguments = new List();
foreach (var ta in this.TypeArguments) {
- typeArguments.Add(ta.ToTypeReference(lookupMode));
+ typeArguments.Add(ta.ToTypeReference(lookupMode, interningProvider));
}
- if (typeArguments.Count == 0 && string.IsNullOrEmpty(this.Identifier)) {
+ string identifier = interningProvider.Intern(this.Identifier);
+ if (typeArguments.Count == 0 && string.IsNullOrEmpty(identifier)) {
// empty SimpleType is used for typeof(List<>).
return SpecialType.UnboundTypeArgument;
}
- return new SimpleTypeOrNamespaceReference(this.Identifier, typeArguments, lookupMode);
+ var t = new SimpleTypeOrNamespaceReference(identifier, interningProvider.InternList(typeArguments), lookupMode);
+ return interningProvider.Intern(t);
}
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/BlockStatement.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/BlockStatement.cs
index d30484d8d..24b9cd106 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/BlockStatement.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/BlockStatement.cs
@@ -47,16 +47,17 @@ namespace ICSharpCode.NRefactory.CSharp
public override void AcceptVisitor (IAstVisitor visitor)
{
+ visitor.VisitNullNode(this);
}
-
+
public override T AcceptVisitor (IAstVisitor visitor)
{
- return default (T);
+ return visitor.VisitNullNode(this);
}
-
+
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
- return default (S);
+ return visitor.VisitNullNode(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
@@ -150,11 +151,6 @@ namespace ICSharpCode.NRefactory.CSharp
AddChild(statement, StatementRole);
}
- public void Add(Expression expression)
- {
- AddChild(new ExpressionStatement(expression), StatementRole);
- }
-
IEnumerator IEnumerable.GetEnumerator()
{
return this.Statements.GetEnumerator();
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/BreakStatement.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/BreakStatement.cs
index 056cf55e4..4bb4e39ef 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/BreakStatement.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/BreakStatement.cs
@@ -40,7 +40,7 @@ namespace ICSharpCode.NRefactory.CSharp
public CSharpTokenNode SemicolonToken {
get { return GetChildByRole (Roles.Semicolon); }
}
-
+
public override void AcceptVisitor (IAstVisitor visitor)
{
visitor.VisitBreakStatement (this);
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/DoWhileStatement.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/DoWhileStatement.cs
index ec6e2ce26..280ca7cea 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/DoWhileStatement.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/DoWhileStatement.cs
@@ -84,6 +84,16 @@ namespace ICSharpCode.NRefactory.CSharp
DoWhileStatement o = other as DoWhileStatement;
return o != null && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match) && this.Condition.DoMatch(o.Condition, match);
}
+
+ public DoWhileStatement()
+ {
+ }
+
+ public DoWhileStatement(Expression condition, Statement embeddedStatement)
+ {
+ this.Condition = condition;
+ this.EmbeddedStatement = embeddedStatement;
+ }
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/LabelStatement.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/LabelStatement.cs
index ef2190bfe..43d22cea7 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/LabelStatement.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/LabelStatement.cs
@@ -45,7 +45,7 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole (Roles.Identifier, value); }
}
- public CSharpTokenNode Colon {
+ public CSharpTokenNode ColonToken {
get { return GetChildByRole (Roles.Colon); }
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/Statement.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/Statement.cs
index 6d3ec7d1f..24d3ede92 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/Statement.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/Statement.cs
@@ -1,5 +1,20 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
-// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
+// Copyright (c) 2010-2013 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;
@@ -27,16 +42,17 @@ namespace ICSharpCode.NRefactory.CSharp
public override void AcceptVisitor (IAstVisitor visitor)
{
+ visitor.VisitNullNode(this);
}
-
+
public override T AcceptVisitor (IAstVisitor visitor)
{
- return default (T);
+ return visitor.VisitNullNode(this);
}
-
+
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
- return default (S);
+ return visitor.VisitNullNode(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
@@ -107,11 +123,10 @@ namespace ICSharpCode.NRefactory.CSharp
public override NodeType NodeType {
get { return NodeType.Statement; }
}
-
- // Make debugging easier by giving Statements a ToString() implementation
- public override string ToString()
+
+ public static implicit operator Statement (Expression type)
{
- return DebugToString();
+ return new ExpressionStatement(type);
}
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/TryCatchStatement.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/TryCatchStatement.cs
index 13e375b49..3611574b7 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/TryCatchStatement.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/TryCatchStatement.cs
@@ -104,16 +104,17 @@ namespace ICSharpCode.NRefactory.CSharp
public override void AcceptVisitor (IAstVisitor visitor)
{
+ visitor.VisitNullNode(this);
}
public override T AcceptVisitor (IAstVisitor visitor)
{
- return default (T);
+ return visitor.VisitNullNode(this);
}
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
- return default (S);
+ return visitor.VisitNullNode(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/WhileStatement.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/WhileStatement.cs
index 256ddb864..e38daa144 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/WhileStatement.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Statements/WhileStatement.cs
@@ -75,5 +75,15 @@ namespace ICSharpCode.NRefactory.CSharp
WhileStatement o = other as WhileStatement;
return o != null && this.Condition.DoMatch(o.Condition, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match);
}
+
+ public WhileStatement()
+ {
+ }
+
+ public WhileStatement(Expression condition, Statement embeddedStatement)
+ {
+ this.Condition = condition;
+ this.EmbeddedStatement = embeddedStatement;
+ }
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/SyntaxExtensions.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/SyntaxExtensions.cs
new file mode 100644
index 000000000..bac28bb76
--- /dev/null
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/SyntaxExtensions.cs
@@ -0,0 +1,45 @@
+// Copyright (c) 2013 Daniel Grunwald
+//
+// 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;
+
+namespace ICSharpCode.NRefactory.CSharp
+{
+ ///
+ /// Extension methods for the syntax tree.
+ ///
+ public static class SyntaxExtensions
+ {
+ public static bool IsComparisonOperator(this OperatorType operatorType)
+ {
+ switch (operatorType) {
+ case OperatorType.Equality:
+ case OperatorType.Inequality:
+ case OperatorType.GreaterThan:
+ case OperatorType.LessThan:
+ case OperatorType.GreaterThanOrEqual:
+ case OperatorType.LessThanOrEqual:
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/SyntaxTree.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/SyntaxTree.cs
index 2906696b3..6ac536159 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/SyntaxTree.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/SyntaxTree.cs
@@ -105,27 +105,34 @@ namespace ICSharpCode.NRefactory.CSharp
{
}
- public IEnumerable GetTypes(bool includeInnerTypes = false)
+ ///
+ /// Gets all defined types in this syntax tree.
+ ///
+ ///
+ /// A list containing or nodes.
+ ///
+ public IEnumerable GetTypes(bool includeInnerTypes = false)
{
Stack nodeStack = new Stack ();
nodeStack.Push(this);
while (nodeStack.Count > 0) {
var curNode = nodeStack.Pop();
- if (curNode is TypeDeclaration) {
- yield return (TypeDeclaration)curNode;
+ if (curNode is TypeDeclaration || curNode is DelegateDeclaration) {
+ yield return (EntityDeclaration)curNode;
}
foreach (var child in curNode.Children) {
if (!(child is Statement || child is Expression) &&
- (child.Role != Roles.TypeMemberRole || (child is TypeDeclaration && includeInnerTypes)))
+ (child.Role != Roles.TypeMemberRole || ((child is TypeDeclaration || child is DelegateDeclaration) && includeInnerTypes)))
nodeStack.Push (child);
}
}
}
+
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
SyntaxTree o = other as SyntaxTree;
- return o != null && GetChildrenByRole(MemberRole).DoMatch(o.GetChildrenByRole(MemberRole), match);
+ return o != null && this.Members.DoMatch(o.Members, match);
}
public override void AcceptVisitor (IAstVisitor visitor)
@@ -157,24 +164,28 @@ namespace ICSharpCode.NRefactory.CSharp
public static SyntaxTree Parse (string program, string fileName = "", CompilerSettings settings = null, CancellationToken cancellationToken = default (CancellationToken))
{
+ cancellationToken.ThrowIfCancellationRequested();
var parser = new CSharpParser (settings);
return parser.Parse (program, fileName);
}
public static SyntaxTree Parse (TextReader reader, string fileName = "", CompilerSettings settings = null, CancellationToken cancellationToken = default (CancellationToken))
{
+ cancellationToken.ThrowIfCancellationRequested();
var parser = new CSharpParser (settings);
return parser.Parse (reader, fileName);
}
public static SyntaxTree Parse (Stream stream, string fileName = "", CompilerSettings settings = null, CancellationToken cancellationToken = default (CancellationToken))
{
+ cancellationToken.ThrowIfCancellationRequested();
var parser = new CSharpParser (settings);
return parser.Parse (stream, fileName);
}
public static SyntaxTree Parse (ITextSource textSource, string fileName = "", CompilerSettings settings = null, CancellationToken cancellationToken = default (CancellationToken))
{
+ cancellationToken.ThrowIfCancellationRequested();
var parser = new CSharpParser (settings);
return parser.Parse (textSource, fileName);
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TokenRole.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TokenRole.cs
index 29a67ab27..8c9c7392a 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TokenRole.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TokenRole.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp
{
@@ -7,6 +8,17 @@ namespace ICSharpCode.NRefactory.CSharp
///
public sealed class TokenRole : Role
{
+ internal readonly static List Tokens = new List ();
+ internal readonly static List TokenLengths = new List ();
+ internal readonly uint TokenIndex;
+
+ static TokenRole ()
+ {
+ // null token
+ Tokens.Add ("");
+ TokenLengths.Add (0);
+ }
+
///
/// Gets the token as string. Note that the token Name and Token value may differ.
///
@@ -22,11 +34,27 @@ namespace ICSharpCode.NRefactory.CSharp
get;
private set;
}
-
- public TokenRole (string token) : base (token, CSharpTokenNode.Null)
+
+
+ public TokenRole(string token) : base (token, CSharpTokenNode.Null)
{
this.Token = token;
this.Length = token.Length;
+
+ bool found = false;
+ for (int i = 0; i < Tokens.Count; i++) {
+ var existingToken = Tokens [i];
+ if (existingToken == token) {
+ TokenIndex = (uint)i;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ TokenIndex = (uint)Tokens.Count;
+ Tokens.Add (token);
+ TokenLengths.Add (this.Length);
+ }
}
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/Accessor.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/Accessor.cs
index a920a849c..8bd18c477 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/Accessor.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/Accessor.cs
@@ -45,16 +45,17 @@ namespace ICSharpCode.NRefactory.CSharp
public override void AcceptVisitor (IAstVisitor visitor)
{
+ visitor.VisitNullNode(this);
}
public override T AcceptVisitor (IAstVisitor visitor)
{
- return default (T);
+ return visitor.VisitNullNode(this);
}
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
- return default (S);
+ return visitor.VisitNullNode(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
@@ -67,8 +68,24 @@ namespace ICSharpCode.NRefactory.CSharp
get { return NodeType.Unknown; }
}
- public override EntityType EntityType {
- get { return EntityType.Method; }
+ public override SymbolKind SymbolKind {
+ get { return SymbolKind.Method; }
+ }
+
+ ///
+ /// Gets the 'get'/'set'/'add'/'remove' keyword
+ ///
+ public CSharpTokenNode Keyword {
+ get {
+ for (AstNode child = this.FirstChild; child != null; child = child.NextSibling) {
+ if (child.Role == PropertyDeclaration.GetKeywordRole || child.Role == PropertyDeclaration.SetKeywordRole
+ || child.Role == CustomEventDeclaration.AddKeywordRole || child.Role == CustomEventDeclaration.RemoveKeywordRole)
+ {
+ return (CSharpTokenNode)child;
+ }
+ }
+ return CSharpTokenNode.Null;
+ }
}
public BlockStatement Body {
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/ConstructorDeclaration.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/ConstructorDeclaration.cs
index 204776793..23a973a5c 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/ConstructorDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/ConstructorDeclaration.cs
@@ -32,8 +32,8 @@ namespace ICSharpCode.NRefactory.CSharp
{
public static readonly Role InitializerRole = new Role("Initializer", ConstructorInitializer.Null);
- public override EntityType EntityType {
- get { return EntityType.Constructor; }
+ public override SymbolKind SymbolKind {
+ get { return SymbolKind.Constructor; }
}
public CSharpTokenNode LParToken {
@@ -86,6 +86,7 @@ namespace ICSharpCode.NRefactory.CSharp
}
public enum ConstructorInitializerType {
+ Any,
Base,
This
}
@@ -112,16 +113,17 @@ namespace ICSharpCode.NRefactory.CSharp
public override void AcceptVisitor (IAstVisitor visitor)
{
+ visitor.VisitNullNode(this);
}
-
+
public override T AcceptVisitor (IAstVisitor visitor)
{
- return default (T);
+ return visitor.VisitNullNode(this);
}
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
- return default (S);
+ return visitor.VisitNullNode(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
@@ -141,6 +143,15 @@ namespace ICSharpCode.NRefactory.CSharp
set;
}
+ public CSharpTokenNode Keyword {
+ get {
+ if (ConstructorInitializerType == ConstructorInitializerType.Base)
+ return GetChildByRole(BaseKeywordRole);
+ else
+ return GetChildByRole(ThisKeywordRole);
+ }
+ }
+
public CSharpTokenNode LParToken {
get { return GetChildByRole (Roles.LPar); }
}
@@ -171,7 +182,9 @@ namespace ICSharpCode.NRefactory.CSharp
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
ConstructorInitializer o = other as ConstructorInitializer;
- return o != null && !o.IsNull && this.ConstructorInitializerType == o.ConstructorInitializerType && this.Arguments.DoMatch(o.Arguments, match);
+ return o != null && !o.IsNull
+ && (this.ConstructorInitializerType == ConstructorInitializerType.Any || this.ConstructorInitializerType == o.ConstructorInitializerType)
+ && this.Arguments.DoMatch(o.Arguments, match);
}
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/DestructorDeclaration.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/DestructorDeclaration.cs
index 5f2411ec8..0609e5dc6 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/DestructorDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/DestructorDeclaration.cs
@@ -36,8 +36,8 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (TildeRole); }
}
- public override EntityType EntityType {
- get { return EntityType.Destructor; }
+ public override SymbolKind SymbolKind {
+ get { return SymbolKind.Destructor; }
}
public CSharpTokenNode LParToken {
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/EntityDeclaration.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/EntityDeclaration.cs
index ca8f69338..c02ff21b6 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/EntityDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/EntityDeclaration.cs
@@ -1,4 +1,4 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
+// Copyright (c) 2010-2013 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
@@ -33,7 +33,7 @@ namespace ICSharpCode.NRefactory.CSharp
get { return NodeType.Member; }
}
- public abstract NRefactory.TypeSystem.EntityType EntityType { get; }
+ public abstract NRefactory.TypeSystem.SymbolKind SymbolKind { get; }
public AstNodeCollection Attributes {
get { return base.GetChildrenByRole (AttributeRole); }
@@ -71,7 +71,11 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.Type); }
set { SetChildByRole(Roles.Type, value); }
}
-
+
+ public CSharpTokenNode SemicolonToken {
+ get { return GetChildByRole (Roles.Semicolon); }
+ }
+
internal static Modifiers GetModifiers(AstNode node)
{
Modifiers m = 0;
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/EnumMemberDeclaration.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/EnumMemberDeclaration.cs
index 8f05e4e2a..b7c924ab9 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/EnumMemberDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/EnumMemberDeclaration.cs
@@ -33,10 +33,14 @@ namespace ICSharpCode.NRefactory.CSharp
{
public static readonly Role InitializerRole = new Role("Initializer", Expression.Null);
- public override EntityType EntityType {
- get { return EntityType.Field; }
+ public override SymbolKind SymbolKind {
+ get { return SymbolKind.Field; }
}
-
+
+ public CSharpTokenNode AssignToken {
+ get { return GetChildByRole (Roles.Assign); }
+ }
+
public Expression Initializer {
get { return GetChildByRole (InitializerRole); }
set { SetChildByRole (InitializerRole, value); }
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/EventDeclaration.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/EventDeclaration.cs
index 8c1958cf8..d543f9ea7 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/EventDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/EventDeclaration.cs
@@ -24,7 +24,10 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+using System;
using System.Collections.Generic;
+using System.ComponentModel;
+
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp
@@ -33,14 +36,32 @@ namespace ICSharpCode.NRefactory.CSharp
{
public static readonly TokenRole EventKeywordRole = new TokenRole ("event");
- public override EntityType EntityType {
- get { return EntityType.Event; }
+ public override SymbolKind SymbolKind {
+ get { return SymbolKind.Event; }
}
-
+
+ public CSharpTokenNode EventToken {
+ get { return GetChildByRole (EventKeywordRole); }
+ }
+
public AstNodeCollection Variables {
get { return GetChildrenByRole (Roles.Variable); }
}
+ // Hide .Name and .NameToken from users; the actual field names
+ // are stored in the VariableInitializer.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override string Name {
+ get { return string.Empty; }
+ set { throw new NotSupportedException(); }
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override Identifier NameToken {
+ get { return Identifier.Null; }
+ set { throw new NotSupportedException(); }
+ }
+
public override void AcceptVisitor (IAstVisitor visitor)
{
visitor.VisitEventDeclaration (this);
@@ -73,8 +94,8 @@ namespace ICSharpCode.NRefactory.CSharp
public static readonly Role AddAccessorRole = new Role("AddAccessor", Accessor.Null);
public static readonly Role RemoveAccessorRole = new Role("RemoveAccessor", Accessor.Null);
- public override EntityType EntityType {
- get { return EntityType.Event; }
+ public override SymbolKind SymbolKind {
+ get { return SymbolKind.Event; }
}
///
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/FieldDeclaration.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/FieldDeclaration.cs
index 16406d59d..de220ecd7 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/FieldDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/FieldDeclaration.cs
@@ -24,20 +24,36 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+using System;
+using System.ComponentModel;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp
{
public class FieldDeclaration : EntityDeclaration
{
- public override EntityType EntityType {
- get { return EntityType.Field; }
+ public override SymbolKind SymbolKind {
+ get { return SymbolKind.Field; }
}
public AstNodeCollection Variables {
get { return GetChildrenByRole (Roles.Variable); }
}
+ // Hide .Name and .NameToken from users; the actual field names
+ // are stored in the VariableInitializer.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override string Name {
+ get { return string.Empty; }
+ set { throw new NotSupportedException(); }
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override Identifier NameToken {
+ get { return Identifier.Null; }
+ set { throw new NotSupportedException(); }
+ }
+
public override void AcceptVisitor (IAstVisitor visitor)
{
visitor.VisitFieldDeclaration (this);
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/FixedFieldDeclaration.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/FixedFieldDeclaration.cs
index ebc20c5ef..fea2a2af2 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/FixedFieldDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/FixedFieldDeclaration.cs
@@ -33,8 +33,8 @@ namespace ICSharpCode.NRefactory.CSharp
public static readonly TokenRole FixedKeywordRole = new TokenRole ("fixed");
public static readonly Role VariableRole = new Role ("FixedVariable");
- public override EntityType EntityType {
- get { return EntityType.Field; }
+ public override SymbolKind SymbolKind {
+ get { return SymbolKind.Field; }
}
public CSharpTokenNode FixedToken {
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/IndexerDeclaration.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/IndexerDeclaration.cs
index 02bc126ae..56156dd19 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/IndexerDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/IndexerDeclaration.cs
@@ -25,6 +25,7 @@
// THE SOFTWARE.
using System;
+using System.ComponentModel;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp
@@ -35,8 +36,8 @@ namespace ICSharpCode.NRefactory.CSharp
public static readonly Role GetterRole = PropertyDeclaration.GetterRole;
public static readonly Role SetterRole = PropertyDeclaration.SetterRole;
- public override EntityType EntityType {
- get { return EntityType.Indexer; }
+ public override SymbolKind SymbolKind {
+ get { return SymbolKind.Indexer; }
}
///
@@ -53,14 +54,19 @@ namespace ICSharpCode.NRefactory.CSharp
set { throw new NotSupportedException(); }
}
+ [EditorBrowsable(EditorBrowsableState.Never)]
public override Identifier NameToken {
get { return Identifier.Null; }
set { throw new NotSupportedException(); }
}
-
+
public CSharpTokenNode LBracketToken {
get { return GetChildByRole (Roles.LBracket); }
}
+
+ public CSharpTokenNode ThisToken {
+ get { return GetChildByRole (ThisKeywordRole); }
+ }
public AstNodeCollection Parameters {
get { return GetChildrenByRole (Roles.Parameter); }
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/MethodDeclaration.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/MethodDeclaration.cs
index 0d4a2340b..90aaa3047 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/MethodDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/MethodDeclaration.cs
@@ -30,8 +30,8 @@ namespace ICSharpCode.NRefactory.CSharp
{
public class MethodDeclaration : EntityDeclaration
{
- public override EntityType EntityType {
- get { return EntityType.Method; }
+ public override SymbolKind SymbolKind {
+ get { return SymbolKind.Method; }
}
///
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/OperatorDeclaration.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/OperatorDeclaration.cs
index 8e0967357..b4ae52a2a 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/OperatorDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/OperatorDeclaration.cs
@@ -25,6 +25,7 @@
// THE SOFTWARE.
using System;
+using System.ComponentModel;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp
@@ -105,8 +106,8 @@ namespace ICSharpCode.NRefactory.CSharp
public static readonly TokenRole ExplicitRole = new TokenRole ("explicit");
public static readonly TokenRole ImplicitRole = new TokenRole ("implicit");
- public override EntityType EntityType {
- get { return EntityType.Operator; }
+ public override SymbolKind SymbolKind {
+ get { return SymbolKind.Operator; }
}
OperatorType operatorType;
@@ -250,6 +251,7 @@ namespace ICSharpCode.NRefactory.CSharp
set { throw new NotSupportedException(); }
}
+ [EditorBrowsable(EditorBrowsableState.Never)]
public override Identifier NameToken {
get { return Identifier.Null; }
set { throw new NotSupportedException(); }
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/ParameterDeclaration.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/ParameterDeclaration.cs
index 15b4993d2..cc69ff1fd 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/ParameterDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/ParameterDeclaration.cs
@@ -88,7 +88,11 @@ namespace ICSharpCode.NRefactory.CSharp
SetChildByRole (Roles.Identifier, value);
}
}
-
+
+ public CSharpTokenNode AssignToken {
+ get { return GetChildByRole (Roles.Assign); }
+ }
+
public Expression DefaultExpression {
get { return GetChildByRole (Roles.Expression); }
set { SetChildByRole (Roles.Expression, value); }
@@ -127,6 +131,17 @@ namespace ICSharpCode.NRefactory.CSharp
Name = name;
ParameterModifier = modifier;
}
+
+ public ParameterDeclaration(string name, ParameterModifier modifier = ParameterModifier.None)
+ {
+ Name = name;
+ ParameterModifier = modifier;
+ }
+
+ public new ParameterDeclaration Clone()
+ {
+ return (ParameterDeclaration)base.Clone();
+ }
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/PropertyDeclaration.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/PropertyDeclaration.cs
index df0fa9876..1f137e0c9 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/PropertyDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/PropertyDeclaration.cs
@@ -34,8 +34,8 @@ namespace ICSharpCode.NRefactory.CSharp
public static readonly Role GetterRole = new Role("Getter", Accessor.Null);
public static readonly Role SetterRole = new Role("Setter", Accessor.Null);
- public override EntityType EntityType {
- get { return EntityType.Property; }
+ public override SymbolKind SymbolKind {
+ get { return SymbolKind.Property; }
}
///
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/VariableInitializer.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/VariableInitializer.cs
index 8b0c3fff2..dbf4bbe3d 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/VariableInitializer.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/VariableInitializer.cs
@@ -41,16 +41,17 @@ namespace ICSharpCode.NRefactory.CSharp
public override void AcceptVisitor (IAstVisitor visitor)
{
+ visitor.VisitNullNode(this);
}
-
+
public override T AcceptVisitor (IAstVisitor visitor)
{
- return default (T);
+ return visitor.VisitNullNode(this);
}
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
- return default (S);
+ return visitor.VisitNullNode(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
@@ -163,15 +164,7 @@ namespace ICSharpCode.NRefactory.CSharp
{
return visitor.VisitVariableInitializer (this, data);
}
-
- public override string ToString()
- {
- if (this.Initializer.IsNull)
- return "[VariableInitializer " + this.Name + "]";
- else
- return "[VariableInitializer " + this.Name + " = " + this.Initializer.ToString() + "]";
- }
-
+
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
VariableInitializer o = other as VariableInitializer;
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/old_ObservableAstVisitor.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/old_ObservableAstVisitor.cs
deleted file mode 100644
index 6baf690df..000000000
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/old_ObservableAstVisitor.cs
+++ /dev/null
@@ -1,1201 +0,0 @@
-//
-// ObservableAstVisitor.cs
-//
-// Author:
-// Mike Krüger
-//
-// Copyright (c) 2011 Novell, Inc (http://www.novell.com)
-//
-// 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;
-
-namespace ICSharpCode.NRefactory.CSharp
-{
- [Obsolete("Use the non-generic version of the ObservableAstVisitor instead (the 'data' parameter and return value cannot be used meaningfully when using events)")]
- public class ObservableAstVisitor: IAstVisitor
- {
- S VisitChildren (AstNode node, T data)
- {
- AstNode next;
- for (var child = node.FirstChild; child != null; child = next) {
- // Store next to allow the loop to continue
- // if the visitor removes/replaces child.
- next = child.NextSibling;
- child.AcceptVisitor (this, data);
- }
- return default (S);
- }
-
- public event Action CompilationUnitVisited;
-
- S IAstVisitor.VisitSyntaxTree (SyntaxTree unit, T data)
- {
- var handler = CompilationUnitVisited;
- if (handler != null)
- handler (unit, data);
- return VisitChildren (unit, data);
- }
-
- public event Action CommentVisited;
-
- S IAstVisitor.VisitComment (Comment comment, T data)
- {
- var handler = CommentVisited;
- if (handler != null)
- handler (comment, data);
- return VisitChildren (comment, data);
- }
-
- public event Action NewLineVisited;
-
- S IAstVisitor.VisitNewLine(NewLineNode newLineNode, T data)
- {
- var handler = NewLineVisited;
- if (handler != null)
- handler(newLineNode, data);
- return VisitChildren(newLineNode, data);
- }
-
- public event Action WhitespaceVisited;
-
- S IAstVisitor.VisitWhitespace(WhitespaceNode whitespace, T data)
- {
- var handler = WhitespaceVisited;
- if (handler != null)
- handler(whitespace, data);
- return VisitChildren(whitespace, data);
- }
-
- public event Action TextVisited;
-
- S IAstVisitor.VisitText(TextNode textNode, T data)
- {
- var handler = TextVisited;
- if (handler != null)
- handler(textNode, data);
- return VisitChildren(textNode, data);
- }
-
- public event Action PreProcessorDirectiveVisited;
- S IAstVisitor.VisitPreProcessorDirective (PreProcessorDirective preProcessorDirective, T data)
- {
- var handler = PreProcessorDirectiveVisited;
- if (handler != null)
- handler (preProcessorDirective, data);
- return VisitChildren (preProcessorDirective, data);
- }
-
- public event Action DocumentationReferenceVisited;
-
- S IAstVisitor.VisitDocumentationReference (DocumentationReference documentationReference, T data)
- {
- var handler = DocumentationReferenceVisited;
- if (handler != null)
- handler (documentationReference, data);
- return VisitChildren (documentationReference, data);
- }
-
- public event Action IdentifierVisited;
-
- S IAstVisitor.VisitIdentifier (Identifier identifier, T data)
- {
- var handler = IdentifierVisited;
- if (handler != null)
- handler (identifier, data);
- return VisitChildren (identifier, data);
- }
-
- public event Action CSharpTokenNodeVisited;
-
- S IAstVisitor.VisitCSharpTokenNode (CSharpTokenNode token, T data)
- {
- var handler = CSharpTokenNodeVisited;
- if (handler != null)
- handler (token, data);
- return VisitChildren (token, data);
- }
-
- public event Action PrimitiveTypeVisited;
-
- S IAstVisitor.VisitPrimitiveType (PrimitiveType primitiveType, T data)
- {
- var handler = PrimitiveTypeVisited;
- if (handler != null)
- handler (primitiveType, data);
- return VisitChildren (primitiveType, data);
- }
-
- public event Action ComposedTypeVisited;
-
- S IAstVisitor.VisitComposedType (ComposedType composedType, T data)
- {
- var handler = ComposedTypeVisited;
- if (handler != null)
- handler (composedType, data);
- return VisitChildren (composedType, data);
- }
-
- public event Action SimpleTypeVisited;
-
- S IAstVisitor.VisitSimpleType (SimpleType simpleType, T data)
- {
- var handler = SimpleTypeVisited;
- if (handler != null)
- handler (simpleType, data);
- return VisitChildren (simpleType, data);
- }
-
- public event Action MemberTypeVisited;
-
- S IAstVisitor.VisitMemberType (MemberType memberType, T data)
- {
- var handler = MemberTypeVisited;
- if (handler != null)
- handler (memberType, data);
- return VisitChildren (memberType, data);
- }
-
- public event Action AttributeVisited;
-
- S IAstVisitor.VisitAttribute (Attribute attribute, T data)
- {
- var handler = AttributeVisited;
- if (handler != null)
- handler (attribute, data);
- return VisitChildren (attribute, data);
- }
-
- public event Action AttributeSectionVisited;
-
- S IAstVisitor.VisitAttributeSection (AttributeSection attributeSection, T data)
- {
- var handler = AttributeSectionVisited;
- if (handler != null)
- handler (attributeSection, data);
- return VisitChildren (attributeSection, data);
- }
-
- public event Action DelegateDeclarationVisited;
-
- S IAstVisitor.VisitDelegateDeclaration (DelegateDeclaration delegateDeclaration, T data)
- {
- var handler = DelegateDeclarationVisited;
- if (handler != null)
- handler (delegateDeclaration, data);
- return VisitChildren (delegateDeclaration, data);
- }
-
- public event Action NamespaceDeclarationVisited;
-
- S IAstVisitor.VisitNamespaceDeclaration (NamespaceDeclaration namespaceDeclaration, T data)
- {
- var handler = NamespaceDeclarationVisited;
- if (handler != null)
- handler (namespaceDeclaration, data);
- return VisitChildren (namespaceDeclaration, data);
- }
-
- public event Action TypeDeclarationVisited;
-
- S IAstVisitor.VisitTypeDeclaration (TypeDeclaration typeDeclaration, T data)
- {
- var handler = TypeDeclarationVisited;
- if (handler != null)
- handler (typeDeclaration, data);
- return VisitChildren (typeDeclaration, data);
- }
-
- public event Action TypeParameterDeclarationVisited;
-
- S IAstVisitor.VisitTypeParameterDeclaration (TypeParameterDeclaration typeParameterDeclaration, T data)
- {
- var handler = TypeParameterDeclarationVisited;
- if (handler != null)
- handler (typeParameterDeclaration, data);
- return VisitChildren (typeParameterDeclaration, data);
- }
-
- public event Action EnumMemberDeclarationVisited;
-
- S IAstVisitor.VisitEnumMemberDeclaration (EnumMemberDeclaration enumMemberDeclaration, T data)
- {
- var handler = EnumMemberDeclarationVisited;
- if (handler != null)
- handler (enumMemberDeclaration, data);
- return VisitChildren (enumMemberDeclaration, data);
- }
-
- public event Action UsingDeclarationVisited;
-
- S IAstVisitor.VisitUsingDeclaration (UsingDeclaration usingDeclaration, T data)
- {
- var handler = UsingDeclarationVisited;
- if (handler != null)
- handler (usingDeclaration, data);
- return VisitChildren (usingDeclaration, data);
- }
-
- public event Action UsingAliasDeclarationVisited;
-
- S IAstVisitor.VisitUsingAliasDeclaration (UsingAliasDeclaration usingDeclaration, T data)
- {
- var handler = UsingAliasDeclarationVisited;
- if (handler != null)
- handler (usingDeclaration, data);
- return VisitChildren (usingDeclaration, data);
- }
-
- public event Action ExternAliasDeclarationVisited;
-
- S IAstVisitor.VisitExternAliasDeclaration (ExternAliasDeclaration externAliasDeclaration, T data)
- {
- var handler = ExternAliasDeclarationVisited;
- if (handler != null)
- handler (externAliasDeclaration, data);
- return VisitChildren (externAliasDeclaration, data);
- }
-
- public event Action ConstructorDeclarationVisited;
-
- S IAstVisitor.VisitConstructorDeclaration (ConstructorDeclaration constructorDeclaration, T data)
- {
- var handler = ConstructorDeclarationVisited;
- if (handler != null)
- handler (constructorDeclaration, data);
- return VisitChildren (constructorDeclaration, data);
- }
-
- public event Action ConstructorInitializerVisited;
-
- S IAstVisitor.VisitConstructorInitializer (ConstructorInitializer constructorInitializer, T data)
- {
- var handler = ConstructorInitializerVisited;
- if (handler != null)
- handler (constructorInitializer, data);
- return VisitChildren (constructorInitializer, data);
- }
-
- public event Action DestructorDeclarationVisited;
-
- S IAstVisitor.VisitDestructorDeclaration (DestructorDeclaration destructorDeclaration, T data)
- {
- var handler = DestructorDeclarationVisited;
- if (handler != null)
- handler (destructorDeclaration, data);
- return VisitChildren (destructorDeclaration, data);
- }
-
- public event Action EventDeclarationVisited;
-
- S IAstVisitor.VisitEventDeclaration (EventDeclaration eventDeclaration, T data)
- {
- var handler = EventDeclarationVisited;
- if (handler != null)
- handler (eventDeclaration, data);
- return VisitChildren (eventDeclaration, data);
- }
-
- public event Action CustomEventDeclarationVisited;
-
- S IAstVisitor.VisitCustomEventDeclaration (CustomEventDeclaration eventDeclaration, T data)
- {
- var handler = CustomEventDeclarationVisited;
- if (handler != null)
- handler (eventDeclaration, data);
- return VisitChildren (eventDeclaration, data);
- }
-
- public event Action FieldDeclarationVisited;
-
- S IAstVisitor.VisitFieldDeclaration (FieldDeclaration fieldDeclaration, T data)
- {
- var handler = FieldDeclarationVisited;
- if (handler != null)
- handler (fieldDeclaration, data);
- return VisitChildren (fieldDeclaration, data);
- }
-
- public event Action FixedFieldDeclarationVisited;
-
- S IAstVisitor.VisitFixedFieldDeclaration (FixedFieldDeclaration fixedFieldDeclaration, T data)
- {
- var handler = FixedFieldDeclarationVisited;
- if (handler != null)
- handler (fixedFieldDeclaration, data);
- return VisitChildren (fixedFieldDeclaration, data);
- }
-
- public event Action FixedVariableInitializerVisited;
-
- S IAstVisitor.VisitFixedVariableInitializer (FixedVariableInitializer fixedVariableInitializer, T data)
- {
- var handler = FixedVariableInitializerVisited;
- if (handler != null)
- handler (fixedVariableInitializer, data);
- return VisitChildren (fixedVariableInitializer, data);
- }
-
- public event Action IndexerDeclarationVisited;
-
- S IAstVisitor.VisitIndexerDeclaration (IndexerDeclaration indexerDeclaration, T data)
- {
- var handler = IndexerDeclarationVisited;
- if (handler != null)
- handler (indexerDeclaration, data);
- return VisitChildren (indexerDeclaration, data);
- }
-
- public event Action MethodDeclarationVisited;
-
- S IAstVisitor.VisitMethodDeclaration (MethodDeclaration methodDeclaration, T data)
- {
- var handler = MethodDeclarationVisited;
- if (handler != null)
- handler (methodDeclaration, data);
- return VisitChildren (methodDeclaration, data);
- }
-
- public event Action OperatorDeclarationVisited;
-
- S IAstVisitor.VisitOperatorDeclaration (OperatorDeclaration operatorDeclaration, T data)
- {
- var handler = OperatorDeclarationVisited;
- if (handler != null)
- handler (operatorDeclaration, data);
- return VisitChildren (operatorDeclaration, data);
- }
-
- public event Action PropertyDeclarationVisited;
-
- S IAstVisitor.VisitPropertyDeclaration (PropertyDeclaration propertyDeclaration, T data)
- {
- var handler = PropertyDeclarationVisited;
- if (handler != null)
- handler (propertyDeclaration, data);
- return VisitChildren (propertyDeclaration, data);
- }
-
- public event Action AccessorVisited;
-
- S IAstVisitor.VisitAccessor (Accessor accessor, T data)
- {
- var handler = AccessorVisited;
- if (handler != null)
- handler (accessor, data);
- return VisitChildren (accessor, data);
- }
-
- public event Action VariableInitializerVisited;
-
- S IAstVisitor.VisitVariableInitializer (VariableInitializer variableInitializer, T data)
- {
- var handler = VariableInitializerVisited;
- if (handler != null)
- handler (variableInitializer, data);
- return VisitChildren (variableInitializer, data);
- }
-
- public event Action ParameterDeclarationVisited;
-
- S IAstVisitor.VisitParameterDeclaration (ParameterDeclaration parameterDeclaration, T data)
- {
- var handler = ParameterDeclarationVisited;
- if (handler != null)
- handler (parameterDeclaration, data);
- return VisitChildren (parameterDeclaration, data);
- }
-
- public event Action ConstraintVisited;
-
- S IAstVisitor.VisitConstraint (Constraint constraint, T data)
- {
- var handler = ConstraintVisited;
- if (handler != null)
- handler (constraint, data);
- return VisitChildren (constraint, data);
- }
-
- public event Action BlockStatementVisited;
-
- S IAstVisitor.VisitBlockStatement (BlockStatement blockStatement, T data)
- {
- var handler = BlockStatementVisited;
- if (handler != null)
- handler (blockStatement, data);
- return VisitChildren (blockStatement, data);
- }
-
- public event Action ExpressionStatementVisited;
-
- S IAstVisitor.VisitExpressionStatement (ExpressionStatement expressionStatement, T data)
- {
- var handler = ExpressionStatementVisited;
- if (handler != null)
- handler (expressionStatement, data);
- return VisitChildren (expressionStatement, data);
- }
-
- public event Action BreakStatementVisited;
-
- S IAstVisitor.VisitBreakStatement (BreakStatement breakStatement, T data)
- {
- var handler = BreakStatementVisited;
- if (handler != null)
- handler (breakStatement, data);
- return VisitChildren (breakStatement, data);
- }
-
- public event Action CheckedStatementVisited;
-
- S IAstVisitor.VisitCheckedStatement (CheckedStatement checkedStatement, T data)
- {
- var handler = CheckedStatementVisited;
- if (handler != null)
- handler (checkedStatement, data);
- return VisitChildren (checkedStatement, data);
- }
-
- public event Action ContinueStatementVisited;
-
- S IAstVisitor.VisitContinueStatement (ContinueStatement continueStatement, T data)
- {
- var handler = ContinueStatementVisited;
- if (handler != null)
- handler (continueStatement, data);
- return VisitChildren (continueStatement, data);
- }
-
- public event Action DoWhileStatementVisited;
-
- S IAstVisitor