Created
April 21, 2016 08:38
-
-
Save JoshVarty/7c65709a197de3babedf8ebdd331fbb4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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