Here's a quick and dirty way to do what you want. It is based on one of the comments above, which points to SebbyLive . This is just a proof of concept, I would not try to use it in production.
The main idea is that you change the compiler of the project you want to change. And this modified compiler will inject the code. Therefore, you will need to write a new compiler (AopCompiler.exe) and install it as a building tool in your project.
Installing AopCompiler.exe as a build tool is easy, in the project file you need to add the following two lines:
<CscToolPath>$(SolutionDir)AopCompiler\bin\Debug</CscToolPath> <CscToolExe>AopCompiler.exe</CscToolExe>
AopCompiler should be a simple console application. It also does code modification and compilation. If you do not want to change the source code, just create it, then the easiest way is to call csc.exe yourself:
static void Main(string[] args) { var p = Process.Start(@"C:\Program Files (x86)\MSBuild\14.0\Bin\csc.exe", string.Join(" ", args)); p.WaitForExit(); }
So, if you install this so far, you will have a normal build process, without testing.
At this point, if you look at what is in args , you will see that there is a path to the .RSP file that contains all the command line options for csc.exe. Naturally, these options contain all .CS file names. Thus, you can parse this .RSP file and find all .CS files that are part of the compilation.
Using C # files, rewriting can be done using Roslyn. CSharpSyntaxRewriter has many tutorials, like here and here . You will need to write your own CSharpSyntaxRewriter , which checks this attribute, and then adds the entry to the beginning of the methods found. Adding a log to the end of each method is a bit more complicated because there can be multiple exit points. To find them, you can use control flow analysis. Roslyn's built-in flow analysis can give you exactly what you need; the ExitPoints property contains a set of operators within a region that go to locations outside the region.
To get a semantic model (and then do CFG analysis), you can do something like this:
public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node) { var semanticModel = _compilation.GetSemanticModel(node.SyntaxTree);
Finally, to process each of the input files, your AopCompiler, you just need to call the rewriter Visit method in the root of the tree. This will create a modified tree that you can write to the file. (Or you can change the source file, or write the result to a new one, and change the .RSP file accordingly.)
Sorry for the lack of a complete working solution, but I hope this is enough to get you started.