{"id":28,"date":"2013-12-01T18:12:00","date_gmt":"2013-12-01T18:12:00","guid":{"rendered":"http:\/\/tpodolak.com.hostingasp.pl\/blog\/2013\/12\/01\/how-to-check-if-one-function-calls-another-function\/"},"modified":"2016-01-30T23:42:28","modified_gmt":"2016-01-30T23:42:28","slug":"how-to-check-if-one-function-calls-another-function","status":"publish","type":"post","link":"https:\/\/tpodolak.com\/blog\/2013\/12\/01\/how-to-check-if-one-function-calls-another-function\/","title":{"rendered":"How to check if one function calls another function"},"content":{"rendered":"<p>An application which I&#8217;m currently developing has quite complicated authorization system. That is why, we can not use role based authorization, and basically every developer is obliged to call appropriate security check method in every controller action he or she writes. As You probably know it is quite easy to forget about that, therefore I decided to write a test which would check whether all controller&#8217;s action invokes this security critical function. After hours of searching for some anchor point, I came across this article http:\/\/blogs.msdn.com\/b\/haibo_luo\/archive\/2006\/11\/06\/system-reflection-based-ilreader.aspx in which author creates so called &#8220;reflection based ILReader&#8221;. <i>ILReader<\/i> is a class which allows You to iterate over IL instructions of every object of type <i>RuntimeMethodInfo<\/i> or <i>RuntimeConstructorInfo<\/i> .One of these instructions is <i>InlineMethodInstruction<\/i> which indicates method call. That is why, in order to get all methods which are called by given method, we have to simply select all instructions of type <i>InlineMethodInstruction<\/i><\/p>\n<pre lang=\"csharp\">\r\npublic static class MethodInvokerCrawler\r\n{\r\n    public static IEnumerable<MethodBase> GetMethods(MethodBase caller)\r\n    {\r\n        ILReader reader = new ILReader(caller);\r\n        return reader.OfType<InlineMethodInstruction>().Select(method => method.Method);\r\n    }\r\n}\r\n<\/pre>\n<p>We can go a bit further and create a recursive version of this function to iterate over entire function execution chain<\/p>\n<pre lang=\"csharp\">\r\npublic static class MethodInvokerCrawler\r\n{\r\n    public const string DefaultPrefix = \"GeneralLearning\";\r\n    public static IEnumerable<MethodBase> GetMethods(MethodBase caller, bool recursive = false, string namespacePrefix = DefaultPrefix)\r\n    {\r\n        ILReader reader = new ILReader(caller);\r\n        foreach (InlineMethodInstruction method in\r\n            reader.OfType<InlineMethodInstruction>())\r\n        {\r\n            yield return method.Method;\r\n            if (recursive && method.Method.DeclaringType != null && method.Method.DeclaringType.FullName.StartsWith(namespacePrefix, StringComparison.InvariantCultureIgnoreCase))\r\n            {\r\n                foreach (var innerMethod in GetMethods(method.Method))\r\n                {\r\n                    yield return innerMethod;\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>Please notice, that I limited recursion depth to methods from user defined namespace, otherwise we would end up iterating over .NET&#8217;s native functions.<br \/>\nNow it is time to show some results. Here is a sample program which demonstrate possibilities of <i>MethodInvokerCrawler<\/i> class<\/p>\n<pre lang=\"csharp\">\r\ninternal class Program\r\n{\r\n    public class FooClass\r\n    {\r\n        public FooClass()\r\n        {\r\n            this.X();\r\n            this.Foo();\r\n            this.Bar();\r\n        }\r\n\r\n        public void Foo(){}\r\n\r\n        public void Bar()\r\n        {\r\n            this.Z();\r\n            this.Foo();\r\n        }\r\n\r\n        public string X()\r\n        {\r\n            return null;\r\n        }\r\n\r\n        public void Y(){ }\r\n\r\n        public void Z()\r\n        {\r\n            this.Y();\r\n        }\r\n    }\r\n\r\n    public static void Main(string[] args)\r\n    {\r\n        Console.WriteLine(\"=== execution chain of Bar function no recursion ===\");\r\n        foreach (var s in MethodInvokerCrawler.GetMethods(typeof(FooClass).GetMethod(\"Bar\")))\r\n        {\r\n            Console.WriteLine(\"{0}.{1}\", s.DeclaringType.FullName, s.Name);\r\n        }\r\n\r\n        Console.WriteLine();\r\n        Console.WriteLine(\"=== execution chain of Bar function with recursion ===\");\r\n        foreach (var s in MethodInvokerCrawler.GetMethods(typeof(FooClass).GetMethod(\"Bar\"), true))\r\n        {\r\n            Console.WriteLine(\"{0}.{1}\", s.DeclaringType.FullName, s.Name);\r\n        }\r\n\r\n        Console.WriteLine();\r\n        Console.WriteLine(\"execution chain of FooClass default constructor no recursion\");\r\n        foreach (var s in MethodInvokerCrawler.GetMethods(typeof(FooClass).GetConstructors().Single()))\r\n        {\r\n            Console.WriteLine(\"{0}.{1}\", s.DeclaringType.FullName, s.Name);\r\n        }\r\n\r\n        Console.WriteLine();\r\n        Console.WriteLine(\"execution chain of FooClass default constructor with recursion\");\r\n        foreach (var s in MethodInvokerCrawler.GetMethods(typeof(FooClass).GetConstructors().Single(), true))\r\n        {\r\n            Console.WriteLine(\"{0}.{1}\", s.DeclaringType.FullName, s.Name);\r\n        }\r\n        Console.ReadKey();\r\n    }\r\n}\r\n<\/pre>\n<p><a href=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2013\/12\/how-to-check-if-one-function-calls-another-function\/result.png\" rel=\"attachment wp-att-338\"><img decoding=\"async\" src=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2013\/12\/how-to-check-if-one-function-calls-another-function\/result.png\" alt=\"calls another function\" width=\"400\" class=\"aligncenter size-medium wp-image-338\" srcset=\"https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2013\/12\/how-to-check-if-one-function-calls-another-function\/result.png 813w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2013\/12\/how-to-check-if-one-function-calls-another-function\/result-150x112.png 150w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2013\/12\/how-to-check-if-one-function-calls-another-function\/result-300x224.png 300w\" sizes=\"(max-width: 813px) 100vw, 813px\" \/><\/a><br \/>\nAt this point checking whether function or constructor calls another function is limited to simple LINQ query<\/p>\n<pre lang=\"csharp\">\r\nMethodInvokerCrawler.GetMethods(typeof(FooClass).GetMethod(\"Bar\")).Any(val => val.Name == \"Foo\");\r\n<\/pre>\n<p>Source code for this post can be found <a href=\"https:\/\/github.com\/tpodolak\/Blog\/tree\/master\/MethodCrawler\">here<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>An application which I&#8217;m currently developing has quite complicated authorization system. That is why, we can not use role based authorization, and basically every developer is obliged to call appropriate security check method in every controller action he or she writes. As You probably know it is quite easy to forget about that, therefore I [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,59,58],"tags":[159,202],"class_list":["post-28","post","type-post","status-publish","format-standard","hentry","category-c","category-crawler","category-function","tag-c","tag-crawler"],"_links":{"self":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/28","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/comments?post=28"}],"version-history":[{"count":4,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/28\/revisions"}],"predecessor-version":[{"id":536,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/28\/revisions\/536"}],"wp:attachment":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/media?parent=28"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/categories?post=28"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/tags?post=28"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}