Exemple #1
0
        /// <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}");
            }
        }