Browse Source

Delete a bunch of dead code.

pull/844/head
Daniel Grunwald 8 years ago
parent
commit
1695474bfc
  1. 1
      .gitmodules
  2. 1700
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  3. 1222
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  4. 69
      ICSharpCode.Decompiler/Ast/CommentStatement.cs
  5. 57
      ICSharpCode.Decompiler/Ast/DecompilerContext.cs
  6. 347
      ICSharpCode.Decompiler/Ast/NameVariables.cs
  7. 373
      ICSharpCode.Decompiler/Ast/TextTokenWriter.cs
  8. 784
      ICSharpCode.Decompiler/CSharp/Analysis/ControlFlow.cs
  9. 750
      ICSharpCode.Decompiler/CSharp/Analysis/DefiniteAssignmentAnalysis.cs
  10. 68
      ICSharpCode.Decompiler/CSharp/Resolver/CompositeResolveVisitorNavigator.cs
  11. 88
      ICSharpCode.Decompiler/CSharp/Resolver/DetectSkippableNodesNavigator.cs
  12. 101
      ICSharpCode.Decompiler/CSharp/Resolver/FindReferencedEntities.cs
  13. 103
      ICSharpCode.Decompiler/CSharp/Resolver/IResolveVisitorNavigator.cs
  14. 77
      ICSharpCode.Decompiler/CSharp/Resolver/NodeListResolveVisitorNavigator.cs
  15. 864
      ICSharpCode.Decompiler/CSharp/Syntax/ObservableAstVisitor.cs
  16. 29
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
  17. 8
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

1
.gitmodules vendored

@ -4,3 +4,4 @@ @@ -4,3 +4,4 @@
[submodule "ILSpy-tests"]
path = ILSpy-tests
url = https://github.com/icsharpcode/ILSpy-tests
ignore = all

1700
ICSharpCode.Decompiler/Ast/AstBuilder.cs

File diff suppressed because it is too large Load Diff

1222
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

File diff suppressed because it is too large Load Diff

69
ICSharpCode.Decompiler/Ast/CommentStatement.cs

@ -1,69 +0,0 @@ @@ -1,69 +0,0 @@
// Copyright (c) 2011 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.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching;
namespace ICSharpCode.Decompiler.Ast
{
/// <summary>
/// Allows storing comments inside IEnumerable{Statement}. Used in the AstMethodBuilder.
/// CommentStatement nodes are replaced with regular comments later on.
/// </summary>
class CommentStatement : Statement
{
string comment;
public CommentStatement(string comment)
{
if (comment == null)
throw new ArgumentNullException("comment");
this.comment = comment;
}
public override void AcceptVisitor(IAstVisitor visitor)
{
}
public override T AcceptVisitor<T>(IAstVisitor<T> visitor)
{
return default(T);
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return default(S);
}
public static void ReplaceAll(AstNode tree)
{
foreach (var cs in tree.Descendants.OfType<CommentStatement>()) {
cs.Parent.InsertChildBefore(cs, new Comment(cs.comment), Roles.Comment);
cs.Remove();
}
}
protected override bool DoMatch(AstNode other, Match match)
{
CommentStatement o = other as CommentStatement;
return o != null && MatchString(comment, o.comment);
}
}
}

57
ICSharpCode.Decompiler/Ast/DecompilerContext.cs

@ -1,57 +0,0 @@ @@ -1,57 +0,0 @@
// Copyright (c) 2011 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.Threading;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using Mono.Cecil;
namespace ICSharpCode.Decompiler
{
public class DecompilerContext
{
public ModuleDefinition CurrentModule;
public CancellationToken CancellationToken;
public TypeDefinition CurrentType;
public MethodDefinition CurrentMethod;
public DecompilerSettings Settings = new DecompilerSettings();
public bool CurrentMethodIsAsync;
public DecompilerContext(ModuleDefinition currentModule)
{
if (currentModule == null)
throw new ArgumentNullException(nameof(currentModule));
this.CurrentModule = currentModule;
}
/// <summary>
/// Used to pass variable names from a method to its anonymous methods.
/// </summary>
internal List<string> ReservedVariableNames = new List<string>();
public DecompilerContext Clone()
{
DecompilerContext ctx = (DecompilerContext)MemberwiseClone();
ctx.ReservedVariableNames = new List<string>(ctx.ReservedVariableNames);
return ctx;
}
}
}

347
ICSharpCode.Decompiler/Ast/NameVariables.cs

@ -1,347 +0,0 @@ @@ -1,347 +0,0 @@
// Copyright (c) 2011 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.Linq;
using ICSharpCode.Decompiler.ILAst;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast
{
public class NameVariables
{
static readonly Dictionary<string, string> typeNameToVariableNameDict = new Dictionary<string, string> {
{ "System.Boolean", "flag" },
{ "System.Byte", "b" },
{ "System.SByte", "b" },
{ "System.Int16", "num" },
{ "System.Int32", "num" },
{ "System.Int64", "num" },
{ "System.UInt16", "num" },
{ "System.UInt32", "num" },
{ "System.UInt64", "num" },
{ "System.Single", "num" },
{ "System.Double", "num" },
{ "System.Decimal", "num" },
{ "System.String", "text" },
{ "System.Object", "obj" },
{ "System.Char", "c" }
};
public static void AssignNamesToVariables(DecompilerContext context, IEnumerable<ILVariable> parameters, IEnumerable<ILVariable> variables, ILBlock methodBody)
{
NameVariables nv = new NameVariables();
nv.context = context;
nv.fieldNamesInCurrentType = context.CurrentType.Fields.Select(f => f.Name).ToList();
// First mark existing variable names as reserved.
foreach (string name in context.ReservedVariableNames)
nv.AddExistingName(name);
foreach (var p in parameters)
nv.AddExistingName(p.Name);
foreach (var v in variables) {
if (v.IsGenerated) {
// don't introduce names for variables generated by ILSpy - keep "expr"/"arg"
nv.AddExistingName(v.Name);
} else if (v.OriginalVariable != null && context.Settings.UseDebugSymbols) {
string varName = v.OriginalVariable.Name;
if (string.IsNullOrEmpty(varName) || varName.StartsWith("V_", StringComparison.Ordinal) || !IsValidName(varName))
{
// don't use the name from the debug symbols if it looks like a generated name
v.Name = null;
} else {
// use the name from the debug symbols
// (but ensure we don't use the same name for two variables)
v.Name = nv.GetAlternativeName(varName);
}
} else {
v.Name = null;
}
}
// Now generate names:
foreach (ILVariable p in parameters) {
if (string.IsNullOrEmpty(p.Name))
p.Name = nv.GenerateNameForVariable(p, methodBody);
}
foreach (ILVariable varDef in variables) {
if (string.IsNullOrEmpty(varDef.Name))
varDef.Name = nv.GenerateNameForVariable(varDef, methodBody);
}
}
static bool IsValidName(string varName)
{
if (string.IsNullOrEmpty(varName))
return false;
if (!(char.IsLetter(varName[0]) || varName[0] == '_'))
return false;
for (int i = 1; i < varName.Length; i++) {
if (!(char.IsLetterOrDigit(varName[i]) || varName[i] == '_'))
return false;
}
return true;
}
DecompilerContext context;
List<string> fieldNamesInCurrentType;
Dictionary<string, int> typeNames = new Dictionary<string, int>();
public void AddExistingName(string name)
{
if (string.IsNullOrEmpty(name))
return;
int number;
string nameWithoutDigits = SplitName(name, out number);
int existingNumber;
if (typeNames.TryGetValue(nameWithoutDigits, out existingNumber)) {
typeNames[nameWithoutDigits] = Math.Max(number, existingNumber);
} else {
typeNames.Add(nameWithoutDigits, number);
}
}
string SplitName(string name, out int number)
{
// First, identify whether the name already ends with a number:
int pos = name.Length;
while (pos > 0 && name[pos-1] >= '0' && name[pos-1] <= '9')
pos--;
if (pos < name.Length) {
if (int.TryParse(name.Substring(pos), out number)) {
return name.Substring(0, pos);
}
}
number = 1;
return name;
}
const char maxLoopVariableName = 'n';
public string GetAlternativeName(string oldVariableName)
{
if (oldVariableName.Length == 1 && oldVariableName[0] >= 'i' && oldVariableName[0] <= maxLoopVariableName) {
for (char c = 'i'; c <= maxLoopVariableName; c++) {
if (!typeNames.ContainsKey(c.ToString())) {
typeNames.Add(c.ToString(), 1);
return c.ToString();
}
}
}
int number;
string nameWithoutDigits = SplitName(oldVariableName, out number);
if (!typeNames.ContainsKey(nameWithoutDigits)) {
typeNames.Add(nameWithoutDigits, number - 1);
}
int count = ++typeNames[nameWithoutDigits];
if (count != 1) {
return nameWithoutDigits + count.ToString();
} else {
return nameWithoutDigits;
}
}
string GenerateNameForVariable(ILVariable variable, ILBlock methodBody)
{
string proposedName = null;
if (variable.Type == context.CurrentType.Module.TypeSystem.Int32) {
// test whether the variable might be a loop counter
bool isLoopCounter = false;
foreach (ILWhileLoop loop in methodBody.GetSelfAndChildrenRecursive<ILWhileLoop>()) {
ILExpression expr = loop.Condition;
while (expr != null && expr.Code == ILCode.LogicNot)
expr = expr.Arguments[0];
if (expr != null) {
switch (expr.Code) {
case ILCode.Clt:
case ILCode.Clt_Un:
case ILCode.Cgt:
case ILCode.Cgt_Un:
case ILCode.Cle:
case ILCode.Cle_Un:
case ILCode.Cge:
case ILCode.Cge_Un:
ILVariable loadVar;
if (expr.Arguments[0].Match(ILCode.Ldloc, out loadVar) && loadVar == variable) {
isLoopCounter = true;
}
break;
}
}
}
if (isLoopCounter) {
// For loop variables, use i,j,k,l,m,n
for (char c = 'i'; c <= maxLoopVariableName; c++) {
if (!typeNames.ContainsKey(c.ToString())) {
proposedName = c.ToString();
break;
}
}
}
}
if (string.IsNullOrEmpty(proposedName)) {
var proposedNameForStores =
(from expr in methodBody.GetSelfAndChildrenRecursive<ILExpression>()
where expr.Code == ILCode.Stloc && expr.Operand == variable
select GetNameFromExpression(expr.Arguments.Single())
).Except(fieldNamesInCurrentType).ToList();
if (proposedNameForStores.Count == 1) {
proposedName = proposedNameForStores[0];
}
}
if (string.IsNullOrEmpty(proposedName)) {
var proposedNameForLoads =
(from expr in methodBody.GetSelfAndChildrenRecursive<ILExpression>()
from i in Enumerable.Range(0, expr.Arguments.Count)
let arg = expr.Arguments[i]
where arg.Code == ILCode.Ldloc && arg.Operand == variable
select GetNameForArgument(expr, i)
).Except(fieldNamesInCurrentType).ToList();
if (proposedNameForLoads.Count == 1) {
proposedName = proposedNameForLoads[0];
}
}
if (string.IsNullOrEmpty(proposedName)) {
proposedName = GetNameByType(variable.Type);
}
// remove any numbers from the proposed name
int number;
proposedName = SplitName(proposedName, out number);
if (!typeNames.ContainsKey(proposedName)) {
typeNames.Add(proposedName, 0);
}
int count = ++typeNames[proposedName];
if (count > 1) {
return proposedName + count.ToString();
} else {
return proposedName;
}
}
static string GetNameFromExpression(ILExpression expr)
{
switch (expr.Code) {
case ILCode.Ldfld:
case ILCode.Ldsfld:
return CleanUpVariableName(((FieldReference)expr.Operand).Name);
case ILCode.Call:
case ILCode.Callvirt:
case ILCode.CallGetter:
case ILCode.CallvirtGetter:
MethodReference mr = (MethodReference)expr.Operand;
if (mr.Name.StartsWith("get_", StringComparison.OrdinalIgnoreCase) && mr.Parameters.Count == 0) {
// use name from properties, but not from indexers
return CleanUpVariableName(mr.Name.Substring(4));
} else if (mr.Name.StartsWith("Get", StringComparison.OrdinalIgnoreCase) && mr.Name.Length >= 4 && char.IsUpper(mr.Name[3])) {
// use name from Get-methods
return CleanUpVariableName(mr.Name.Substring(3));
}
break;
}
return null;
}
static string GetNameForArgument(ILExpression parent, int i)
{
switch (parent.Code) {
case ILCode.Stfld:
case ILCode.Stsfld:
if (i == parent.Arguments.Count - 1) // last argument is stored value
return CleanUpVariableName(((FieldReference)parent.Operand).Name);
else
break;
case ILCode.Call:
case ILCode.Callvirt:
case ILCode.Newobj:
case ILCode.CallGetter:
case ILCode.CallvirtGetter:
case ILCode.CallSetter:
case ILCode.CallvirtSetter:
MethodReference methodRef = (MethodReference)parent.Operand;
if (methodRef.Parameters.Count == 1 && i == parent.Arguments.Count - 1) {
// argument might be value of a setter
if (methodRef.Name.StartsWith("set_", StringComparison.OrdinalIgnoreCase)) {
return CleanUpVariableName(methodRef.Name.Substring(4));
} else if (methodRef.Name.StartsWith("Set", StringComparison.OrdinalIgnoreCase) && methodRef.Name.Length >= 4 && char.IsUpper(methodRef.Name[3])) {
return CleanUpVariableName(methodRef.Name.Substring(3));
}
}
MethodDefinition methodDef = methodRef.Resolve();
if (methodDef != null) {
var p = methodDef.Parameters.ElementAtOrDefault((parent.Code != ILCode.Newobj && methodDef.HasThis) ? i - 1 : i);
if (p != null && !string.IsNullOrEmpty(p.Name))
return CleanUpVariableName(p.Name);
}
break;
case ILCode.Ret:
return "result";
}
return null;
}
string GetNameByType(TypeReference type)
{
type = TypeAnalysis.UnpackModifiers(type);
GenericInstanceType git = type as GenericInstanceType;
if (git != null && git.ElementType.FullName == "System.Nullable`1" && git.GenericArguments.Count == 1) {
type = ((GenericInstanceType)type).GenericArguments[0];
}
string name;
if (type.IsArray) {
name = "array";
} else if (type.IsPointer || type.IsByReference) {
name = "ptr";
} else if (type.Name.EndsWith("Exception", StringComparison.Ordinal)) {
name = "ex";
} else if (!typeNameToVariableNameDict.TryGetValue(type.FullName, out name)) {
name = type.Name;
// remove the 'I' for interfaces
if (name.Length >= 3 && name[0] == 'I' && char.IsUpper(name[1]) && char.IsLower(name[2]))
name = name.Substring(1);
name = CleanUpVariableName(name);
}
return name;
}
static string CleanUpVariableName(string name)
{
// remove the backtick (generics)
int pos = name.IndexOf('`');
if (pos >= 0)
name = name.Substring(0, pos);
// remove field prefix:
if (name.Length > 2 && name.StartsWith("m_", StringComparison.Ordinal))
name = name.Substring(2);
else if (name.Length > 1 && name[0] == '_' && (char.IsLetter(name[1]) || name[1] == '_'))
name = name.Substring(1);
if (name.Length == 0)
return "obj";
else
return char.ToLower(name[0]) + name.Substring(1);
}
}
}

373
ICSharpCode.Decompiler/Ast/TextTokenWriter.cs

@ -1,373 +0,0 @@ @@ -1,373 +0,0 @@
// Copyright (c) 2011 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.Linq;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast
{
public class TextTokenWriter : TokenWriter
{
readonly ITextOutput output;
readonly DecompilerContext context;
readonly Stack<AstNode> nodeStack = new Stack<AstNode>();
int braceLevelWithinType = -1;
bool inDocumentationComment = false;
bool firstUsingDeclaration;
bool lastUsingDeclaration;
TextLocation? lastEndOfLine;
public bool FoldBraces = false;
public TextTokenWriter(ITextOutput output, DecompilerContext context)
{
if (output == null)
throw new ArgumentNullException("output");
if (context == null)
throw new ArgumentNullException("context");
this.output = output;
this.context = context;
}
public override void WriteIdentifier(Identifier identifier)
{
if (identifier.IsVerbatim || CSharpOutputVisitor.IsKeyword(identifier.Name, identifier)) {
output.Write('@');
}
var definition = GetCurrentDefinition();
if (definition != null) {
output.WriteDefinition(identifier.Name, definition, false);
return;
}
object memberRef = GetCurrentMemberReference();
if (memberRef != null) {
output.WriteReference(identifier.Name, memberRef);
return;
}
definition = GetCurrentLocalDefinition();
if (definition != null) {
output.WriteDefinition(identifier.Name, definition);
return;
}
memberRef = GetCurrentLocalReference();
if (memberRef != null) {
output.WriteReference(identifier.Name, memberRef, true);
return;
}
if (firstUsingDeclaration) {
output.MarkFoldStart(defaultCollapsed: true);
firstUsingDeclaration = false;
}
output.Write(identifier.Name);
}
MemberReference GetCurrentMemberReference()
{
AstNode node = nodeStack.Peek();
MemberReference memberRef = node.Annotation<MemberReference>();
if (memberRef == null && node.Role == Roles.TargetExpression && (node.Parent is InvocationExpression || node.Parent is ObjectCreateExpression)) {
memberRef = node.Parent.Annotation<MemberReference>();
}
if (node is IdentifierExpression && node.Role == Roles.TargetExpression && node.Parent is InvocationExpression && memberRef != null) {
var declaringType = memberRef.DeclaringType.Resolve();
if (declaringType != null && declaringType.IsDelegate())
return null;
}
return FilterMemberReference(memberRef);
}
MemberReference FilterMemberReference(MemberReference memberRef)
{
if (memberRef == null)
return null;
if (context.Settings.AutomaticEvents && memberRef is FieldDefinition) {
var field = (FieldDefinition)memberRef;
return field.DeclaringType.Events.FirstOrDefault(ev => ev.Name == field.Name) ?? memberRef;
}
return memberRef;
}
object GetCurrentLocalReference()
{
AstNode node = nodeStack.Peek();
ILVariable variable = node.Annotation<ILVariable>();
if (variable != null) {
if (variable.OriginalParameter != null)
return variable.OriginalParameter;
//if (variable.OriginalVariable != null)
// return variable.OriginalVariable;
return variable;
}
var gotoStatement = node as GotoStatement;
if (gotoStatement != null)
{
var method = nodeStack.Select(nd => nd.Annotation<MethodReference>()).FirstOrDefault(mr => mr != null);
if (method != null)
return method.ToString() + gotoStatement.Label;
}
return null;
}
object GetCurrentLocalDefinition()
{
AstNode node = nodeStack.Peek();
if (node is Identifier && node.Parent != null)
node = node.Parent;
var parameterDef = node.Annotation<ParameterDefinition>();
if (parameterDef != null)
return parameterDef;
if (node is VariableInitializer || node is CatchClause || node is ForeachStatement) {
var variable = node.Annotation<ILVariable>();
if (variable != null) {
if (variable.OriginalParameter != null)
return variable.OriginalParameter;
//if (variable.OriginalVariable != null)
// return variable.OriginalVariable;
return variable;
}
}
var label = node as LabelStatement;
if (label != null) {
var method = nodeStack.Select(nd => nd.Annotation<MethodReference>()).FirstOrDefault(mr => mr != null);
if (method != null)
return method.ToString() + label.Label;
}
return null;
}
object GetCurrentDefinition()
{
if (nodeStack == null || nodeStack.Count == 0)
return null;
var node = nodeStack.Peek();
if (node is Identifier)
node = node.Parent;
if (IsDefinition(node))
return node.Annotation<MemberReference>();
return null;
}
public override void WriteKeyword(Role role, string keyword)
{
output.Write(keyword);
}
public override void WriteToken(Role role, string token)
{
// Attach member reference to token only if there's no identifier in the current node.
MemberReference memberRef = GetCurrentMemberReference();
var node = nodeStack.Peek();
if (memberRef != null && node.GetChildByRole(Roles.Identifier).IsNull)
output.WriteReference(token, memberRef);
else
output.Write(token);
}
public override void Space()
{
output.Write(' ');
}
public void OpenBrace(BraceStyle style)
{
if (braceLevelWithinType >= 0 || nodeStack.Peek() is TypeDeclaration)
braceLevelWithinType++;
if (nodeStack.OfType<BlockStatement>().Count() <= 1 || FoldBraces) {
output.MarkFoldStart(defaultCollapsed: braceLevelWithinType == 1);
}
output.WriteLine();
output.WriteLine("{");
output.Indent();
}
public void CloseBrace(BraceStyle style)
{
output.Unindent();
output.Write('}');
if (nodeStack.OfType<BlockStatement>().Count() <= 1 || FoldBraces)
output.MarkFoldEnd();
if (braceLevelWithinType >= 0)
braceLevelWithinType--;
}
public override void Indent()
{
output.Indent();
}
public override void Unindent()
{
output.Unindent();
}
public override void NewLine()
{
if (lastUsingDeclaration) {
output.MarkFoldEnd();
lastUsingDeclaration = false;
}
lastEndOfLine = output.Location;
output.WriteLine();
}
public override void WriteComment(CommentType commentType, string content)
{
switch (commentType) {
case CommentType.SingleLine:
output.Write("//");
output.WriteLine(content);
break;
case CommentType.MultiLine:
output.Write("/*");
output.Write(content);
output.Write("*/");
break;
case CommentType.Documentation:
bool isLastLine = !(nodeStack.Peek().NextSibling is Comment);
if (!inDocumentationComment && !isLastLine) {
inDocumentationComment = true;
output.MarkFoldStart("///" + content, true);
}
output.Write("///");
output.Write(content);
if (inDocumentationComment && isLastLine) {
inDocumentationComment = false;
output.MarkFoldEnd();
}
output.WriteLine();
break;
default:
output.Write(content);
break;
}
}
public override void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument)
{
// pre-processor directive must start on its own line
output.Write('#');
output.Write(type.ToString().ToLowerInvariant());
if (!string.IsNullOrEmpty(argument)) {
output.Write(' ');
output.Write(argument);
}
output.WriteLine();
}
public override void WritePrimitiveValue(object value, string literalValue = null)
{
new TextWriterTokenWriter(new TextOutputWriter(output)).WritePrimitiveValue(value, literalValue);
}
public override void WritePrimitiveType(string type)
{
output.Write(type);
if (type == "new") {
output.Write("()");
}
}
Stack<TextLocation> startLocations = new Stack<TextLocation>();
Stack<MethodDebugSymbols> symbolsStack = new Stack<MethodDebugSymbols>();
public override void StartNode(AstNode node)
{
if (nodeStack.Count == 0) {
if (IsUsingDeclaration(node)) {
firstUsingDeclaration = !IsUsingDeclaration(node.PrevSibling);
lastUsingDeclaration = !IsUsingDeclaration(node.NextSibling);
} else {
firstUsingDeclaration = false;
lastUsingDeclaration = false;
}
}
nodeStack.Push(node);
startLocations.Push(output.Location);
if (node is EntityDeclaration && node.Annotation<MemberReference>() != null && node.GetChildByRole(Roles.Identifier).IsNull)
output.WriteDefinition("", node.Annotation<MemberReference>(), false);
if (node.Annotation<MethodDebugSymbols>() != null) {
symbolsStack.Push(node.Annotation<MethodDebugSymbols>());
symbolsStack.Peek().StartLocation = startLocations.Peek();
}
}
private bool IsUsingDeclaration(AstNode node)
{
return node is UsingDeclaration || node is UsingAliasDeclaration;
}
public override void EndNode(AstNode node)
{
if (nodeStack.Pop() != node)
throw new InvalidOperationException();
var startLocation = startLocations.Pop();
// code mappings
var ranges = node.Annotation<List<ILRange>>();
if (symbolsStack.Count > 0 && ranges != null && ranges.Count > 0) {
// Ignore the newline which was printed at the end of the statement
TextLocation endLocation = (node is Statement) ? (lastEndOfLine ?? output.Location) : output.Location;
symbolsStack.Peek().SequencePoints.Add(
new SequencePoint() {
ILRanges = ILRange.OrderAndJoin(ranges).ToArray(),
StartLocation = startLocation,
EndLocation = endLocation
});
}
if (node.Annotation<MethodDebugSymbols>() != null) {
symbolsStack.Peek().EndLocation = output.Location;
output.AddDebugSymbols(symbolsStack.Pop());
}
}
private static bool IsDefinition(AstNode node)
{
return node is EntityDeclaration
|| (node is VariableInitializer && node.Parent is FieldDeclaration)
|| node is FixedVariableInitializer;
}
}
}

784
ICSharpCode.Decompiler/CSharp/Analysis/ControlFlow.cs

@ -1,784 +0,0 @@ @@ -1,784 +0,0 @@
// 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 System.Threading;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.TypeSystem;
using ICSharpCode.Decompiler.Semantics;
namespace ICSharpCode.Decompiler.CSharp.Analysis
{
/// <summary>
/// Represents a node in the control flow graph of a C# method.
/// </summary>
public class ControlFlowNode
{
public readonly Statement PreviousStatement;
public readonly Statement NextStatement;
public readonly ControlFlowNodeType Type;
public readonly List<ControlFlowEdge> Outgoing = new List<ControlFlowEdge>();
public readonly List<ControlFlowEdge> Incoming = new List<ControlFlowEdge>();
public ControlFlowNode(Statement previousStatement, Statement nextStatement, ControlFlowNodeType type)
{
if (previousStatement == null && nextStatement == null)
throw new ArgumentException("previousStatement and nextStatement must not be both null");
this.PreviousStatement = previousStatement;
this.NextStatement = nextStatement;
this.Type = type;
}
}
public enum ControlFlowNodeType
{
/// <summary>
/// Unknown node type
/// </summary>
None,
/// <summary>
/// Node in front of a statement
/// </summary>
StartNode,
/// <summary>
/// Node between two statements
/// </summary>
BetweenStatements,
/// <summary>
/// Node at the end of a statement list
/// </summary>
EndNode,
/// <summary>
/// Node representing the position before evaluating the condition of a loop.
/// </summary>
LoopCondition
}
public class ControlFlowEdge
{
public readonly ControlFlowNode From;
public readonly ControlFlowNode To;
public readonly ControlFlowEdgeType Type;
List<TryCatchStatement> jumpOutOfTryFinally;
public ControlFlowEdge(ControlFlowNode from, ControlFlowNode to, ControlFlowEdgeType type)
{
if (from == null)
throw new ArgumentNullException("from");
if (to == null)
throw new ArgumentNullException("to");
this.From = from;
this.To = to;
this.Type = type;
}
internal void AddJumpOutOfTryFinally(TryCatchStatement tryFinally)
{
if (jumpOutOfTryFinally == null)
jumpOutOfTryFinally = new List<TryCatchStatement>();
jumpOutOfTryFinally.Add(tryFinally);
}
/// <summary>
/// Gets whether this control flow edge is leaving any try-finally statements.
/// </summary>
public bool IsLeavingTryFinally {
get { return jumpOutOfTryFinally != null; }
}
/// <summary>
/// Gets the try-finally statements that this control flow edge is leaving.
/// </summary>
public IEnumerable<TryCatchStatement> TryFinallyStatements {
get { return jumpOutOfTryFinally ?? Enumerable.Empty<TryCatchStatement>(); }
}
}
public enum ControlFlowEdgeType
{
/// <summary>
/// Regular control flow.
/// </summary>
Normal,
/// <summary>
/// Conditional control flow (edge taken if condition is true)
/// </summary>
ConditionTrue,
/// <summary>
/// Conditional control flow (edge taken if condition is false)
/// </summary>
ConditionFalse,
/// <summary>
/// A jump statement (goto, goto case, break or continue)
/// </summary>
Jump
}
/// <summary>
/// Constructs the control flow graph for C# statements.
/// </summary>
public class ControlFlowGraphBuilder
{
// Written according to the reachability rules in the C# spec (§8.1 End points and reachability)
protected virtual ControlFlowNode CreateNode(Statement previousStatement, Statement nextStatement, ControlFlowNodeType type)
{
cancellationToken.ThrowIfCancellationRequested();
return new ControlFlowNode(previousStatement, nextStatement, type);
}
protected virtual ControlFlowEdge CreateEdge(ControlFlowNode from, ControlFlowNode to, ControlFlowEdgeType type)
{
cancellationToken.ThrowIfCancellationRequested();
return new ControlFlowEdge(from, to, type);
}
Statement rootStatement;
CSharpTypeResolveContext typeResolveContext;
Func<AstNode, CancellationToken, ResolveResult> resolver;
List<ControlFlowNode> nodes;
Dictionary<string, ControlFlowNode> labels;
List<ControlFlowNode> gotoStatements;
CancellationToken cancellationToken;
internal IList<ControlFlowNode> BuildControlFlowGraph(Statement statement, Func<AstNode, CancellationToken, ResolveResult> resolver, CSharpTypeResolveContext typeResolveContext, CancellationToken cancellationToken)
{
NodeCreationVisitor nodeCreationVisitor = new NodeCreationVisitor();
nodeCreationVisitor.builder = this;
try {
this.nodes = new List<ControlFlowNode>();
this.labels = new Dictionary<string, ControlFlowNode>();
this.gotoStatements = new List<ControlFlowNode>();
this.rootStatement = statement;
this.resolver = resolver;
this.typeResolveContext = typeResolveContext;
this.cancellationToken = cancellationToken;
ControlFlowNode entryPoint = CreateStartNode(statement);
statement.AcceptVisitor(nodeCreationVisitor, entryPoint);
// Resolve goto statements:
foreach (ControlFlowNode gotoStmt in gotoStatements) {
string label = ((GotoStatement)gotoStmt.NextStatement).Label;
ControlFlowNode labelNode;
if (labels.TryGetValue(label, out labelNode))
nodeCreationVisitor.Connect(gotoStmt, labelNode, ControlFlowEdgeType.Jump);
}
AnnotateLeaveEdgesWithTryFinallyBlocks();
return nodes;
} finally {
this.nodes = null;
this.labels = null;
this.gotoStatements = null;
this.rootStatement = null;
this.resolver = null;
this.typeResolveContext = null;
this.cancellationToken = CancellationToken.None;
}
}
void AnnotateLeaveEdgesWithTryFinallyBlocks()
{
foreach (ControlFlowEdge edge in nodes.SelectMany(n => n.Outgoing)) {
if (edge.Type != ControlFlowEdgeType.Jump) {
// Only jumps are potential candidates for leaving try-finally blocks.
// Note that the regular edges leaving try or catch blocks are already annotated by the visitor.
continue;
}
Statement gotoStatement = edge.From.NextStatement;
Debug.Assert(gotoStatement is GotoStatement || gotoStatement is GotoDefaultStatement || gotoStatement is GotoCaseStatement || gotoStatement is BreakStatement || gotoStatement is ContinueStatement);
Statement targetStatement = edge.To.PreviousStatement ?? edge.To.NextStatement;
if (gotoStatement.Parent == targetStatement.Parent)
continue;
HashSet<TryCatchStatement> targetParentTryCatch = new HashSet<TryCatchStatement>(targetStatement.Ancestors.OfType<TryCatchStatement>());
for (AstNode node = gotoStatement.Parent; node != null; node = node.Parent) {
TryCatchStatement leftTryCatch = node as TryCatchStatement;
if (leftTryCatch != null) {
if (targetParentTryCatch.Contains(leftTryCatch))
break;
if (!leftTryCatch.FinallyBlock.IsNull)
edge.AddJumpOutOfTryFinally(leftTryCatch);
}
}
}
}
#region Create*Node
ControlFlowNode CreateStartNode(Statement statement)
{
if (statement.IsNull)
return null;
ControlFlowNode node = CreateNode(null, statement, ControlFlowNodeType.StartNode);
nodes.Add(node);
return node;
}
ControlFlowNode CreateSpecialNode(Statement statement, ControlFlowNodeType type, bool addToNodeList = true)
{
ControlFlowNode node = CreateNode(null, statement, type);
if (addToNodeList)
nodes.Add(node);
return node;
}
ControlFlowNode CreateEndNode(Statement statement, bool addToNodeList = true)
{
Statement nextStatement;
if (statement == rootStatement) {
nextStatement = null;
} else {
// Find the next statement in the same role:
AstNode next = statement;
do {
next = next.NextSibling;
} while (next != null && next.Role != statement.Role);
nextStatement = next as Statement;
}
ControlFlowNodeType type = nextStatement != null ? ControlFlowNodeType.BetweenStatements : ControlFlowNodeType.EndNode;
ControlFlowNode node = CreateNode(statement, nextStatement, type);
if (addToNodeList)
nodes.Add(node);
return node;
}
#endregion
#region Constant evaluation
/// <summary>
/// Gets/Sets whether to handle only primitive expressions as constants (no complex expressions like "a + b").
/// </summary>
public bool EvaluateOnlyPrimitiveConstants { get; set; }
/// <summary>
/// Evaluates an expression.
/// </summary>
/// <returns>The constant value of the expression; or null if the expression is not a constant.</returns>
ResolveResult EvaluateConstant(Expression expr)
{
if (expr.IsNull)
return null;
if (EvaluateOnlyPrimitiveConstants) {
if (!(expr is PrimitiveExpression || expr is NullReferenceExpression))
return null;
}
return resolver(expr, cancellationToken);
}
/// <summary>
/// Evaluates an expression.
/// </summary>
/// <returns>The value of the constant boolean expression; or null if the value is not a constant boolean expression.</returns>
bool? EvaluateCondition(Expression expr)
{
ResolveResult rr = EvaluateConstant(expr);
if (rr != null && rr.IsCompileTimeConstant)
return rr.ConstantValue as bool?;
else
return null;
}
bool AreEqualConstants(ResolveResult c1, ResolveResult c2)
{
if (c1 == null || c2 == null || !c1.IsCompileTimeConstant || !c2.IsCompileTimeConstant)
return false;
CSharpResolver r = new CSharpResolver(typeResolveContext);
ResolveResult c = r.ResolveBinaryOperator(BinaryOperatorType.Equality, c1, c2);
return c.IsCompileTimeConstant && (c.ConstantValue as bool?) == true;
}
#endregion
sealed class NodeCreationVisitor : DepthFirstAstVisitor<ControlFlowNode, ControlFlowNode>
{
// 'data' parameter: input control flow node (start of statement being visited)
// Return value: result control flow node (end of statement being visited)
internal ControlFlowGraphBuilder builder;
Stack<ControlFlowNode> breakTargets = new Stack<ControlFlowNode>();
Stack<ControlFlowNode> continueTargets = new Stack<ControlFlowNode>();
List<ControlFlowNode> gotoCaseOrDefault = new List<ControlFlowNode>();
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);
return edge;
}
/// <summary>
/// Creates an end node for <c>stmt</c> and connects <c>from</c> with the new node.
/// </summary>
ControlFlowNode CreateConnectedEndNode(Statement stmt, ControlFlowNode from)
{
ControlFlowNode newNode = builder.CreateEndNode(stmt);
Connect(from, newNode);
return newNode;
}
protected override ControlFlowNode VisitChildren(AstNode node, ControlFlowNode data)
{
// We have overrides for all possible statements and should visit statements only.
throw new NotSupportedException();
}
public override ControlFlowNode VisitBlockStatement(BlockStatement blockStatement, ControlFlowNode data)
{
// C# 4.0 spec: §8.2 Blocks
ControlFlowNode childNode = HandleStatementList(blockStatement.Statements, data);
return CreateConnectedEndNode(blockStatement, childNode);
}
ControlFlowNode HandleStatementList(AstNodeCollection<Statement> statements, ControlFlowNode source)
{
ControlFlowNode childNode = null;
foreach (Statement stmt in statements) {
if (childNode == null) {
childNode = builder.CreateStartNode(stmt);
if (source != null)
Connect(source, childNode);
}
Debug.Assert(childNode.NextStatement == stmt);
childNode = stmt.AcceptVisitor(this, childNode);
Debug.Assert(childNode.PreviousStatement == stmt);
}
return childNode ?? source;
}
public override ControlFlowNode VisitEmptyStatement(EmptyStatement emptyStatement, ControlFlowNode data)
{
return CreateConnectedEndNode(emptyStatement, data);
}
public override ControlFlowNode VisitLabelStatement(LabelStatement labelStatement, ControlFlowNode data)
{
ControlFlowNode end = CreateConnectedEndNode(labelStatement, data);
builder.labels[labelStatement.Label] = end;
return end;
}
public override ControlFlowNode VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement, ControlFlowNode data)
{
return CreateConnectedEndNode(variableDeclarationStatement, data);
}
public override ControlFlowNode VisitExpressionStatement(ExpressionStatement expressionStatement, ControlFlowNode data)
{
return CreateConnectedEndNode(expressionStatement, data);
}
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 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);
Connect(trueEnd, end);
if (falseEnd != null) {
Connect(falseEnd, end);
} else if (cond != true) {
Connect(data, end, ControlFlowEdgeType.ConditionFalse);
}
return end;
}
public override ControlFlowNode VisitSwitchStatement(SwitchStatement switchStatement, ControlFlowNode data)
{
// First, figure out which switch section will get called (if the expression is constant):
ResolveResult constant = builder.EvaluateConstant(switchStatement.Expression);
SwitchSection defaultSection = null;
SwitchSection sectionMatchedByConstant = null;
foreach (SwitchSection section in switchStatement.SwitchSections) {
foreach (CaseLabel label in section.CaseLabels) {
if (label.Expression.IsNull) {
defaultSection = section;
} else if (constant != null && constant.IsCompileTimeConstant) {
ResolveResult labelConstant = builder.EvaluateConstant(label.Expression);
if (builder.AreEqualConstants(constant, labelConstant))
sectionMatchedByConstant = section;
}
}
}
if (constant != null && constant.IsCompileTimeConstant && sectionMatchedByConstant == null)
sectionMatchedByConstant = defaultSection;
int gotoCaseOrDefaultInOuterScope = gotoCaseOrDefault.Count;
List<ControlFlowNode> sectionStartNodes = new List<ControlFlowNode>();
ControlFlowNode end = builder.CreateEndNode(switchStatement, addToNodeList: false);
breakTargets.Push(end);
foreach (SwitchSection section in switchStatement.SwitchSections) {
int sectionStartNodeID = builder.nodes.Count;
if (constant == null || !constant.IsCompileTimeConstant || section == sectionMatchedByConstant) {
HandleStatementList(section.Statements, data);
} else {
// This section is unreachable: pass null to HandleStatementList.
HandleStatementList(section.Statements, null);
}
// Don't bother connecting the ends of the sections: the 'break' statement takes care of that.
// Store the section start node for 'goto case' statements.
sectionStartNodes.Add(sectionStartNodeID < builder.nodes.Count ? builder.nodes[sectionStartNodeID] : null);
}
breakTargets.Pop();
if (defaultSection == null && sectionMatchedByConstant == null) {
Connect(data, end);
}
if (gotoCaseOrDefault.Count > gotoCaseOrDefaultInOuterScope) {
// Resolve 'goto case' statements:
for (int i = gotoCaseOrDefaultInOuterScope; i < gotoCaseOrDefault.Count; i++) {
ControlFlowNode gotoCaseNode = gotoCaseOrDefault[i];
GotoCaseStatement gotoCaseStatement = gotoCaseNode.NextStatement as GotoCaseStatement;
ResolveResult gotoCaseConstant = null;
if (gotoCaseStatement != null) {
gotoCaseConstant = builder.EvaluateConstant(gotoCaseStatement.LabelExpression);
}
int targetSectionIndex = -1;
int currentSectionIndex = 0;
foreach (SwitchSection section in switchStatement.SwitchSections) {
foreach (CaseLabel label in section.CaseLabels) {
if (gotoCaseStatement != null) {
// goto case
if (!label.Expression.IsNull) {
ResolveResult labelConstant = builder.EvaluateConstant(label.Expression);
if (builder.AreEqualConstants(gotoCaseConstant, labelConstant))
targetSectionIndex = currentSectionIndex;
}
} else {
// goto default
if (label.Expression.IsNull)
targetSectionIndex = currentSectionIndex;
}
}
currentSectionIndex++;
}
if (targetSectionIndex >= 0 && sectionStartNodes[targetSectionIndex] != null)
Connect(gotoCaseNode, sectionStartNodes[targetSectionIndex], ControlFlowEdgeType.Jump);
else
Connect(gotoCaseNode, end, ControlFlowEdgeType.Jump);
}
gotoCaseOrDefault.RemoveRange(gotoCaseOrDefaultInOuterScope, gotoCaseOrDefault.Count - gotoCaseOrDefaultInOuterScope);
}
builder.nodes.Add(end);
return end;
}
public override ControlFlowNode VisitGotoCaseStatement(GotoCaseStatement gotoCaseStatement, ControlFlowNode data)
{
gotoCaseOrDefault.Add(data);
return builder.CreateEndNode(gotoCaseStatement);
}
public override ControlFlowNode VisitGotoDefaultStatement(GotoDefaultStatement gotoDefaultStatement, ControlFlowNode data)
{
gotoCaseOrDefault.Add(data);
return builder.CreateEndNode(gotoDefaultStatement);
}
public override ControlFlowNode VisitWhileStatement(WhileStatement whileStatement, ControlFlowNode data)
{
// <data> <condition> while (cond) { <bodyStart> embeddedStmt; <bodyEnd> } <end>
ControlFlowNode end = builder.CreateEndNode(whileStatement, addToNodeList: false);
ControlFlowNode conditionNode = builder.CreateSpecialNode(whileStatement, ControlFlowNodeType.LoopCondition);
breakTargets.Push(end);
continueTargets.Push(conditionNode);
Connect(data, conditionNode);
bool? cond = builder.EvaluateCondition(whileStatement.Condition);
ControlFlowNode bodyStart = builder.CreateStartNode(whileStatement.EmbeddedStatement);
if (cond != false)
Connect(conditionNode, bodyStart, ControlFlowEdgeType.ConditionTrue);
ControlFlowNode bodyEnd = whileStatement.EmbeddedStatement.AcceptVisitor(this, bodyStart);
Connect(bodyEnd, conditionNode);
if (cond != true)
Connect(conditionNode, end, ControlFlowEdgeType.ConditionFalse);
breakTargets.Pop();
continueTargets.Pop();
builder.nodes.Add(end);
return end;
}
public override ControlFlowNode VisitDoWhileStatement(DoWhileStatement doWhileStatement, ControlFlowNode data)
{
// <data> do { <bodyStart> embeddedStmt; <bodyEnd>} <condition> while(cond); <end>
ControlFlowNode end = builder.CreateEndNode(doWhileStatement, addToNodeList: false);
ControlFlowNode conditionNode = builder.CreateSpecialNode(doWhileStatement, ControlFlowNodeType.LoopCondition, addToNodeList: false);
breakTargets.Push(end);
continueTargets.Push(conditionNode);
ControlFlowNode bodyStart = builder.CreateStartNode(doWhileStatement.EmbeddedStatement);
Connect(data, bodyStart);
ControlFlowNode bodyEnd = doWhileStatement.EmbeddedStatement.AcceptVisitor(this, bodyStart);
Connect(bodyEnd, conditionNode);
bool? cond = builder.EvaluateCondition(doWhileStatement.Condition);
if (cond != false)
Connect(conditionNode, bodyStart, ControlFlowEdgeType.ConditionTrue);
if (cond != true)
Connect(conditionNode, end, ControlFlowEdgeType.ConditionFalse);
breakTargets.Pop();
continueTargets.Pop();
builder.nodes.Add(conditionNode);
builder.nodes.Add(end);
return end;
}
public override ControlFlowNode VisitForStatement(ForStatement forStatement, ControlFlowNode data)
{
data = HandleStatementList(forStatement.Initializers, data);
// for (initializers <data>; <condition>cond; <iteratorStart>iterators<iteratorEnd>) { <bodyStart> embeddedStmt; <bodyEnd> } <end>
ControlFlowNode end = builder.CreateEndNode(forStatement, addToNodeList: false);
ControlFlowNode conditionNode = builder.CreateSpecialNode(forStatement, ControlFlowNodeType.LoopCondition);
Connect(data, conditionNode);
int iteratorStartNodeID = builder.nodes.Count;
ControlFlowNode iteratorEnd = HandleStatementList(forStatement.Iterators, null);
ControlFlowNode iteratorStart;
if (iteratorEnd != null) {
iteratorStart = builder.nodes[iteratorStartNodeID];
Connect(iteratorEnd, conditionNode);
} else {
iteratorStart = conditionNode;
}
breakTargets.Push(end);
continueTargets.Push(iteratorStart);
ControlFlowNode bodyStart = builder.CreateStartNode(forStatement.EmbeddedStatement);
ControlFlowNode bodyEnd = forStatement.EmbeddedStatement.AcceptVisitor(this, bodyStart);
Connect(bodyEnd, iteratorStart);
breakTargets.Pop();
continueTargets.Pop();
bool? cond = forStatement.Condition.IsNull ? true : builder.EvaluateCondition(forStatement.Condition);
if (cond != false)
Connect(conditionNode, bodyStart, ControlFlowEdgeType.ConditionTrue);
if (cond != true)
Connect(conditionNode, end, ControlFlowEdgeType.ConditionFalse);
builder.nodes.Add(end);
return end;
}
ControlFlowNode HandleEmbeddedStatement(Statement embeddedStatement, ControlFlowNode source)
{
if (embeddedStatement == null || embeddedStatement.IsNull)
return source;
ControlFlowNode bodyStart = builder.CreateStartNode(embeddedStatement);
if (source != null)
Connect(source, bodyStart);
return embeddedStatement.AcceptVisitor(this, bodyStart);
}
public override ControlFlowNode VisitForeachStatement(ForeachStatement foreachStatement, ControlFlowNode data)
{
// <data> foreach (<condition>...) { <bodyStart>embeddedStmt<bodyEnd> } <end>
ControlFlowNode end = builder.CreateEndNode(foreachStatement, addToNodeList: false);
ControlFlowNode conditionNode = builder.CreateSpecialNode(foreachStatement, ControlFlowNodeType.LoopCondition);
Connect(data, conditionNode);
breakTargets.Push(end);
continueTargets.Push(conditionNode);
ControlFlowNode bodyEnd = HandleEmbeddedStatement(foreachStatement.EmbeddedStatement, conditionNode);
Connect(bodyEnd, conditionNode);
breakTargets.Pop();
continueTargets.Pop();
Connect(conditionNode, end);
builder.nodes.Add(end);
return end;
}
public override ControlFlowNode VisitBreakStatement(BreakStatement breakStatement, ControlFlowNode data)
{
if (breakTargets.Count > 0)
Connect(data, breakTargets.Peek(), ControlFlowEdgeType.Jump);
return builder.CreateEndNode(breakStatement);
}
public override ControlFlowNode VisitContinueStatement(ContinueStatement continueStatement, ControlFlowNode data)
{
if (continueTargets.Count > 0)
Connect(data, continueTargets.Peek(), ControlFlowEdgeType.Jump);
return builder.CreateEndNode(continueStatement);
}
public override ControlFlowNode VisitGotoStatement(GotoStatement gotoStatement, ControlFlowNode data)
{
builder.gotoStatements.Add(data);
return builder.CreateEndNode(gotoStatement);
}
public override ControlFlowNode VisitReturnStatement(ReturnStatement returnStatement, ControlFlowNode data)
{
return builder.CreateEndNode(returnStatement); // end not connected with data
}
public override ControlFlowNode VisitThrowStatement(ThrowStatement throwStatement, ControlFlowNode data)
{
return builder.CreateEndNode(throwStatement); // end not connected with data
}
public override ControlFlowNode VisitTryCatchStatement(TryCatchStatement tryCatchStatement, ControlFlowNode data)
{
ControlFlowNode end = builder.CreateEndNode(tryCatchStatement, addToNodeList: false);
var edge = Connect(HandleEmbeddedStatement(tryCatchStatement.TryBlock, data), end);
if (!tryCatchStatement.FinallyBlock.IsNull)
edge.AddJumpOutOfTryFinally(tryCatchStatement);
foreach (CatchClause cc in tryCatchStatement.CatchClauses) {
edge = Connect(HandleEmbeddedStatement(cc.Body, data), end);
if (!tryCatchStatement.FinallyBlock.IsNull)
edge.AddJumpOutOfTryFinally(tryCatchStatement);
}
if (!tryCatchStatement.FinallyBlock.IsNull) {
// Don't connect the end of the try-finally block to anything.
// Consumers of the CFG will have to special-case try-finally.
HandleEmbeddedStatement(tryCatchStatement.FinallyBlock, data);
}
builder.nodes.Add(end);
return end;
}
public override ControlFlowNode VisitCheckedStatement(CheckedStatement checkedStatement, ControlFlowNode data)
{
ControlFlowNode bodyEnd = HandleEmbeddedStatement(checkedStatement.Body, data);
return CreateConnectedEndNode(checkedStatement, bodyEnd);
}
public override ControlFlowNode VisitUncheckedStatement(UncheckedStatement uncheckedStatement, ControlFlowNode data)
{
ControlFlowNode bodyEnd = HandleEmbeddedStatement(uncheckedStatement.Body, data);
return CreateConnectedEndNode(uncheckedStatement, bodyEnd);
}
public override ControlFlowNode VisitLockStatement(LockStatement lockStatement, ControlFlowNode data)
{
ControlFlowNode bodyEnd = HandleEmbeddedStatement(lockStatement.EmbeddedStatement, data);
return CreateConnectedEndNode(lockStatement, bodyEnd);
}
public override ControlFlowNode VisitUsingStatement(UsingStatement usingStatement, ControlFlowNode data)
{
data = HandleEmbeddedStatement(usingStatement.ResourceAcquisition as Statement, data);
ControlFlowNode bodyEnd = HandleEmbeddedStatement(usingStatement.EmbeddedStatement, data);
return CreateConnectedEndNode(usingStatement, bodyEnd);
}
public override ControlFlowNode VisitYieldReturnStatement(YieldReturnStatement yieldStatement, ControlFlowNode data)
{
return CreateConnectedEndNode(yieldStatement, data);
}
public override ControlFlowNode VisitYieldBreakStatement(YieldBreakStatement yieldBreakStatement, ControlFlowNode data)
{
return builder.CreateEndNode(yieldBreakStatement); // end not connected with data
}
public override ControlFlowNode VisitUnsafeStatement(UnsafeStatement unsafeStatement, ControlFlowNode data)
{
ControlFlowNode bodyEnd = HandleEmbeddedStatement(unsafeStatement.Body, data);
return CreateConnectedEndNode(unsafeStatement, bodyEnd);
}
public override ControlFlowNode VisitFixedStatement(FixedStatement fixedStatement, ControlFlowNode data)
{
ControlFlowNode bodyEnd = HandleEmbeddedStatement(fixedStatement.EmbeddedStatement, data);
return CreateConnectedEndNode(fixedStatement, bodyEnd);
}
}
/// <summary>
/// Debugging helper that exports a control flow graph.
/// </summary>
//public static GraphVizGraph ExportGraph(IList<ControlFlowNode> nodes)
//{
// GraphVizGraph g = new GraphVizGraph();
// GraphVizNode[] n = new GraphVizNode[nodes.Count];
// Dictionary<ControlFlowNode, int> dict = new Dictionary<ControlFlowNode, int>();
// 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;
//}
}
}

750
ICSharpCode.Decompiler/CSharp/Analysis/DefiniteAssignmentAnalysis.cs

@ -1,750 +0,0 @@ @@ -1,750 +0,0 @@
// 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 System.Threading;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.TypeSystem;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
namespace ICSharpCode.Decompiler.CSharp.Analysis
{
/// <summary>
/// Represents the definite assignment status of a variable at a specific location.
/// </summary>
public enum DefiniteAssignmentStatus
{
/// <summary>
/// The variable might be assigned or unassigned.
/// </summary>
PotentiallyAssigned,
/// <summary>
/// The variable is definitely assigned.
/// </summary>
DefinitelyAssigned,
/// <summary>
/// The variable is definitely assigned iff the expression results in the value 'true'.
/// </summary>
AssignedAfterTrueExpression,
/// <summary>
/// The variable is definitely assigned iff the expression results in the value 'false'.
/// </summary>
AssignedAfterFalseExpression,
/// <summary>
/// The code is unreachable.
/// </summary>
CodeUnreachable
}
/// <summary>
/// Implements the C# definite assignment analysis (C# 4.0 Spec: §5.3 Definite assignment)
/// </summary>
public class DefiniteAssignmentAnalysis
{
sealed class DefiniteAssignmentNode : ControlFlowNode
{
public int Index;
public DefiniteAssignmentStatus NodeStatus;
public DefiniteAssignmentNode(Statement previousStatement, Statement nextStatement, ControlFlowNodeType type)
: base(previousStatement, nextStatement, type)
{
}
}
sealed class DerivedControlFlowGraphBuilder : ControlFlowGraphBuilder
{
protected override ControlFlowNode CreateNode(Statement previousStatement, Statement nextStatement, ControlFlowNodeType type)
{
return new DefiniteAssignmentNode(previousStatement, nextStatement, type);
}
}
readonly DefiniteAssignmentVisitor visitor = new DefiniteAssignmentVisitor();
readonly List<DefiniteAssignmentNode> allNodes = new List<DefiniteAssignmentNode>();
readonly Dictionary<Statement, DefiniteAssignmentNode> beginNodeDict = new Dictionary<Statement, DefiniteAssignmentNode>();
readonly Dictionary<Statement, DefiniteAssignmentNode> endNodeDict = new Dictionary<Statement, DefiniteAssignmentNode>();
readonly Dictionary<Statement, DefiniteAssignmentNode> conditionNodeDict = new Dictionary<Statement, DefiniteAssignmentNode>();
readonly Func<AstNode, CancellationToken, ResolveResult> resolve;
Dictionary<ControlFlowEdge, DefiniteAssignmentStatus> edgeStatus = new Dictionary<ControlFlowEdge, DefiniteAssignmentStatus>();
string variableName;
List<IdentifierExpression> unassignedVariableUses = new List<IdentifierExpression>();
int analyzedRangeStart, analyzedRangeEnd;
CancellationToken analysisCancellationToken;
Queue<DefiniteAssignmentNode> nodesWithModifiedInput = new Queue<DefiniteAssignmentNode>();
public DefiniteAssignmentAnalysis(Statement rootStatement, Func<AstNode, CancellationToken, ResolveResult> resolve, CSharpTypeResolveContext context, CancellationToken cancellationToken)
{
if (rootStatement == null)
throw new ArgumentNullException("rootStatement");
if (resolve == null)
throw new ArgumentNullException("resolve");
this.resolve = resolve;
visitor.analysis = this;
DerivedControlFlowGraphBuilder cfgBuilder = new DerivedControlFlowGraphBuilder();
if (context.Compilation.MainAssembly.UnresolvedAssembly is MinimalCorlib) {
cfgBuilder.EvaluateOnlyPrimitiveConstants = true;
}
allNodes.AddRange(cfgBuilder.BuildControlFlowGraph(rootStatement, resolve, context, cancellationToken).Cast<DefiniteAssignmentNode>());
for (int i = 0; i < allNodes.Count; i++) {
DefiniteAssignmentNode node = allNodes[i];
node.Index = i; // assign numbers to the nodes
if (node.Type == ControlFlowNodeType.StartNode || node.Type == ControlFlowNodeType.BetweenStatements) {
// Anonymous methods have separate control flow graphs, but we also need to analyze those.
// Iterate backwards so that anonymous methods are inserted in the correct order
for (AstNode child = node.NextStatement.LastChild; child != null; child = child.PrevSibling) {
InsertAnonymousMethods(i + 1, child, cfgBuilder, context, cancellationToken);
}
}
// Now register the node in the dictionaries:
if (node.Type == ControlFlowNodeType.StartNode || node.Type == ControlFlowNodeType.BetweenStatements)
beginNodeDict.Add(node.NextStatement, node);
if (node.Type == ControlFlowNodeType.BetweenStatements || node.Type == ControlFlowNodeType.EndNode)
endNodeDict.Add(node.PreviousStatement, node);
if (node.Type == ControlFlowNodeType.LoopCondition)
conditionNodeDict.Add(node.NextStatement, node);
}
// Verify that we created nodes for all statements:
Debug.Assert(!rootStatement.DescendantsAndSelf.OfType<Statement>().Except(allNodes.Select(n => n.NextStatement)).Any());
// Verify that we put all nodes into the dictionaries:
Debug.Assert(rootStatement.DescendantsAndSelf.OfType<Statement>().All(stmt => beginNodeDict.ContainsKey(stmt)));
Debug.Assert(rootStatement.DescendantsAndSelf.OfType<Statement>().All(stmt => endNodeDict.ContainsKey(stmt)));
this.analyzedRangeStart = 0;
this.analyzedRangeEnd = allNodes.Count - 1;
}
void InsertAnonymousMethods(int insertPos, AstNode node, ControlFlowGraphBuilder cfgBuilder, CSharpTypeResolveContext context, CancellationToken cancellationToken)
{
// Ignore any statements, as those have their own ControlFlowNode and get handled separately
if (node is Statement)
return;
AnonymousMethodExpression ame = node as AnonymousMethodExpression;
if (ame != null) {
allNodes.InsertRange(insertPos, cfgBuilder.BuildControlFlowGraph(ame.Body, resolve, context, cancellationToken).Cast<DefiniteAssignmentNode>());
return;
}
LambdaExpression lambda = node as LambdaExpression;
if (lambda != null && lambda.Body is Statement) {
allNodes.InsertRange(insertPos, cfgBuilder.BuildControlFlowGraph((Statement)lambda.Body, resolve, context, cancellationToken).Cast<DefiniteAssignmentNode>());
return;
}
// Descend into child expressions
// Iterate backwards so that anonymous methods are inserted in the correct order
for (AstNode child = node.LastChild; child != null; child = child.PrevSibling) {
InsertAnonymousMethods(insertPos, child, cfgBuilder, context, cancellationToken);
}
}
/// <summary>
/// Gets the unassigned usages of the previously analyzed variable.
/// </summary>
public IList<IdentifierExpression> UnassignedVariableUses {
get {
return unassignedVariableUses.AsReadOnly();
}
}
/// <summary>
/// Sets the range of statements to be analyzed.
/// This method can be used to restrict the analysis to only a part of the method.
/// Only the control flow paths that are fully contained within the selected part will be analyzed.
/// </summary>
/// <remarks>By default, both 'start' and 'end' are inclusive.</remarks>
public void SetAnalyzedRange(Statement start, Statement end, bool startInclusive = true, bool endInclusive = true)
{
var dictForStart = startInclusive ? beginNodeDict : endNodeDict;
var dictForEnd = endInclusive ? endNodeDict : beginNodeDict;
Debug.Assert(dictForStart.ContainsKey(start) && dictForEnd.ContainsKey(end));
int startIndex = dictForStart[start].Index;
int endIndex = dictForEnd[end].Index;
if (startIndex > endIndex)
throw new ArgumentException("The start statement must be lexically preceding the end statement");
this.analyzedRangeStart = startIndex;
this.analyzedRangeEnd = endIndex;
}
public void Analyze(string variable, DefiniteAssignmentStatus initialStatus = DefiniteAssignmentStatus.PotentiallyAssigned, CancellationToken cancellationToken = default(CancellationToken))
{
this.analysisCancellationToken = cancellationToken;
this.variableName = variable;
try {
// Reset the status:
unassignedVariableUses.Clear();
foreach (DefiniteAssignmentNode node in allNodes) {
node.NodeStatus = DefiniteAssignmentStatus.CodeUnreachable;
foreach (ControlFlowEdge edge in node.Outgoing)
edgeStatus[edge] = DefiniteAssignmentStatus.CodeUnreachable;
}
ChangeNodeStatus(allNodes[analyzedRangeStart], initialStatus);
// Iterate as long as the input status of some nodes is changing:
while (nodesWithModifiedInput.Count > 0) {
DefiniteAssignmentNode node = nodesWithModifiedInput.Dequeue();
DefiniteAssignmentStatus inputStatus = DefiniteAssignmentStatus.CodeUnreachable;
foreach (ControlFlowEdge edge in node.Incoming) {
inputStatus = MergeStatus(inputStatus, edgeStatus[edge]);
}
ChangeNodeStatus(node, inputStatus);
}
} finally {
this.analysisCancellationToken = CancellationToken.None;
this.variableName = null;
}
}
public DefiniteAssignmentStatus GetStatusBefore(Statement statement)
{
return beginNodeDict[statement].NodeStatus;
}
public DefiniteAssignmentStatus GetStatusAfter(Statement statement)
{
return endNodeDict[statement].NodeStatus;
}
public DefiniteAssignmentStatus GetStatusBeforeLoopCondition(Statement statement)
{
return conditionNodeDict[statement].NodeStatus;
}
/*/// <summary>
/// Exports the CFG. This method is intended to help debugging issues related to definite assignment.
/// </summary>
public GraphVizGraph ExportGraph()
{
GraphVizGraph g = new GraphVizGraph();
g.Title = "DefiniteAssignment - " + variableName;
for (int i = 0; i < allNodes.Count; i++) {
string name = "#" + i + " = " + allNodes[i].NodeStatus.ToString() + Environment.NewLine;
switch (allNodes[i].Type) {
case ControlFlowNodeType.StartNode:
case ControlFlowNodeType.BetweenStatements:
name += allNodes[i].NextStatement.ToString();
break;
case ControlFlowNodeType.EndNode:
name += "End of " + allNodes[i].PreviousStatement.ToString();
break;
case ControlFlowNodeType.LoopCondition:
name += "Condition in " + allNodes[i].NextStatement.ToString();
break;
default:
name += allNodes[i].Type.ToString();
break;
}
g.AddNode(new GraphVizNode(i) { label = name });
foreach (ControlFlowEdge edge in allNodes[i].Outgoing) {
GraphVizEdge ge = new GraphVizEdge(i, ((DefiniteAssignmentNode)edge.To).Index);
if (edgeStatus.Count > 0)
ge.label = edgeStatus[edge].ToString();
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;
}*/
static DefiniteAssignmentStatus MergeStatus(DefiniteAssignmentStatus a, DefiniteAssignmentStatus b)
{
// The result will be DefinitelyAssigned if at least one incoming edge is DefinitelyAssigned and all others are unreachable.
// The result will be DefinitelyUnassigned if at least one incoming edge is DefinitelyUnassigned and all others are unreachable.
// The result will be Unreachable if all incoming edges are unreachable.
// Otherwise, the result will be PotentiallyAssigned.
if (a == b)
return a;
else if (a == DefiniteAssignmentStatus.CodeUnreachable)
return b;
else if (b == DefiniteAssignmentStatus.CodeUnreachable)
return a;
else
return DefiniteAssignmentStatus.PotentiallyAssigned;
}
void ChangeNodeStatus (DefiniteAssignmentNode node, DefiniteAssignmentStatus inputStatus)
{
if (node.NodeStatus == inputStatus)
return;
node.NodeStatus = inputStatus;
DefiniteAssignmentStatus outputStatus;
switch (node.Type) {
case ControlFlowNodeType.StartNode:
case ControlFlowNodeType.BetweenStatements:
if (node.NextStatement is IfElseStatement) {
// Handle if-else as a condition node
goto case ControlFlowNodeType.LoopCondition;
}
if (inputStatus == DefiniteAssignmentStatus.DefinitelyAssigned) {
// There isn't any way to un-assign variables, so we don't have to check the expression
// if the status already is definitely assigned.
outputStatus = DefiniteAssignmentStatus.DefinitelyAssigned;
} else {
outputStatus = CleanSpecialValues (node.NextStatement.AcceptVisitor (visitor, inputStatus));
}
break;
case ControlFlowNodeType.EndNode:
outputStatus = inputStatus;
if (node.PreviousStatement.Role == TryCatchStatement.FinallyBlockRole
&& (outputStatus == DefiniteAssignmentStatus.DefinitelyAssigned || outputStatus == DefiniteAssignmentStatus.PotentiallyAssigned)) {
TryCatchStatement tryFinally = (TryCatchStatement)node.PreviousStatement.Parent;
// Changing the status on a finally block potentially changes the status of all edges leaving that finally block:
foreach (ControlFlowEdge edge in allNodes.SelectMany(n => n.Outgoing)) {
if (edge.IsLeavingTryFinally && edge.TryFinallyStatements.Contains (tryFinally)) {
DefiniteAssignmentStatus s = edgeStatus [edge];
if (s == DefiniteAssignmentStatus.PotentiallyAssigned) {
ChangeEdgeStatus (edge, outputStatus);
}
}
}
}
break;
case ControlFlowNodeType.LoopCondition:
ForeachStatement foreachStmt = node.NextStatement as ForeachStatement;
if (foreachStmt != null) {
outputStatus = CleanSpecialValues (foreachStmt.InExpression.AcceptVisitor (visitor, inputStatus));
if (foreachStmt.VariableName == this.variableName)
outputStatus = DefiniteAssignmentStatus.DefinitelyAssigned;
break;
} else {
Debug.Assert (node.NextStatement is IfElseStatement || node.NextStatement is WhileStatement || node.NextStatement is ForStatement || node.NextStatement is DoWhileStatement);
Expression condition = node.NextStatement.GetChildByRole (Roles.Condition);
if (condition.IsNull)
outputStatus = inputStatus;
else
outputStatus = condition.AcceptVisitor(visitor, inputStatus);
foreach (ControlFlowEdge edge in node.Outgoing) {
if (edge.Type == ControlFlowEdgeType.ConditionTrue && outputStatus == DefiniteAssignmentStatus.AssignedAfterTrueExpression) {
ChangeEdgeStatus(edge, DefiniteAssignmentStatus.DefinitelyAssigned);
} else if (edge.Type == ControlFlowEdgeType.ConditionFalse && outputStatus == DefiniteAssignmentStatus.AssignedAfterFalseExpression) {
ChangeEdgeStatus(edge, DefiniteAssignmentStatus.DefinitelyAssigned);
} else {
ChangeEdgeStatus(edge, CleanSpecialValues(outputStatus));
}
}
return;
}
default:
throw new InvalidOperationException();
}
foreach (ControlFlowEdge edge in node.Outgoing) {
ChangeEdgeStatus(edge, outputStatus);
}
}
void ChangeEdgeStatus(ControlFlowEdge edge, DefiniteAssignmentStatus newStatus)
{
DefiniteAssignmentStatus oldStatus = edgeStatus[edge];
if (oldStatus == newStatus)
return;
// Ensure that status can cannot change back to CodeUnreachable after it once was reachable.
// Also, don't ever use AssignedAfter... for statements.
if (newStatus == DefiniteAssignmentStatus.CodeUnreachable
|| newStatus == DefiniteAssignmentStatus.AssignedAfterFalseExpression
|| newStatus == DefiniteAssignmentStatus.AssignedAfterTrueExpression)
{
throw new InvalidOperationException();
}
// Note that the status can change from DefinitelyAssigned
// back to PotentiallyAssigned as unreachable input edges are
// discovered to be reachable.
edgeStatus[edge] = newStatus;
DefiniteAssignmentNode targetNode = (DefiniteAssignmentNode)edge.To;
if (analyzedRangeStart <= targetNode.Index && targetNode.Index <= analyzedRangeEnd) {
// TODO: potential optimization: visit previously unreachable nodes with higher priority
// (e.g. use Deque and enqueue previously unreachable nodes at the front, but
// other nodes at the end)
nodesWithModifiedInput.Enqueue(targetNode);
}
}
/// <summary>
/// Evaluates an expression.
/// </summary>
/// <returns>The constant value of the expression; or null if the expression is not a constant.</returns>
ResolveResult EvaluateConstant(Expression expr)
{
return resolve(expr, analysisCancellationToken);
}
/// <summary>
/// Evaluates an expression.
/// </summary>
/// <returns>The value of the constant boolean expression; or null if the value is not a constant boolean expression.</returns>
bool? EvaluateCondition(Expression expr)
{
ResolveResult rr = EvaluateConstant(expr);
if (rr != null && rr.IsCompileTimeConstant)
return rr.ConstantValue as bool?;
else
return null;
}
static DefiniteAssignmentStatus CleanSpecialValues(DefiniteAssignmentStatus status)
{
if (status == DefiniteAssignmentStatus.AssignedAfterTrueExpression)
return DefiniteAssignmentStatus.PotentiallyAssigned;
else if (status == DefiniteAssignmentStatus.AssignedAfterFalseExpression)
return DefiniteAssignmentStatus.PotentiallyAssigned;
else
return status;
}
sealed class DefiniteAssignmentVisitor : DepthFirstAstVisitor<DefiniteAssignmentStatus, DefiniteAssignmentStatus>
{
internal DefiniteAssignmentAnalysis analysis;
// The general approach for unknown nodes is to pass the status through all child nodes in order
protected override DefiniteAssignmentStatus VisitChildren(AstNode node, DefiniteAssignmentStatus data)
{
// the special values are valid as output only, not as input
Debug.Assert(data == CleanSpecialValues(data));
DefiniteAssignmentStatus status = data;
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
analysis.analysisCancellationToken.ThrowIfCancellationRequested();
Debug.Assert(!(child is Statement)); // statements are visited with the CFG, not with the visitor pattern
status = child.AcceptVisitor(this, status);
status = CleanSpecialValues(status);
}
return status;
}
#region Statements
// For statements, the visitor only describes the effect of the statement itself;
// we do not consider the effect of any nested statements.
// This is done because the nested statements will be reached using the control flow graph.
// In fact, these methods are present so that the default logic in VisitChildren does not try to visit the nested statements.
public override DefiniteAssignmentStatus VisitBlockStatement(BlockStatement blockStatement, DefiniteAssignmentStatus data)
{
return data;
}
public override DefiniteAssignmentStatus VisitCheckedStatement(CheckedStatement checkedStatement, DefiniteAssignmentStatus data)
{
return data;
}
public override DefiniteAssignmentStatus VisitUncheckedStatement(UncheckedStatement uncheckedStatement, DefiniteAssignmentStatus data)
{
return data;
}
// ExpressionStatement handled by default logic
// VariableDeclarationStatement handled by default logic
public override DefiniteAssignmentStatus VisitVariableInitializer(VariableInitializer variableInitializer, DefiniteAssignmentStatus data)
{
if (variableInitializer.Initializer.IsNull) {
return data;
} else {
DefiniteAssignmentStatus status = variableInitializer.Initializer.AcceptVisitor(this, data);
if (variableInitializer.Name == analysis.variableName)
return DefiniteAssignmentStatus.DefinitelyAssigned;
else
return status;
}
}
// IfStatement not handled by visitor, but special-cased in the code consuming the control flow graph
public override DefiniteAssignmentStatus VisitSwitchStatement(SwitchStatement switchStatement, DefiniteAssignmentStatus data)
{
return switchStatement.Expression.AcceptVisitor(this, data);
}
public override DefiniteAssignmentStatus VisitWhileStatement(WhileStatement whileStatement, DefiniteAssignmentStatus data)
{
return data; // condition is handled by special condition CFG node
}
public override DefiniteAssignmentStatus VisitDoWhileStatement(DoWhileStatement doWhileStatement, DefiniteAssignmentStatus data)
{
return data; // condition is handled by special condition CFG node
}
public override DefiniteAssignmentStatus VisitForStatement(ForStatement forStatement, DefiniteAssignmentStatus data)
{
return data; // condition is handled by special condition CFG node; initializer and iterator statements are handled by CFG
}
// Break/Continue/Goto: handled by default logic
// ThrowStatement: handled by default logic (just visit the expression)
// ReturnStatement: handled by default logic (just visit the expression)
public override DefiniteAssignmentStatus VisitTryCatchStatement(TryCatchStatement tryCatchStatement, DefiniteAssignmentStatus data)
{
return data; // no special logic when entering the try-catch-finally statement
// TODO: where to put the special logic when exiting the try-finally statement?
}
public override DefiniteAssignmentStatus VisitForeachStatement(ForeachStatement foreachStatement, DefiniteAssignmentStatus data)
{
return data; // assignment of the foreach loop variable is done when handling the condition node
}
public override DefiniteAssignmentStatus VisitUsingStatement(UsingStatement usingStatement, DefiniteAssignmentStatus data)
{
if (usingStatement.ResourceAcquisition is Expression)
return usingStatement.ResourceAcquisition.AcceptVisitor(this, data);
else
return data; // don't handle resource acquisition statements, as those are connected in the control flow graph
}
public override DefiniteAssignmentStatus VisitLockStatement(LockStatement lockStatement, DefiniteAssignmentStatus data)
{
return lockStatement.Expression.AcceptVisitor(this, data);
}
// Yield statements use the default logic
public override DefiniteAssignmentStatus VisitUnsafeStatement(UnsafeStatement unsafeStatement, DefiniteAssignmentStatus data)
{
return data;
}
public override DefiniteAssignmentStatus VisitFixedStatement(FixedStatement fixedStatement, DefiniteAssignmentStatus data)
{
DefiniteAssignmentStatus status = data;
foreach (var variable in fixedStatement.Variables)
status = variable.AcceptVisitor(this, status);
return status;
}
#endregion
#region Expressions
public override DefiniteAssignmentStatus VisitDirectionExpression(DirectionExpression directionExpression, DefiniteAssignmentStatus data)
{
if (directionExpression.FieldDirection == FieldDirection.Out) {
return HandleAssignment(directionExpression.Expression, null, data);
} else {
// use default logic for 'ref'
return VisitChildren(directionExpression, data);
}
}
public override DefiniteAssignmentStatus VisitAssignmentExpression(AssignmentExpression assignmentExpression, DefiniteAssignmentStatus data)
{
if (assignmentExpression.Operator == AssignmentOperatorType.Assign) {
return HandleAssignment(assignmentExpression.Left, assignmentExpression.Right, data);
} else {
// use default logic for compound assignment operators
return VisitChildren(assignmentExpression, data);
}
}
DefiniteAssignmentStatus HandleAssignment(Expression left, Expression right, DefiniteAssignmentStatus initialStatus)
{
IdentifierExpression ident = left as IdentifierExpression;
if (ident != null && ident.Identifier == analysis.variableName) {
// right==null is special case when handling 'out' expressions
if (right != null)
right.AcceptVisitor(this, initialStatus);
return DefiniteAssignmentStatus.DefinitelyAssigned;
} else {
DefiniteAssignmentStatus status = left.AcceptVisitor(this, initialStatus);
if (right != null)
status = right.AcceptVisitor(this, CleanSpecialValues(status));
return CleanSpecialValues(status);
}
}
public override DefiniteAssignmentStatus VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, DefiniteAssignmentStatus data)
{
// Don't use the default logic here because we don't want to clean up the special values.
return parenthesizedExpression.Expression.AcceptVisitor(this, data);
}
public override DefiniteAssignmentStatus VisitCheckedExpression(CheckedExpression checkedExpression, DefiniteAssignmentStatus data)
{
return checkedExpression.Expression.AcceptVisitor(this, data);
}
public override DefiniteAssignmentStatus VisitUncheckedExpression(UncheckedExpression uncheckedExpression, DefiniteAssignmentStatus data)
{
return uncheckedExpression.Expression.AcceptVisitor(this, data);
}
public override DefiniteAssignmentStatus VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, DefiniteAssignmentStatus data)
{
if (binaryOperatorExpression.Operator == BinaryOperatorType.ConditionalAnd) {
// Handle constant left side of && expressions (not in the C# spec, but done by the MS compiler)
bool? cond = analysis.EvaluateCondition(binaryOperatorExpression.Left);
if (cond == true)
return binaryOperatorExpression.Right.AcceptVisitor(this, data); // right operand gets evaluated unconditionally
else if (cond == false)
return data; // right operand never gets evaluated
// C# 4.0 spec: §5.3.3.24 Definite Assignment for && expressions
DefiniteAssignmentStatus afterLeft = binaryOperatorExpression.Left.AcceptVisitor(this, data);
DefiniteAssignmentStatus beforeRight;
if (afterLeft == DefiniteAssignmentStatus.AssignedAfterTrueExpression)
beforeRight = DefiniteAssignmentStatus.DefinitelyAssigned;
else if (afterLeft == DefiniteAssignmentStatus.AssignedAfterFalseExpression)
beforeRight = DefiniteAssignmentStatus.PotentiallyAssigned;
else
beforeRight = afterLeft;
DefiniteAssignmentStatus afterRight = binaryOperatorExpression.Right.AcceptVisitor(this, beforeRight);
if (afterLeft == DefiniteAssignmentStatus.DefinitelyAssigned)
return DefiniteAssignmentStatus.DefinitelyAssigned;
else if (afterRight == DefiniteAssignmentStatus.DefinitelyAssigned && afterLeft == DefiniteAssignmentStatus.AssignedAfterFalseExpression)
return DefiniteAssignmentStatus.DefinitelyAssigned;
else if (afterRight == DefiniteAssignmentStatus.DefinitelyAssigned || afterRight == DefiniteAssignmentStatus.AssignedAfterTrueExpression)
return DefiniteAssignmentStatus.AssignedAfterTrueExpression;
else if (afterLeft == DefiniteAssignmentStatus.AssignedAfterFalseExpression && afterRight == DefiniteAssignmentStatus.AssignedAfterFalseExpression)
return DefiniteAssignmentStatus.AssignedAfterFalseExpression;
else
return DefiniteAssignmentStatus.PotentiallyAssigned;
} else if (binaryOperatorExpression.Operator == BinaryOperatorType.ConditionalOr) {
// C# 4.0 spec: §5.3.3.25 Definite Assignment for || expressions
bool? cond = analysis.EvaluateCondition(binaryOperatorExpression.Left);
if (cond == false)
return binaryOperatorExpression.Right.AcceptVisitor(this, data); // right operand gets evaluated unconditionally
else if (cond == true)
return data; // right operand never gets evaluated
DefiniteAssignmentStatus afterLeft = binaryOperatorExpression.Left.AcceptVisitor(this, data);
DefiniteAssignmentStatus beforeRight;
if (afterLeft == DefiniteAssignmentStatus.AssignedAfterTrueExpression)
beforeRight = DefiniteAssignmentStatus.PotentiallyAssigned;
else if (afterLeft == DefiniteAssignmentStatus.AssignedAfterFalseExpression)
beforeRight = DefiniteAssignmentStatus.DefinitelyAssigned;
else
beforeRight = afterLeft;
DefiniteAssignmentStatus afterRight = binaryOperatorExpression.Right.AcceptVisitor(this, beforeRight);
if (afterLeft == DefiniteAssignmentStatus.DefinitelyAssigned)
return DefiniteAssignmentStatus.DefinitelyAssigned;
else if (afterRight == DefiniteAssignmentStatus.DefinitelyAssigned && afterLeft == DefiniteAssignmentStatus.AssignedAfterTrueExpression)
return DefiniteAssignmentStatus.DefinitelyAssigned;
else if (afterRight == DefiniteAssignmentStatus.DefinitelyAssigned || afterRight == DefiniteAssignmentStatus.AssignedAfterFalseExpression)
return DefiniteAssignmentStatus.AssignedAfterFalseExpression;
else if (afterLeft == DefiniteAssignmentStatus.AssignedAfterTrueExpression && afterRight == DefiniteAssignmentStatus.AssignedAfterTrueExpression)
return DefiniteAssignmentStatus.AssignedAfterTrueExpression;
else
return DefiniteAssignmentStatus.PotentiallyAssigned;
} else if (binaryOperatorExpression.Operator == BinaryOperatorType.NullCoalescing) {
// C# 4.0 spec: §5.3.3.27 Definite assignment for ?? expressions
ResolveResult crr = analysis.EvaluateConstant(binaryOperatorExpression.Left);
if (crr != null && crr.IsCompileTimeConstant && crr.ConstantValue == null)
return binaryOperatorExpression.Right.AcceptVisitor(this, data);
DefiniteAssignmentStatus status = CleanSpecialValues(binaryOperatorExpression.Left.AcceptVisitor(this, data));
binaryOperatorExpression.Right.AcceptVisitor(this, status);
return status;
} else {
// use default logic for other operators
return VisitChildren(binaryOperatorExpression, data);
}
}
public override DefiniteAssignmentStatus VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, DefiniteAssignmentStatus data)
{
if (unaryOperatorExpression.Operator == UnaryOperatorType.Not) {
// C# 4.0 spec: §5.3.3.26 Definite assignment for ! expressions
DefiniteAssignmentStatus status = unaryOperatorExpression.Expression.AcceptVisitor(this, data);
if (status == DefiniteAssignmentStatus.AssignedAfterFalseExpression)
return DefiniteAssignmentStatus.AssignedAfterTrueExpression;
else if (status == DefiniteAssignmentStatus.AssignedAfterTrueExpression)
return DefiniteAssignmentStatus.AssignedAfterFalseExpression;
else
return status;
} else {
// use default logic for other operators
return VisitChildren(unaryOperatorExpression, data);
}
}
public override DefiniteAssignmentStatus VisitConditionalExpression(ConditionalExpression conditionalExpression, DefiniteAssignmentStatus data)
{
// C# 4.0 spec: §5.3.3.28 Definite assignment for ?: expressions
bool? cond = analysis.EvaluateCondition(conditionalExpression.Condition);
if (cond == true) {
return conditionalExpression.TrueExpression.AcceptVisitor(this, data);
} else if (cond == false) {
return conditionalExpression.FalseExpression.AcceptVisitor(this, data);
} else {
DefiniteAssignmentStatus afterCondition = conditionalExpression.Condition.AcceptVisitor(this, data);
DefiniteAssignmentStatus beforeTrue, beforeFalse;
if (afterCondition == DefiniteAssignmentStatus.AssignedAfterTrueExpression) {
beforeTrue = DefiniteAssignmentStatus.DefinitelyAssigned;
beforeFalse = DefiniteAssignmentStatus.PotentiallyAssigned;
} else if (afterCondition == DefiniteAssignmentStatus.AssignedAfterFalseExpression) {
beforeTrue = DefiniteAssignmentStatus.PotentiallyAssigned;
beforeFalse = DefiniteAssignmentStatus.DefinitelyAssigned;
} else {
beforeTrue = afterCondition;
beforeFalse = afterCondition;
}
DefiniteAssignmentStatus afterTrue = conditionalExpression.TrueExpression.AcceptVisitor(this, beforeTrue);
DefiniteAssignmentStatus afterFalse = conditionalExpression.FalseExpression.AcceptVisitor(this, beforeFalse);
return MergeStatus(CleanSpecialValues(afterTrue), CleanSpecialValues(afterFalse));
}
}
public override DefiniteAssignmentStatus VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression, DefiniteAssignmentStatus data)
{
BlockStatement body = anonymousMethodExpression.Body;
analysis.ChangeNodeStatus(analysis.beginNodeDict[body], data);
return data;
}
public override DefiniteAssignmentStatus VisitLambdaExpression(LambdaExpression lambdaExpression, DefiniteAssignmentStatus data)
{
Statement body = lambdaExpression.Body as Statement;
if (body != null) {
analysis.ChangeNodeStatus(analysis.beginNodeDict[body], data);
} else {
lambdaExpression.Body.AcceptVisitor(this, data);
}
return data;
}
public override DefiniteAssignmentStatus VisitIdentifierExpression(IdentifierExpression identifierExpression, DefiniteAssignmentStatus data)
{
if (data != DefiniteAssignmentStatus.DefinitelyAssigned
&& identifierExpression.Identifier == analysis.variableName && identifierExpression.TypeArguments.Count == 0)
{
analysis.unassignedVariableUses.Add(identifierExpression);
}
return data;
}
#endregion
}
}
}

68
ICSharpCode.Decompiler/CSharp/Resolver/CompositeResolveVisitorNavigator.cs

@ -1,68 +0,0 @@ @@ -1,68 +0,0 @@
// 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 ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Resolver
{
public sealed class CompositeResolveVisitorNavigator : IResolveVisitorNavigator
{
IResolveVisitorNavigator[] navigators;
public CompositeResolveVisitorNavigator(params IResolveVisitorNavigator[] navigators)
{
if (navigators == null)
throw new ArgumentNullException("navigators");
this.navigators = navigators;
foreach (var n in navigators) {
if (n == null)
throw new ArgumentException("Array must not contain nulls.");
}
}
public ResolveVisitorNavigationMode Scan(AstNode node)
{
bool needsScan = false;
foreach (var navigator in navigators) {
ResolveVisitorNavigationMode mode = navigator.Scan(node);
if (mode == ResolveVisitorNavigationMode.Resolve)
return mode; // resolve has highest priority
else if (mode == ResolveVisitorNavigationMode.Scan)
needsScan = true;
}
return needsScan ? ResolveVisitorNavigationMode.Scan : ResolveVisitorNavigationMode.Skip;
}
public void Resolved(AstNode node, ResolveResult result)
{
foreach (var navigator in navigators) {
navigator.Resolved(node, result);
}
}
public void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{
foreach (var navigator in navigators) {
navigator.ProcessConversion(expression, result, conversion, targetType);
}
}
}
}

88
ICSharpCode.Decompiler/CSharp/Resolver/DetectSkippableNodesNavigator.cs

@ -1,88 +0,0 @@ @@ -1,88 +0,0 @@
// 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.Collections.Generic;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Resolver
{
/// <summary>
/// When an <see cref="IResolveVisitorNavigator"/> is searching for specific nodes
/// (e.g. all IdentifierExpressions), it has to scan the whole syntax tree for those nodes.
/// However, scanning in the ResolveVisitor is expensive (e.g. any lambda that is scanned must be resolved),
/// so it makes sense to detect when a whole subtree is scan-only, and skip that tree instead.
///
/// The DetectSkippableNodesNavigator performs this job by running the input IResolveVisitorNavigator
/// over the whole AST, and detecting subtrees that are scan-only, and replaces them with Skip.
/// </summary>
public sealed class DetectSkippableNodesNavigator : IResolveVisitorNavigator
{
readonly Dictionary<AstNode, ResolveVisitorNavigationMode> dict = new Dictionary<AstNode, ResolveVisitorNavigationMode>();
IResolveVisitorNavigator navigator;
public DetectSkippableNodesNavigator(IResolveVisitorNavigator navigator, AstNode root)
{
this.navigator = navigator;
Init(root);
}
bool Init(AstNode node)
{
var mode = navigator.Scan(node);
if (mode == ResolveVisitorNavigationMode.Skip)
return false;
bool needsResolve = (mode != ResolveVisitorNavigationMode.Scan);
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
needsResolve |= Init(child);
}
if (needsResolve) {
// If this node or any child node needs resolving, store the mode in the dictionary.
dict.Add(node, mode);
}
return needsResolve;
}
/// <inheritdoc/>
public ResolveVisitorNavigationMode Scan(AstNode node)
{
ResolveVisitorNavigationMode mode;
if (dict.TryGetValue(node, out mode)) {
return mode;
} else {
return ResolveVisitorNavigationMode.Skip;
}
}
/// <inheritdoc/>
public void Resolved(AstNode node, ResolveResult result)
{
navigator.Resolved(node, result);
}
/// <inheritdoc/>
public void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{
navigator.ProcessConversion(expression, result, conversion, targetType);
}
}
}

101
ICSharpCode.Decompiler/CSharp/Resolver/FindReferencedEntities.cs

@ -1,101 +0,0 @@ @@ -1,101 +0,0 @@
// 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 ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Resolver
{
/// <summary>
/// Find all entities that are referenced in the scanned AST.
/// </summary>
public sealed class FindReferencedEntities : IResolveVisitorNavigator
{
readonly Action<AstNode, IMember> memberReferenceFound;
readonly Action<AstNode, IType> typeReferenceFound;
/// <summary>
/// Creates a new FindReferencedEntities instance that
/// looks for entity definitions.
/// The visitor will report type definitions and member definitions (not specialized members).
/// </summary>
public FindReferencedEntities(Action<AstNode, IEntity> referenceFound)
{
if (referenceFound == null)
throw new ArgumentNullException("referenceFound");
this.memberReferenceFound = (node, member) => referenceFound(node, member.MemberDefinition);
this.typeReferenceFound = (node, type) => {
var def = type.GetDefinition();
if (def != null)
referenceFound(node, def);
};
}
/// <summary>
/// Creates a new FindReferencedEntities instance that
/// looks for types and members.
/// The visitor will report parameterized types and potentially specialized members.
/// </summary>
public FindReferencedEntities(Action<AstNode, IType> typeReferenceFound, Action<AstNode, IMember> memberReferenceFound)
{
if (typeReferenceFound == null)
throw new ArgumentNullException("typeReferenceFound");
if (memberReferenceFound == null)
throw new ArgumentNullException("memberReferenceFound");
this.typeReferenceFound = typeReferenceFound;
this.memberReferenceFound = memberReferenceFound;
}
public ResolveVisitorNavigationMode Scan(AstNode node)
{
return ResolveVisitorNavigationMode.Resolve;
}
public void Resolved(AstNode node, ResolveResult result)
{
if (ParenthesizedExpression.ActsAsParenthesizedExpression(node))
return;
MemberResolveResult mrr = result as MemberResolveResult;
if (mrr != null) {
memberReferenceFound(node, mrr.Member);
}
TypeResolveResult trr = result as TypeResolveResult;
if (trr != null) {
typeReferenceFound(node, trr.Type);
}
ForEachResolveResult ferr = result as ForEachResolveResult;
if (ferr != null) {
Resolved(node, ferr.GetEnumeratorCall);
if (ferr.CurrentProperty != null)
memberReferenceFound(node, ferr.CurrentProperty);
if (ferr.MoveNextMethod != null)
memberReferenceFound(node, ferr.MoveNextMethod);
}
}
public void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{
if (conversion.IsUserDefined || conversion.IsMethodGroupConversion) {
memberReferenceFound(expression, conversion.Method);
}
}
}
}

103
ICSharpCode.Decompiler/CSharp/Resolver/IResolveVisitorNavigator.cs

@ -1,103 +0,0 @@ @@ -1,103 +0,0 @@
// 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 ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Resolver
{
/// <summary>
/// Allows controlling which nodes are resolved by the resolve visitor.
/// </summary>
/// <seealso cref="ResolveVisitor"/>
public interface IResolveVisitorNavigator
{
/// <summary>
/// Asks the navigator whether to scan, skip, or resolve a node.
/// </summary>
ResolveVisitorNavigationMode Scan(AstNode node);
/// <summary>
/// Notifies the navigator that a node was resolved.
/// </summary>
/// <param name="node">The node that was resolved</param>
/// <param name="result">Resolve result</param>
void Resolved(AstNode node, ResolveResult result);
/// <summary>
/// Notifies the navigator that an implicit conversion was applied.
/// </summary>
/// <param name="expression">The expression that was resolved.</param>
/// <param name="result">The resolve result of the expression.</param>
/// <param name="conversion">The conversion applied to the expressed.</param>
/// <param name="targetType">The target type of the conversion.</param>
void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType);
}
/// <summary>
/// Represents the operation mode of the resolve visitor.
/// </summary>
/// <seealso cref="ResolveVisitor"/>
public enum ResolveVisitorNavigationMode
{
/// <summary>
/// Scan into the children of the current node, without resolving the current node.
/// </summary>
Scan,
/// <summary>
/// Skip the current node - do not scan into it; do not resolve it.
/// </summary>
Skip,
/// <summary>
/// Resolve the current node.
/// Subnodes which are not required for resolving the current node
/// will ask the navigator again whether they should be resolved.
/// </summary>
Resolve
}
sealed class ConstantModeResolveVisitorNavigator : IResolveVisitorNavigator
{
readonly ResolveVisitorNavigationMode mode;
readonly IResolveVisitorNavigator targetForResolveCalls;
public ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode mode, IResolveVisitorNavigator targetForResolveCalls)
{
this.mode = mode;
this.targetForResolveCalls = targetForResolveCalls;
}
ResolveVisitorNavigationMode IResolveVisitorNavigator.Scan(AstNode node)
{
return mode;
}
void IResolveVisitorNavigator.Resolved(AstNode node, ResolveResult result)
{
if (targetForResolveCalls != null)
targetForResolveCalls.Resolved(node, result);
}
void IResolveVisitorNavigator.ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{
if (targetForResolveCalls != null)
targetForResolveCalls.ProcessConversion(expression, result, conversion, targetType);
}
}
}

77
ICSharpCode.Decompiler/CSharp/Resolver/NodeListResolveVisitorNavigator.cs

@ -1,77 +0,0 @@ @@ -1,77 +0,0 @@
// 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 ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Resolver
{
/// <summary>
/// <see cref="IResolveVisitorNavigator"/> implementation that resolves a list of nodes.
/// We will skip all nodes which are not the target nodes or ancestors of the target nodes.
/// </summary>
public class NodeListResolveVisitorNavigator : IResolveVisitorNavigator
{
readonly Dictionary<AstNode, ResolveVisitorNavigationMode> dict = new Dictionary<AstNode, ResolveVisitorNavigationMode>();
/// <summary>
/// Creates a new NodeListResolveVisitorNavigator that resolves the specified nodes.
/// </summary>
public NodeListResolveVisitorNavigator(params AstNode[] nodes)
: this((IEnumerable<AstNode>)nodes)
{
}
/// <summary>
/// Creates a new NodeListResolveVisitorNavigator that resolves the specified nodes.
/// </summary>
public NodeListResolveVisitorNavigator(IEnumerable<AstNode> nodes, bool scanOnly = false)
{
if (nodes == null)
throw new ArgumentNullException("nodes");
foreach (var node in nodes) {
dict[node] = scanOnly ? ResolveVisitorNavigationMode.Scan : ResolveVisitorNavigationMode.Resolve;
for (var ancestor = node.Parent; ancestor != null && !dict.ContainsKey(ancestor); ancestor = ancestor.Parent) {
dict.Add(ancestor, ResolveVisitorNavigationMode.Scan);
}
}
}
/// <inheritdoc/>
public virtual ResolveVisitorNavigationMode Scan(AstNode node)
{
ResolveVisitorNavigationMode mode;
if (dict.TryGetValue(node, out mode)) {
return mode;
} else {
return ResolveVisitorNavigationMode.Skip;
}
}
public virtual void Resolved(AstNode node, ResolveResult result)
{
}
public virtual void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{
}
}
}

864
ICSharpCode.Decompiler/CSharp/Syntax/ObservableAstVisitor.cs

@ -1,864 +0,0 @@ @@ -1,864 +0,0 @@
//
// ObservableAstVisitor.cs
//
// Author:
// Mike Krüger <mkrueger@novell.com>
//
// 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.Decompiler.CSharp.Syntax
{
public class ObservableAstVisitor : IAstVisitor
{
void Visit<T>(Action<T> enter, Action<T> leave, T node) where T : AstNode
{
if (enter != null)
enter(node);
AstNode next;
for (var child = node.FirstChild; child != null; child = next) {
// Store next to allow the loop to continue
// if the visitor removes/replaces children.
next = child.NextSibling;
child.AcceptVisitor (this);
}
if (leave != null)
leave(node);
}
void IAstVisitor.VisitNullNode(AstNode nullNode)
{
}
void IAstVisitor.VisitErrorNode(AstNode nullNode)
{
}
public event Action<SyntaxTree> EnterSyntaxTree, LeaveSyntaxTree;
void IAstVisitor.VisitSyntaxTree(SyntaxTree unit)
{
Visit(EnterSyntaxTree, LeaveSyntaxTree, unit);
}
public event Action<Comment> EnterComment, LeaveComment;
void IAstVisitor.VisitComment(Comment comment)
{
Visit(EnterComment, LeaveComment, comment);
}
public event Action<NewLineNode> EnterNewLine, LeaveNewLine;
void IAstVisitor.VisitNewLine(NewLineNode newLineNode)
{
Visit(EnterNewLine, LeaveNewLine, newLineNode);
}
public event Action<WhitespaceNode> EnterWhitespace, LeaveWhitespace;
void IAstVisitor.VisitWhitespace(WhitespaceNode whitespace)
{
Visit(EnterWhitespace, LeaveWhitespace, whitespace);
}
public event Action<TextNode> EnterText, LeaveText;
void IAstVisitor.VisitText(TextNode textNode)
{
Visit(EnterText, LeaveText, textNode);
}
public event Action<PreProcessorDirective> EnterPreProcessorDirective, LeavePreProcessorDirective;
void IAstVisitor.VisitPreProcessorDirective(PreProcessorDirective preProcessorDirective)
{
Visit(EnterPreProcessorDirective, LeavePreProcessorDirective, preProcessorDirective);
}
public event Action<DocumentationReference> EnterDocumentationReference, LeaveDocumentationReference;
void IAstVisitor.VisitDocumentationReference(DocumentationReference documentationReference)
{
Visit(EnterDocumentationReference, LeaveDocumentationReference, documentationReference);
}
public event Action<Identifier> EnterIdentifier, LeaveIdentifier;
void IAstVisitor.VisitIdentifier(Identifier identifier)
{
Visit(EnterIdentifier, LeaveIdentifier, identifier);
}
public event Action<CSharpTokenNode> EnterCSharpTokenNode, LeaveCSharpTokenNode;
void IAstVisitor.VisitCSharpTokenNode(CSharpTokenNode token)
{
Visit(EnterCSharpTokenNode, LeaveCSharpTokenNode, token);
}
public event Action<PrimitiveType> EnterPrimitiveType, LeavePrimitiveType;
void IAstVisitor.VisitPrimitiveType(PrimitiveType primitiveType)
{
Visit(EnterPrimitiveType, LeavePrimitiveType, primitiveType);
}
public event Action<ComposedType> EnterComposedType, LeaveComposedType;
void IAstVisitor.VisitComposedType(ComposedType composedType)
{
Visit(EnterComposedType, LeaveComposedType, composedType);
}
public event Action<SimpleType> EnterSimpleType, LeaveSimpleType;
void IAstVisitor.VisitSimpleType(SimpleType simpleType)
{
Visit(EnterSimpleType, LeaveSimpleType, simpleType);
}
public event Action<MemberType> EnterMemberType, LeaveMemberType;
void IAstVisitor.VisitMemberType(MemberType memberType)
{
Visit(EnterMemberType, LeaveMemberType, memberType);
}
public event Action<Attribute> EnterAttribute, LeaveAttribute;
void IAstVisitor.VisitAttribute(Attribute attribute)
{
Visit(EnterAttribute, LeaveAttribute, attribute);
}
public event Action<AttributeSection> EnterAttributeSection, LeaveAttributeSection;
void IAstVisitor.VisitAttributeSection(AttributeSection attributeSection)
{
Visit(EnterAttributeSection, LeaveAttributeSection, attributeSection);
}
public event Action<DelegateDeclaration> EnterDelegateDeclaration, LeaveDelegateDeclaration;
void IAstVisitor.VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration)
{
Visit(EnterDelegateDeclaration, LeaveDelegateDeclaration, delegateDeclaration);
}
public event Action<NamespaceDeclaration> EnterNamespaceDeclaration, LeaveNamespaceDeclaration;
void IAstVisitor.VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration)
{
Visit(EnterNamespaceDeclaration, LeaveNamespaceDeclaration, namespaceDeclaration);
}
public event Action<TypeDeclaration> EnterTypeDeclaration, LeaveTypeDeclaration;
void IAstVisitor.VisitTypeDeclaration(TypeDeclaration typeDeclaration)
{
Visit(EnterTypeDeclaration, LeaveTypeDeclaration, typeDeclaration);
}
public event Action<TypeParameterDeclaration> EnterTypeParameterDeclaration, LeaveTypeParameterDeclaration;
void IAstVisitor.VisitTypeParameterDeclaration(TypeParameterDeclaration typeParameterDeclaration)
{
Visit(EnterTypeParameterDeclaration, LeaveTypeParameterDeclaration, typeParameterDeclaration);
}
public event Action<EnumMemberDeclaration> EnterEnumMemberDeclaration, LeaveEnumMemberDeclaration;
void IAstVisitor.VisitEnumMemberDeclaration(EnumMemberDeclaration enumMemberDeclaration)
{
Visit(EnterEnumMemberDeclaration, LeaveEnumMemberDeclaration, enumMemberDeclaration);
}
public event Action<UsingDeclaration> EnterUsingDeclaration, LeaveUsingDeclaration;
void IAstVisitor.VisitUsingDeclaration(UsingDeclaration usingDeclaration)
{
Visit(EnterUsingDeclaration, LeaveUsingDeclaration, usingDeclaration);
}
public event Action<UsingAliasDeclaration> EnterUsingAliasDeclaration, LeaveUsingAliasDeclaration;
void IAstVisitor.VisitUsingAliasDeclaration(UsingAliasDeclaration usingDeclaration)
{
Visit(EnterUsingAliasDeclaration, LeaveUsingAliasDeclaration, usingDeclaration);
}
public event Action<ExternAliasDeclaration> EnterExternAliasDeclaration, LeaveExternAliasDeclaration;
void IAstVisitor.VisitExternAliasDeclaration(ExternAliasDeclaration externAliasDeclaration)
{
Visit(EnterExternAliasDeclaration, LeaveExternAliasDeclaration, externAliasDeclaration);
}
public event Action<ConstructorDeclaration> EnterConstructorDeclaration, LeaveConstructorDeclaration;
void IAstVisitor.VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration)
{
Visit(EnterConstructorDeclaration, LeaveConstructorDeclaration, constructorDeclaration);
}
public event Action<ConstructorInitializer> EnterConstructorInitializer, LeaveConstructorInitializer;
void IAstVisitor.VisitConstructorInitializer(ConstructorInitializer constructorInitializer)
{
Visit(EnterConstructorInitializer, LeaveConstructorInitializer, constructorInitializer);
}
public event Action<DestructorDeclaration> EnterDestructorDeclaration, LeaveDestructorDeclaration;
void IAstVisitor.VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration)
{
Visit(EnterDestructorDeclaration, LeaveDestructorDeclaration, destructorDeclaration);
}
public event Action<EventDeclaration> EnterEventDeclaration, LeaveEventDeclaration;
void IAstVisitor.VisitEventDeclaration(EventDeclaration eventDeclaration)
{
Visit(EnterEventDeclaration, LeaveEventDeclaration, eventDeclaration);
}
public event Action<CustomEventDeclaration> EnterCustomEventDeclaration, LeaveCustomEventDeclaration;
void IAstVisitor.VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration)
{
Visit(EnterCustomEventDeclaration, LeaveCustomEventDeclaration, eventDeclaration);
}
public event Action<FieldDeclaration> EnterFieldDeclaration, LeaveFieldDeclaration;
void IAstVisitor.VisitFieldDeclaration(FieldDeclaration fieldDeclaration)
{
Visit(EnterFieldDeclaration, LeaveFieldDeclaration, fieldDeclaration);
}
public event Action<FixedFieldDeclaration> EnterFixedFieldDeclaration, LeaveFixedFieldDeclaration;
void IAstVisitor.VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration)
{
Visit(EnterFixedFieldDeclaration, LeaveFixedFieldDeclaration, fixedFieldDeclaration);
}
public event Action<FixedVariableInitializer> EnterFixedVariableInitializer, LeaveFixedVariableInitializer;
void IAstVisitor.VisitFixedVariableInitializer(FixedVariableInitializer fixedVariableInitializer)
{
Visit(EnterFixedVariableInitializer, LeaveFixedVariableInitializer, fixedVariableInitializer);
}
public event Action<IndexerDeclaration> EnterIndexerDeclaration, LeaveIndexerDeclaration;
void IAstVisitor.VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration)
{
Visit(EnterIndexerDeclaration, LeaveIndexerDeclaration, indexerDeclaration);
}
public event Action<MethodDeclaration> EnterMethodDeclaration, LeaveMethodDeclaration;
void IAstVisitor.VisitMethodDeclaration(MethodDeclaration methodDeclaration)
{
Visit(EnterMethodDeclaration, LeaveMethodDeclaration, methodDeclaration);
}
public event Action<OperatorDeclaration> EnterOperatorDeclaration, LeaveOperatorDeclaration;
void IAstVisitor.VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration)
{
Visit(EnterOperatorDeclaration, LeaveOperatorDeclaration, operatorDeclaration);
}
public event Action<PropertyDeclaration> EnterPropertyDeclaration, LeavePropertyDeclaration;
void IAstVisitor.VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration)
{
Visit(EnterPropertyDeclaration, LeavePropertyDeclaration, propertyDeclaration);
}
public event Action<Accessor> EnterAccessor, LeaveAccessor;
void IAstVisitor.VisitAccessor(Accessor accessor)
{
Visit(EnterAccessor, LeaveAccessor, accessor);
}
public event Action<VariableInitializer> EnterVariableInitializer, LeaveVariableInitializer;
void IAstVisitor.VisitVariableInitializer(VariableInitializer variableInitializer)
{
Visit(EnterVariableInitializer, LeaveVariableInitializer, variableInitializer);
}
public event Action<ParameterDeclaration> EnterParameterDeclaration, LeaveParameterDeclaration;
void IAstVisitor.VisitParameterDeclaration(ParameterDeclaration parameterDeclaration)
{
Visit(EnterParameterDeclaration, LeaveParameterDeclaration, parameterDeclaration);
}
public event Action<Constraint> EnterConstraint, LeaveConstraint;
void IAstVisitor.VisitConstraint(Constraint constraint)
{
Visit(EnterConstraint, LeaveConstraint, constraint);
}
public event Action<BlockStatement> EnterBlockStatement, LeaveBlockStatement;
void IAstVisitor.VisitBlockStatement(BlockStatement blockStatement)
{
Visit(EnterBlockStatement, LeaveBlockStatement, blockStatement);
}
public event Action<ExpressionStatement> EnterExpressionStatement, LeaveExpressionStatement;
void IAstVisitor.VisitExpressionStatement(ExpressionStatement expressionStatement)
{
Visit(EnterExpressionStatement, LeaveExpressionStatement, expressionStatement);
}
public event Action<BreakStatement> EnterBreakStatement, LeaveBreakStatement;
void IAstVisitor.VisitBreakStatement(BreakStatement breakStatement)
{
Visit(EnterBreakStatement, LeaveBreakStatement, breakStatement);
}
public event Action<CheckedStatement> EnterCheckedStatement, LeaveCheckedStatement;
void IAstVisitor.VisitCheckedStatement(CheckedStatement checkedStatement)
{
Visit(EnterCheckedStatement, LeaveCheckedStatement, checkedStatement);
}
public event Action<ContinueStatement> EnterContinueStatement, LeaveContinueStatement;
void IAstVisitor.VisitContinueStatement(ContinueStatement continueStatement)
{
Visit(EnterContinueStatement, LeaveContinueStatement, continueStatement);
}
public event Action<DoWhileStatement> EnterDoWhileStatement, LeaveDoWhileStatement;
void IAstVisitor.VisitDoWhileStatement(DoWhileStatement doWhileStatement)
{
Visit(EnterDoWhileStatement, LeaveDoWhileStatement, doWhileStatement);
}
public event Action<EmptyStatement> EnterEmptyStatement, LeaveEmptyStatement;
void IAstVisitor.VisitEmptyStatement(EmptyStatement emptyStatement)
{
Visit(EnterEmptyStatement, LeaveEmptyStatement, emptyStatement);
}
public event Action<FixedStatement> EnterFixedStatement, LeaveFixedStatement;
void IAstVisitor.VisitFixedStatement(FixedStatement fixedStatement)
{
Visit(EnterFixedStatement, LeaveFixedStatement, fixedStatement);
}
public event Action<ForeachStatement> EnterForeachStatement, LeaveForeachStatement;
void IAstVisitor.VisitForeachStatement(ForeachStatement foreachStatement)
{
Visit(EnterForeachStatement, LeaveForeachStatement, foreachStatement);
}
public event Action<ForStatement> EnterForStatement, LeaveForStatement;
void IAstVisitor.VisitForStatement(ForStatement forStatement)
{
Visit(EnterForStatement, LeaveForStatement, forStatement);
}
public event Action<GotoCaseStatement> EnterGotoCaseStatement, LeaveGotoCaseStatement;
void IAstVisitor.VisitGotoCaseStatement(GotoCaseStatement gotoCaseStatement)
{
Visit(EnterGotoCaseStatement, LeaveGotoCaseStatement, gotoCaseStatement);
}
public event Action<GotoDefaultStatement> EnterGotoDefaultStatement, LeaveGotoDefaultStatement;
void IAstVisitor.VisitGotoDefaultStatement(GotoDefaultStatement gotoDefaultStatement)
{
Visit(EnterGotoDefaultStatement, LeaveGotoDefaultStatement, gotoDefaultStatement);
}
public event Action<GotoStatement> EnterGotoStatement, LeaveGotoStatement;
void IAstVisitor.VisitGotoStatement(GotoStatement gotoStatement)
{
Visit(EnterGotoStatement, LeaveGotoStatement, gotoStatement);
}
public event Action<IfElseStatement> EnterIfElseStatement, LeaveIfElseStatement;
void IAstVisitor.VisitIfElseStatement(IfElseStatement ifElseStatement)
{
Visit(EnterIfElseStatement, LeaveIfElseStatement, ifElseStatement);
}
public event Action<LabelStatement> EnterLabelStatement, LeaveLabelStatement;
void IAstVisitor.VisitLabelStatement(LabelStatement labelStatement)
{
Visit(EnterLabelStatement, LeaveLabelStatement, labelStatement);
}
public event Action<LockStatement> EnterLockStatement, LeaveLockStatement;
void IAstVisitor.VisitLockStatement(LockStatement lockStatement)
{
Visit(EnterLockStatement, LeaveLockStatement, lockStatement);
}
public event Action<ReturnStatement> EnterReturnStatement, LeaveReturnStatement;
void IAstVisitor.VisitReturnStatement(ReturnStatement returnStatement)
{
Visit(EnterReturnStatement, LeaveReturnStatement, returnStatement);
}
public event Action<SwitchStatement> EnterSwitchStatement, LeaveSwitchStatement;
void IAstVisitor.VisitSwitchStatement(SwitchStatement switchStatement)
{
Visit(EnterSwitchStatement, LeaveSwitchStatement, switchStatement);
}
public event Action<SwitchSection> EnterSwitchSection, LeaveSwitchSection;
void IAstVisitor.VisitSwitchSection(SwitchSection switchSection)
{
Visit(EnterSwitchSection, LeaveSwitchSection, switchSection);
}
public event Action<CaseLabel> EnterCaseLabel, LeaveCaseLabel;
void IAstVisitor.VisitCaseLabel(CaseLabel caseLabel)
{
Visit(EnterCaseLabel, LeaveCaseLabel, caseLabel);
}
public event Action<ThrowStatement> EnterThrowStatement, LeaveThrowStatement;
void IAstVisitor.VisitThrowStatement(ThrowStatement throwStatement)
{
Visit(EnterThrowStatement, LeaveThrowStatement, throwStatement);
}
public event Action<TryCatchStatement> EnterTryCatchStatement, LeaveTryCatchStatement;
void IAstVisitor.VisitTryCatchStatement(TryCatchStatement tryCatchStatement)
{
Visit(EnterTryCatchStatement, LeaveTryCatchStatement, tryCatchStatement);
}
public event Action<CatchClause> EnterCatchClause, LeaveCatchClause;
void IAstVisitor.VisitCatchClause(CatchClause catchClause)
{
Visit(EnterCatchClause, LeaveCatchClause, catchClause);
}
public event Action<UncheckedStatement> EnterUncheckedStatement, LeaveUncheckedStatement;
void IAstVisitor.VisitUncheckedStatement(UncheckedStatement uncheckedStatement)
{
Visit(EnterUncheckedStatement, LeaveUncheckedStatement, uncheckedStatement);
}
public event Action<UnsafeStatement> EnterUnsafeStatement, LeaveUnsafeStatement;
void IAstVisitor.VisitUnsafeStatement(UnsafeStatement unsafeStatement)
{
Visit(EnterUnsafeStatement, LeaveUnsafeStatement, unsafeStatement);
}
public event Action<UsingStatement> EnterUsingStatement, LeaveUsingStatement;
void IAstVisitor.VisitUsingStatement(UsingStatement usingStatement)
{
Visit(EnterUsingStatement, LeaveUsingStatement, usingStatement);
}
public event Action<VariableDeclarationStatement> EnterVariableDeclarationStatement, LeaveVariableDeclarationStatement;
void IAstVisitor.VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement)
{
Visit(EnterVariableDeclarationStatement, LeaveVariableDeclarationStatement, variableDeclarationStatement);
}
public event Action<WhileStatement> EnterWhileStatement, LeaveWhileStatement;
void IAstVisitor.VisitWhileStatement(WhileStatement whileStatement)
{
Visit(EnterWhileStatement, LeaveWhileStatement, whileStatement);
}
public event Action<YieldBreakStatement> EnterYieldBreakStatement, LeaveYieldBreakStatement;
void IAstVisitor.VisitYieldBreakStatement(YieldBreakStatement yieldBreakStatement)
{
Visit(EnterYieldBreakStatement, LeaveYieldBreakStatement, yieldBreakStatement);
}
public event Action<YieldReturnStatement> EnterYieldReturnStatement, LeaveYieldReturnStatement;
void IAstVisitor.VisitYieldReturnStatement(YieldReturnStatement yieldStatement)
{
Visit(EnterYieldReturnStatement, LeaveYieldReturnStatement, yieldStatement);
}
public event Action<AnonymousMethodExpression> EnterAnonymousMethodExpression, LeaveAnonymousMethodExpression;
void IAstVisitor.VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression)
{
Visit(EnterAnonymousMethodExpression, LeaveAnonymousMethodExpression, anonymousMethodExpression);
}
public event Action<LambdaExpression> EnterLambdaExpression, LeaveLambdaExpression;
void IAstVisitor.VisitLambdaExpression(LambdaExpression lambdaExpression)
{
Visit(EnterLambdaExpression, LeaveLambdaExpression, lambdaExpression);
}
public event Action<AssignmentExpression> EnterAssignmentExpression, LeaveAssignmentExpression;
void IAstVisitor.VisitAssignmentExpression(AssignmentExpression assignmentExpression)
{
Visit(EnterAssignmentExpression, LeaveAssignmentExpression, assignmentExpression);
}
public event Action<BaseReferenceExpression> EnterBaseReferenceExpression, LeaveBaseReferenceExpression;
void IAstVisitor.VisitBaseReferenceExpression(BaseReferenceExpression baseReferenceExpression)
{
Visit(EnterBaseReferenceExpression, LeaveBaseReferenceExpression, baseReferenceExpression);
}
public event Action<BinaryOperatorExpression> EnterBinaryOperatorExpression, LeaveBinaryOperatorExpression;
void IAstVisitor.VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression)
{
Visit(EnterBinaryOperatorExpression, LeaveBinaryOperatorExpression, binaryOperatorExpression);
}
public event Action<CastExpression> EnterCastExpression, LeaveCastExpression;
void IAstVisitor.VisitCastExpression(CastExpression castExpression)
{
Visit(EnterCastExpression, LeaveCastExpression, castExpression);
}
public event Action<CheckedExpression> EnterCheckedExpression, LeaveCheckedExpression;
void IAstVisitor.VisitCheckedExpression(CheckedExpression checkedExpression)
{
Visit(EnterCheckedExpression, LeaveCheckedExpression, checkedExpression);
}
public event Action<ConditionalExpression> EnterConditionalExpression, LeaveConditionalExpression;
void IAstVisitor.VisitConditionalExpression(ConditionalExpression conditionalExpression)
{
Visit(EnterConditionalExpression, LeaveConditionalExpression, conditionalExpression);
}
public event Action<IdentifierExpression> EnterIdentifierExpression, LeaveIdentifierExpression;
void IAstVisitor.VisitIdentifierExpression(IdentifierExpression identifierExpression)
{
Visit(EnterIdentifierExpression, LeaveIdentifierExpression, identifierExpression);
}
public event Action<IndexerExpression> EnterIndexerExpression, LeaveIndexerExpression;
void IAstVisitor.VisitIndexerExpression(IndexerExpression indexerExpression)
{
Visit(EnterIndexerExpression, LeaveIndexerExpression, indexerExpression);
}
public event Action<InvocationExpression> EnterInvocationExpression, LeaveInvocationExpression;
void IAstVisitor.VisitInvocationExpression(InvocationExpression invocationExpression)
{
Visit(EnterInvocationExpression, LeaveInvocationExpression, invocationExpression);
}
public event Action<DirectionExpression> EnterDirectionExpression, LeaveDirectionExpression;
void IAstVisitor.VisitDirectionExpression(DirectionExpression directionExpression)
{
Visit(EnterDirectionExpression, LeaveDirectionExpression, directionExpression);
}
public event Action<MemberReferenceExpression> EnterMemberReferenceExpression, LeaveMemberReferenceExpression;
void IAstVisitor.VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression)
{
Visit(EnterMemberReferenceExpression, LeaveMemberReferenceExpression, memberReferenceExpression);
}
public event Action<NullReferenceExpression> EnterNullReferenceExpression, LeaveNullReferenceExpression;
void IAstVisitor.VisitNullReferenceExpression(NullReferenceExpression nullReferenceExpression)
{
Visit(EnterNullReferenceExpression, LeaveNullReferenceExpression, nullReferenceExpression);
}
public event Action<ObjectCreateExpression> EnterObjectCreateExpression, LeaveObjectCreateExpression;
void IAstVisitor.VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression)
{
Visit(EnterObjectCreateExpression, LeaveObjectCreateExpression, objectCreateExpression);
}
public event Action<OutVarDeclarationExpression> EnterOutVarDeclarationExpression, LeaveOutVarDeclarationExpression;
void IAstVisitor.VisitOutVarDeclarationExpression(OutVarDeclarationExpression outVarDeclarationExpression)
{
Visit(EnterOutVarDeclarationExpression, LeaveOutVarDeclarationExpression, outVarDeclarationExpression);
}
public event Action<AnonymousTypeCreateExpression> EnterAnonymousTypeCreateExpression, LeaveAnonymousTypeCreateExpression;
void IAstVisitor.VisitAnonymousTypeCreateExpression(AnonymousTypeCreateExpression anonymousTypeCreateExpression)
{
Visit(EnterAnonymousTypeCreateExpression, LeaveAnonymousTypeCreateExpression, anonymousTypeCreateExpression);
}
public event Action<ArrayCreateExpression> EnterArrayCreateExpression, LeaveArrayCreateExpression;
void IAstVisitor.VisitArrayCreateExpression(ArrayCreateExpression arraySCreateExpression)
{
Visit(EnterArrayCreateExpression, LeaveArrayCreateExpression, arraySCreateExpression);
}
public event Action<ParenthesizedExpression> EnterParenthesizedExpression, LeaveParenthesizedExpression;
void IAstVisitor.VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression)
{
Visit(EnterParenthesizedExpression, LeaveParenthesizedExpression, parenthesizedExpression);
}
public event Action<PointerReferenceExpression> EnterPointerReferenceExpression, LeavePointerReferenceExpression;
void IAstVisitor.VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression)
{
Visit(EnterPointerReferenceExpression, LeavePointerReferenceExpression, pointerReferenceExpression);
}
public event Action<PrimitiveExpression> EnterPrimitiveExpression, LeavePrimitiveExpression;
void IAstVisitor.VisitPrimitiveExpression(PrimitiveExpression primitiveExpression)
{
Visit(EnterPrimitiveExpression, LeavePrimitiveExpression, primitiveExpression);
}
public event Action<SizeOfExpression> EnterSizeOfExpression, LeaveSizeOfExpression;
void IAstVisitor.VisitSizeOfExpression(SizeOfExpression sizeOfExpression)
{
Visit(EnterSizeOfExpression, LeaveSizeOfExpression, sizeOfExpression);
}
public event Action<StackAllocExpression> EnterStackAllocExpression, LeaveStackAllocExpression;
void IAstVisitor.VisitStackAllocExpression(StackAllocExpression stackAllocExpression)
{
Visit(EnterStackAllocExpression, LeaveStackAllocExpression, stackAllocExpression);
}
public event Action<ThisReferenceExpression> EnterThisReferenceExpression, LeaveThisReferenceExpression;
void IAstVisitor.VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression)
{
Visit(EnterThisReferenceExpression, LeaveThisReferenceExpression, thisReferenceExpression);
}
public event Action<TypeOfExpression> EnterTypeOfExpression, LeaveTypeOfExpression;
void IAstVisitor.VisitTypeOfExpression(TypeOfExpression typeOfExpression)
{
Visit(EnterTypeOfExpression, LeaveTypeOfExpression, typeOfExpression);
}
public event Action<TypeReferenceExpression> EnterTypeReferenceExpression, LeaveTypeReferenceExpression;
void IAstVisitor.VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression)
{
Visit(EnterTypeReferenceExpression, LeaveTypeReferenceExpression, typeReferenceExpression);
}
public event Action<UnaryOperatorExpression> EnterUnaryOperatorExpression, LeaveUnaryOperatorExpression;
void IAstVisitor.VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression)
{
Visit(EnterUnaryOperatorExpression, LeaveUnaryOperatorExpression, unaryOperatorExpression);
}
public event Action<UncheckedExpression> EnterUncheckedExpression, LeaveUncheckedExpression;
void IAstVisitor.VisitUncheckedExpression(UncheckedExpression uncheckedExpression)
{
Visit(EnterUncheckedExpression, LeaveUncheckedExpression, uncheckedExpression);
}
public event Action<QueryExpression> EnterQueryExpression, LeaveQueryExpression;
void IAstVisitor.VisitQueryExpression(QueryExpression queryExpression)
{
Visit(EnterQueryExpression, LeaveQueryExpression, queryExpression);
}
public event Action<QueryContinuationClause> EnterQueryContinuationClause, LeaveQueryContinuationClause;
void IAstVisitor.VisitQueryContinuationClause(QueryContinuationClause queryContinuationClause)
{
Visit(EnterQueryContinuationClause, LeaveQueryContinuationClause, queryContinuationClause);
}
public event Action<QueryFromClause> EnterQueryFromClause, LeaveQueryFromClause;
void IAstVisitor.VisitQueryFromClause(QueryFromClause queryFromClause)
{
Visit(EnterQueryFromClause, LeaveQueryFromClause, queryFromClause);
}
public event Action<QueryLetClause> EnterQueryLetClause, LeaveQueryLetClause;
void IAstVisitor.VisitQueryLetClause(QueryLetClause queryLetClause)
{
Visit(EnterQueryLetClause, LeaveQueryLetClause, queryLetClause);
}
public event Action<QueryWhereClause> EnterQueryWhereClause, LeaveQueryWhereClause;
void IAstVisitor.VisitQueryWhereClause(QueryWhereClause queryWhereClause)
{
Visit(EnterQueryWhereClause, LeaveQueryWhereClause, queryWhereClause);
}
public event Action<QueryJoinClause> EnterQueryJoinClause, LeaveQueryJoinClause;
void IAstVisitor.VisitQueryJoinClause(QueryJoinClause queryJoinClause)
{
Visit(EnterQueryJoinClause, LeaveQueryJoinClause, queryJoinClause);
}
public event Action<QueryOrderClause> EnterQueryOrderClause, LeaveQueryOrderClause;
void IAstVisitor.VisitQueryOrderClause(QueryOrderClause queryOrderClause)
{
Visit(EnterQueryOrderClause, LeaveQueryOrderClause, queryOrderClause);
}
public event Action<QueryOrdering> EnterQueryOrdering, LeaveQueryOrdering;
void IAstVisitor.VisitQueryOrdering(QueryOrdering queryOrdering)
{
Visit(EnterQueryOrdering, LeaveQueryOrdering, queryOrdering);
}
public event Action<QuerySelectClause> EnterQuerySelectClause, LeaveQuerySelectClause;
void IAstVisitor.VisitQuerySelectClause(QuerySelectClause querySelectClause)
{
Visit(EnterQuerySelectClause, LeaveQuerySelectClause, querySelectClause);
}
public event Action<QueryGroupClause> EnterQueryGroupClause, LeaveQueryGroupClause;
void IAstVisitor.VisitQueryGroupClause(QueryGroupClause queryGroupClause)
{
Visit(EnterQueryGroupClause, LeaveQueryGroupClause, queryGroupClause);
}
public event Action<AsExpression> EnterAsExpression, LeaveAsExpression;
void IAstVisitor.VisitAsExpression(AsExpression asExpression)
{
Visit(EnterAsExpression, LeaveAsExpression, asExpression);
}
public event Action<IsExpression> EnterIsExpression, LeaveIsExpression;
void IAstVisitor.VisitIsExpression(IsExpression isExpression)
{
Visit(EnterIsExpression, LeaveIsExpression, isExpression);
}
public event Action<DefaultValueExpression> EnterDefaultValueExpression, LeaveDefaultValueExpression;
void IAstVisitor.VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression)
{
Visit(EnterDefaultValueExpression, LeaveDefaultValueExpression, defaultValueExpression);
}
public event Action<UndocumentedExpression> EnterUndocumentedExpression, LeaveUndocumentedExpression;
void IAstVisitor.VisitUndocumentedExpression(UndocumentedExpression undocumentedExpression)
{
Visit(EnterUndocumentedExpression, LeaveUndocumentedExpression, undocumentedExpression);
}
public event Action<ArrayInitializerExpression> EnterArrayInitializerExpression, LeaveArrayInitializerExpression;
void IAstVisitor.VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression)
{
Visit(EnterArrayInitializerExpression, LeaveArrayInitializerExpression, arrayInitializerExpression);
}
public event Action<ArraySpecifier> EnterArraySpecifier, LeaveArraySpecifier;
void IAstVisitor.VisitArraySpecifier(ArraySpecifier arraySpecifier)
{
Visit(EnterArraySpecifier, LeaveArraySpecifier, arraySpecifier);
}
public event Action<NamedArgumentExpression> EnterNamedArgumentExpression, LeaveNamedArgumentExpression;
void IAstVisitor.VisitNamedArgumentExpression(NamedArgumentExpression namedArgumentExpression)
{
Visit(EnterNamedArgumentExpression, LeaveNamedArgumentExpression, namedArgumentExpression);
}
public event Action<NamedExpression> EnterNamedExpression, LeaveNamedExpression;
void IAstVisitor.VisitNamedExpression(NamedExpression namedExpression)
{
Visit(EnterNamedExpression, LeaveNamedExpression, namedExpression);
}
void IAstVisitor.VisitPatternPlaceholder(AstNode placeholder, PatternMatching.Pattern pattern)
{
}
}
}

29
ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs

@ -24,7 +24,6 @@ using ICSharpCode.Decompiler.CSharp.Syntax; @@ -24,7 +24,6 @@ using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
using ICSharpCode.Decompiler.CSharp.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.CSharp.Analysis;
using Mono.Cecil;
using ICSharpCode.Decompiler.Semantics;
@ -313,34 +312,6 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -313,34 +312,6 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return null;
}
/// <summary>
/// Gets whether the old variable value (assigned inside 'targetStatement' or earlier)
/// is read anywhere in the remaining scope of the variable declaration.
/// </summary>
bool IsVariableValueUnused(VariableDeclarationStatement varDecl, Statement targetStatement)
{
Debug.Assert(targetStatement.Ancestors.Contains(varDecl.Parent));
BlockStatement block = (BlockStatement)varDecl.Parent;
DefiniteAssignmentAnalysis daa = CreateDAA(block);
daa.SetAnalyzedRange(targetStatement, block, startInclusive: false);
daa.Analyze(varDecl.Variables.Single().Name);
return daa.UnassignedVariableUses.Count == 0;
}
// I used this in the first implementation of the using-statement transform, but now no longer
// because there were problems when multiple using statements were using the same variable
// - no single using statement could be transformed without making the C# code invalid,
// but transforming both would work.
// We now use 'IsVariableValueUnused' which will perform the transform
// even if it results in two variables with the same name and overlapping scopes.
// (this issue could be fixed later by renaming one of the variables)
private DefiniteAssignmentAnalysis CreateDAA(BlockStatement block)
{
var typeResolveContext = new CSharpTypeResolveContext(context.TypeSystem.MainAssembly);
return new DefiniteAssignmentAnalysis(block, (node, ct) => node.GetResolveResult(), typeResolveContext, context.CancellationToken);
}
/// <summary>
/// Gets whether there is an assignment to 'variableName' anywhere within the given node.
/// </summary>

8
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -54,8 +54,6 @@ @@ -54,8 +54,6 @@
</ItemGroup>
<ItemGroup>
<Compile Include="CSharp\Analysis\ControlFlow.cs" />
<Compile Include="CSharp\Analysis\DefiniteAssignmentAnalysis.cs" />
<Compile Include="CSharp\Annotations.cs" />
<Compile Include="CSharp\Syntax\AstNode.cs" />
<Compile Include="CSharp\Syntax\AstNodeCollection.cs" />
@ -128,7 +126,6 @@ @@ -128,7 +126,6 @@
<Compile Include="CSharp\Syntax\MemberType.cs" />
<Compile Include="CSharp\Syntax\Modifiers.cs" />
<Compile Include="CSharp\Syntax\NodeType.cs" />
<Compile Include="CSharp\Syntax\ObservableAstVisitor.cs" />
<Compile Include="CSharp\Syntax\PatternMatching\AnyNode.cs" />
<Compile Include="CSharp\Syntax\PatternMatching\AnyNodeOrNull.cs" />
<Compile Include="CSharp\Syntax\PatternMatching\Backreference.cs" />
@ -204,22 +201,17 @@ @@ -204,22 +201,17 @@
<Compile Include="CSharp\Resolver\AliasTypeResolveResult.cs" />
<Compile Include="CSharp\Resolver\AwaitResolveResult.cs" />
<Compile Include="CSharp\Resolver\CastResolveResult.cs" />
<Compile Include="CSharp\Resolver\CompositeResolveVisitorNavigator.cs" />
<Compile Include="CSharp\Resolver\CSharpConversions.cs" />
<Compile Include="CSharp\Resolver\CSharpInvocationResolveResult.cs" />
<Compile Include="CSharp\Resolver\CSharpOperators.cs" />
<Compile Include="CSharp\Resolver\CSharpResolver.cs" />
<Compile Include="CSharp\Resolver\DetectSkippableNodesNavigator.cs" />
<Compile Include="CSharp\Resolver\DynamicInvocationResolveResult.cs" />
<Compile Include="CSharp\Resolver\DynamicMemberResolveResult.cs" />
<Compile Include="CSharp\Resolver\FindReferencedEntities.cs" />
<Compile Include="CSharp\Resolver\IResolveVisitorNavigator.cs" />
<Compile Include="CSharp\Resolver\LambdaResolveResult.cs" />
<Compile Include="CSharp\Resolver\Log.cs" />
<Compile Include="CSharp\Resolver\MemberLookup.cs" />
<Compile Include="CSharp\Resolver\MethodGroupResolveResult.cs" />
<Compile Include="CSharp\Resolver\NameLookupMode.cs" />
<Compile Include="CSharp\Resolver\NodeListResolveVisitorNavigator.cs" />
<Compile Include="CSharp\Resolver\OverloadResolution.cs" />
<Compile Include="CSharp\Resolver\OverloadResolutionErrors.cs" />
<Compile Include="CSharp\Resolver\ReducedExtensionMethod.cs" />

Loading…
Cancel
Save