11using System ;
22using System . IO ;
33using System . IO . Compression ;
4+ using System . Reflection ;
45using UnityEditor ;
56using UnityEngine ;
67using UnityEngine . Networking ;
@@ -13,19 +14,44 @@ public static class RoslynInstaller
1314
1415 private static readonly ( string packageId , string version , string dllPath , string dllName ) [ ] NuGetEntries =
1516 {
16- ( "microsoft.codeanalysis.common" , "4.12.0" , "lib/netstandard2.0/Microsoft.CodeAnalysis.dll" , "Microsoft.CodeAnalysis.dll" ) ,
17- ( "microsoft.codeanalysis.csharp" , "4.12.0" , "lib/netstandard2.0/Microsoft.CodeAnalysis.CSharp.dll" , "Microsoft.CodeAnalysis.CSharp.dll" ) ,
18- ( "system.collections.immutable" , "8.0.0" , "lib/netstandard2.0/System.Collections.Immutable.dll" , "System.Collections.Immutable.dll" ) ,
19- ( "system.reflection.metadata" , "8.0.0" , "lib/netstandard2.0/System.Reflection.Metadata.dll" , "System.Reflection.Metadata.dll" ) ,
17+ ( "microsoft.codeanalysis.common" , "4.12.0" , "lib/netstandard2.0/Microsoft.CodeAnalysis.dll" , "Microsoft.CodeAnalysis.dll" ) ,
18+ ( "microsoft.codeanalysis.csharp" , "4.12.0" , "lib/netstandard2.0/Microsoft.CodeAnalysis.CSharp.dll" , "Microsoft.CodeAnalysis.CSharp.dll" ) ,
19+ ( "system.collections.immutable" , "8.0.0" , "lib/netstandard2.0/System.Collections.Immutable.dll" , "System.Collections.Immutable.dll" ) ,
20+ ( "system.reflection.metadata" , "8.0.0" , "lib/netstandard2.0/System.Reflection.Metadata.dll" , "System.Reflection.Metadata.dll" ) ,
21+ // Transitive dep of Microsoft.CodeAnalysis.* on netstandard2.0. Without it, Roslyn's StringTable
22+ // static cctor throws FileNotFoundException for v6.0.0.0 and every Roslyn entry point fails to
23+ // initialize. Unity ships a v4.x of this assembly which does NOT satisfy the v6 reference.
24+ ( "system.runtime.compilerservices.unsafe" , "6.0.0" , "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll" , "System.Runtime.CompilerServices.Unsafe.dll" ) ,
2025 } ;
2126
2227 public static bool IsInstalled ( )
2328 {
2429 string folder = Path . Combine ( Application . dataPath , PluginsRelPath ) ;
2530 foreach ( var entry in NuGetEntries )
2631 {
27- if ( ! File . Exists ( Path . Combine ( folder , entry . dllName ) ) )
32+ string path = Path . Combine ( folder , entry . dllName ) ;
33+ if ( ! File . Exists ( path ) )
2834 return false ;
35+
36+ // Defense-in-depth: a stale DLL whose assembly version is older than what
37+ // Roslyn references (e.g. a v4.x System.Runtime.CompilerServices.Unsafe
38+ // shadowing the v6 we actually need) would still satisfy file-existence but
39+ // leave Roslyn unable to load. Compare the on-disk assembly version against
40+ // each entry's declared NuGet version, treating "older or unreadable" as not
41+ // installed so Install() can rewrite it.
42+ if ( Version . TryParse ( entry . version , out var requiredVersion ) )
43+ {
44+ try
45+ {
46+ var actual = AssemblyName . GetAssemblyName ( path ) . Version ;
47+ if ( actual == null || actual < requiredVersion )
48+ return false ;
49+ }
50+ catch
51+ {
52+ return false ;
53+ }
54+ }
2955 }
3056 return true ;
3157 }
0 commit comments