/// <summary> /// Locates the target for an expression. /// </summary> /// <returns>The data element.</returns> /// <param name="network">The top-level network.</param> /// <param name="proc">The process where the method is located.</param> /// <param name="method">The method where the statement is found.</param> /// <param name="statement">The statement where the expression is found.</param> /// <param name="expression">The expression to examine.</param> protected ASTItem TryLocateElement(NetworkState network, ProcessState proc, MethodState method, Statement statement, ICSharpCode.Decompiler.CSharp.Syntax.Expression expression) { if (expression is ICSharpCode.Decompiler.CSharp.Syntax.InvocationExpression) { var e = expression as ICSharpCode.Decompiler.CSharp.Syntax.InvocationExpression; var target = e.Target; return(LocateDataElement(network, proc, method, statement, target)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.IndexerExpression) { var e = expression as ICSharpCode.Decompiler.CSharp.Syntax.IndexerExpression; var target = e.Target; return(LocateDataElement(network, proc, method, statement, target)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.IdentifierExpression) { var e = expression as ICSharpCode.Decompiler.CSharp.Syntax.IdentifierExpression; var name = e.Identifier; Variable variable; if (method != null && method.TryGetVariable(name, out variable)) { return(variable); } if (method != null) { var p = method.Parameters.FirstOrDefault(x => x.Name == name); if (p != null) { return(p); } } if (proc.Variables.TryGetValue(name, out variable)) { return(variable); } Signal signal; if (proc != null && proc.Signals.TryGetValue(name, out signal)) { return(signal); } return(null); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.MemberReferenceExpression) { var e = expression as ICSharpCode.Decompiler.CSharp.Syntax.MemberReferenceExpression; ASTItem current = null; var parts = new List <string>(); ICSharpCode.Decompiler.CSharp.Syntax.Expression ec = e; while (ec != null) { if (ec is ICSharpCode.Decompiler.CSharp.Syntax.MemberReferenceExpression) { parts.Add(((ICSharpCode.Decompiler.CSharp.Syntax.MemberReferenceExpression)ec).MemberName); ec = ((ICSharpCode.Decompiler.CSharp.Syntax.MemberReferenceExpression)ec).Target; } else if (ec is ICSharpCode.Decompiler.CSharp.Syntax.ThisReferenceExpression) { //parts.Add("this"); ec = null; break; } else if (ec is ICSharpCode.Decompiler.CSharp.Syntax.IdentifierExpression) { parts.Add(((ICSharpCode.Decompiler.CSharp.Syntax.IdentifierExpression)ec).Identifier); ec = null; break; } else if (ec is ICSharpCode.Decompiler.CSharp.Syntax.TypeReferenceExpression) { TypeDefinition dc = null; if (method != null) { dc = method.SourceMethod.DeclaringType; } else if (proc != null) { dc = proc.CecilType.Resolve(); } var ecs = ec.ToString(); if (dc != null) { if (ecs == dc.FullName || ecs == dc.Name) { ec = null; //parts.Add("this"); break; } var targetproc = network.Processes.FirstOrDefault(x => x.CecilType.Name == ecs || x.CecilType.FullName == ecs); if (targetproc != null) { // This is a static reference current = null; //targetproc; break; } var bt = LoadTypeByName(ecs, dc.Module); if (bt == null) { bt = LoadTypeByName(dc.FullName + "." + ecs, method.SourceMethod.Module); } if (bt == null) { bt = LoadTypeByName(dc.Namespace + "." + ecs, method.SourceMethod.Module); } // In some cases dc.Namespace is empty ... if (bt == null && proc != null && proc.SourceType != null) { bt = LoadTypeByName(proc.SourceType.Namespace + "." + ecs, method.SourceMethod.Module); } if (bt != null && parts.Count == 1) { var br = bt.Resolve(); var px = br.Fields.FirstOrDefault(x => x.Name == parts[0]); // Enum flags are encoded as constants if (br.IsEnum) { if (px == null) { throw new Exception($"Unable to find enum value {parts[0]} in {br.FullName}"); } return(new Constant() { CecilType = bt, DefaultValue = px, Source = expression }); } else { // This is a constant of sorts var pe = network.ConstantLookup.Keys.FirstOrDefault(x => x.Name == parts[0]); if (pe != null) { return(network.ConstantLookup[pe]); } return(network.ConstantLookup[px] = new Constant() { CecilType = px.FieldType, Name = parts[0], Source = px, Parent = network }); } //parts.AddRange(bt.FullName.Split('.').Reverse()); } break; } // Likely a static reference, which is stored as a global constant ec = null; } else { throw new Exception($"Unexpected element in reference chain: {ec.GetType().FullName}"); } } parts.Reverse(); var fullname = string.Join(".", parts); if (parts.First() == "this") { parts.RemoveAt(0); if (proc == null) { throw new Exception("Attempting to do a resolve of \this\" but no process context is provided"); } current = proc; } var first = true; foreach (var el in parts) { var isIsFirst = first; first = false; if (current == null) { var pe = network.ConstantLookup.Keys.FirstOrDefault(x => x.Name == el); if (pe != null) { current = network.ConstantLookup[pe]; continue; } } if (current is MethodState || (isIsFirst && current == null)) { //if (method.LocalRenames.ContainsKey(el)) // el = method.LocalRenames[el]; var mt = current as MethodState ?? method; if (mt != null) { Variable temp; if (mt.TryGetVariable(el, out temp)) { current = temp; continue; } var p = mt.Parameters.FirstOrDefault(x => x.Name == el); if (p != null) { current = p; continue; } if (mt.ReturnVariable != null && !string.IsNullOrWhiteSpace(mt.ReturnVariable.Name) && el == mt.ReturnVariable.Name) { current = mt.ReturnVariable; continue; } } } if (current is ProcessState || (isIsFirst && current == null)) { var pr = current as ProcessState ?? proc; if (pr != null) { if (pr.BusInstances.ContainsKey(el)) { current = pr.BusInstances[el]; continue; } if (pr.Signals.ContainsKey(el)) { current = pr.Signals[el]; continue; } if (pr.Variables.ContainsKey(el)) { current = pr.Variables[el]; continue; } if (pr.Methods != null) { var p = pr.Methods.FirstOrDefault(x => x.Name == el); if (p != null) { current = p; continue; } } } } if (current is Bus) { current = ((Bus)current).Signals.FirstOrDefault(x => x.Name == el); if (current != null) { continue; } } if (current is Variable) { var fi = ((Variable)current).CecilType.Resolve().Fields.FirstOrDefault(x => x.Name == el); if (fi != null) { current = new Variable() { Name = el, Parent = current, Source = fi, CecilType = fi.FieldType, DefaultValue = null }; continue; } var pi = ((Variable)current).CecilType.Resolve().Properties.FirstOrDefault(x => x.Name == el); if (pi != null) { current = new Variable() { Name = el, Parent = current, Source = fi, CecilType = fi.FieldType, DefaultValue = null }; continue; } } if (el == "Length" && (current is DataElement) && ((DataElement)current).CecilType.IsArrayType()) { return(new Constant() { ArrayLengthSource = current as DataElement, CecilType = LoadType(typeof(int)), DefaultValue = null, Source = (current as DataElement).Source }); } throw new Exception($"Failed lookup at {el} in {fullname}"); } if (current == null) { throw new Exception($"Failed to fully resolve {fullname}"); } return(current); } else { throw new Exception($"Unable to find a data element for an expression of type {expression.GetType().FullName}"); } }