Skip to content

Instantly share code, notes, and snippets.

@JoshVarty
Created April 21, 2016 08:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoshVarty/7c65709a197de3babedf8ebdd331fbb4 to your computer and use it in GitHub Desktop.
Save JoshVarty/7c65709a197de3babedf8ebdd331fbb4 to your computer and use it in GitHub Desktop.
static void FullWal()
{
string sourceText_1 = @"
using System;
using System.Threading.Tasks;
class C
{
public static void F() { Console.WriteLine(""Original Text""); }
public static void Main() { F(); Console.ReadLine(); }
}";
string sourceText_2 = @"
using System;
using System.Threading.Tasks;
class C
{
public static void F() { Console.WriteLine(123456789); }
public static void Main() { F(); Console.ReadLine(); }
}";
string programName = "MyProgram.exe";
string pdbName = "MyProgram.pdb";
//Get solution
Solution solution = createSolution(sourceText_1);
//Get compilation
var compilation = solution.Projects.Single().GetCompilationAsync().Result;
//Emit .exe. and .pdb to disk
var emitResult = compilation.Emit(programName, pdbName);
if (!emitResult.Success)
{
throw new InvalidOperationException("Errors in compilation: " + emitResult.Diagnostics.Count());
}
//Build the EmitBaseline
var metadataModule = ModuleMetadata.CreateFromFile(programName);
var fs = new FileStream(pdbName, FileMode.Open);
var emitBaseline = EmitBaseline.CreateInitialBaseline(metadataModule, SymReaderFactory.CreateReader(fs).GetEncMethodDebugInfo);
//Take solution, change it and compile it
var document = solution.Projects.Single().Documents.Single();
var updatedDocument = document.WithText(SourceText.From(sourceText_2, System.Text.Encoding.UTF8));
var newCompilation = updatedDocument.Project.GetCompilationAsync().Result;
//Get semantic edits with Reflection + CSharpEditAndContinueAnalyzer
IEnumerable<SemanticEdit> semanticEdits = GetSemanticEdits(solution, updatedDocument);
//Apply metadat/IL deltas
var metadataStream = new MemoryStream();
var ilStream = new MemoryStream();
var newPdbStream = new MemoryStream();
var updatedMethods = new List<System.Reflection.Metadata.MethodDefinitionHandle>();
var newEmitResult = newCompilation.EmitDifference(emitBaseline, semanticEdits, metadataStream, ilStream, newPdbStream, updatedMethods);
}
private static IEnumerable<SemanticEdit> GetSemanticEdits(Solution originalSolution, Document updatedDocument, CancellationToken token = default(CancellationToken))
{
//Load our CSharpAnalyzer and ActiveStatementSpan types via reflection
Type csharpEditAndContinueAnalyzerType = Type.GetType("Microsoft.CodeAnalysis.CSharp.EditAndContinue.CSharpEditAndContinueAnalyzer, Microsoft.CodeAnalysis.CSharp.Features");
Type activeStatementSpanType = Type.GetType("Microsoft.CodeAnalysis.EditAndContinue.ActiveStatementSpan, Microsoft.CodeAnalysis.Features");
dynamic csharpEditAndContinueAnalyzer = Activator.CreateInstance(csharpEditAndContinueAnalyzerType, nonPublic: true);
var bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
Type[] targetParams = new Type[] { };
//Create an empty ImmutableArray<ActiveStatementSpan> because we're not currently running the code
var immutableArray_Create_T = typeof(ImmutableArray).GetMethod("Create", bindingFlags, binder: null, types: targetParams, modifiers: null);
var immutableArray_Create_ActiveStatementSpan = immutableArray_Create_T.MakeGenericMethod(activeStatementSpanType);
var immutableArray_ActiveStatementSpan = immutableArray_Create_ActiveStatementSpan.Invoke(null, new object[] { });
var method = (MethodInfo)csharpEditAndContinueAnalyzer.GetType().GetMethod("AnalyzeDocumentAsync");
var myParams = new object[] { originalSolution, immutableArray_ActiveStatementSpan, updatedDocument, token };
object task = method.Invoke(csharpEditAndContinueAnalyzer, myParams);
var documentAnalysisResults = task.GetType().GetProperty("Result").GetValue(task);
//Get the semantic edits from DocumentAnalysisResults
var edits = (IEnumerable<SemanticEdit>)documentAnalysisResults.GetType().GetField("SemanticEdits", bindingFlags).GetValue(documentAnalysisResults);
return edits;
}
private static Solution createSolution(string text)
{
var tree = CSharpSyntaxTree.ParseText(text);
var mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
var adHockWorkspace = new AdhocWorkspace();
var options = new CSharpCompilationOptions(OutputKind.ConsoleApplication, platform: Platform.X86);
var project = adHockWorkspace.AddProject(ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Default, "MyProject", "MyProject", "C#", metadataReferences: new List<MetadataReference>() { mscorlib }, compilationOptions: options));
adHockWorkspace.AddDocument(project.Id, "MyDocument.cs", SourceText.From(text, System.Text.UTF8Encoding.UTF8));
return adHockWorkspace.CurrentSolution;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment