@@ -15,17 +15,14 @@ open Microsoft.CodeAnalysis
1515open Microsoft.CodeAnalysis .MSBuild
1616open Microsoft.CodeAnalysis .Text
1717open Microsoft.Extensions .Logging
18+ open NuGet.Frameworks
1819
19- open CSharpLanguageServer
2020open CSharpLanguageServer.Lsp
2121open CSharpLanguageServer.Logging
22- open CSharpLanguageServer.Util
2322open CSharpLanguageServer.Roslyn .WorkspaceServices
2423
25-
2624let private logger = Logging.getLoggerByName " Roslyn.Solution"
2725
28-
2926let initializeMSBuild () : unit =
3027 let vsInstanceQueryOpt = VisualStudioInstanceQueryOptions.Default
3128 let vsInstanceList = MSBuildLocator.QueryVisualStudioInstances( vsInstanceQueryOpt)
@@ -61,7 +58,6 @@ let initializeMSBuild () : unit =
6158
6259 MSBuildLocator.RegisterInstance( vsInstance)
6360
64-
6561let solutionLoadProjectFilenames ( solutionPath : string ) =
6662 assert Path.IsPathRooted solutionPath
6763 let projectFilenames = new List< string>()
@@ -75,49 +71,6 @@ let solutionLoadProjectFilenames (solutionPath: string) =
7571 projectFilenames |> Set.ofSeq
7672
7773
78- type TfmCategory =
79- | NetFramework of Version
80- | NetStandard of Version
81- | NetCoreApp of Version
82- | Net of Version
83- | Unknown
84-
85-
86- let selectLatestTfm ( tfms : string seq ) : string option =
87- let parseTfm ( tfm : string ) : TfmCategory =
88- let patterns =
89- [ @" ^net(?<major>\d)(?<minor>\d)?(?<build>\d)?$" , NetFramework
90- @" ^netstandard(?<major>\d+)\.(?<minor>\d+)$" , NetStandard
91- @" ^netcoreapp(?<major>\d+)\.(?<minor>\d+)$" , NetCoreApp
92- @" ^net(?<major>\d+)\.(?<minor>\d+)$" , Net ]
93-
94- let matchingTfmCategory ( pat , categoryCtor ) =
95- let m = Regex.Match( tfm.ToLowerInvariant(), pat)
96-
97- if m.Success then
98- let readVersionNum ( groupName : string ) =
99- let group = m.Groups.[ groupName]
100- if group.Success then int group.Value else 0
101-
102- Version( readVersionNum " major" , readVersionNum " minor" , readVersionNum " build" )
103- |> categoryCtor
104- |> Some
105- else
106- None
107-
108- patterns |> List.tryPick matchingTfmCategory |> Option.defaultValue Unknown
109-
110- let rankTfm =
111- function
112- | Net v -> 3000 + v.Major * 10 + v.Minor
113- | NetCoreApp v -> 2000 + v.Major * 10 + v.Minor
114- | NetStandard v -> 1000 + v.Major * 10 + v.Minor
115- | NetFramework v -> 0 + v.Major * 10 + v.Minor
116- | Unknown -> - 1
117-
118- tfms |> Seq.sortByDescending ( parseTfm >> rankTfm) |> Seq.tryHead
119-
120-
12174let loadProjectTfms ( projs : string seq ) : Map < string , list < string >> =
12275 let mutable projectTfms = Map.empty
12376
@@ -156,6 +109,38 @@ let loadProjectTfms (projs: string seq) : Map<string, list<string>> =
156109
157110 projectTfms
158111
112+ let compatibleTfmsOfTwoSets afxs bfxs = seq {
113+ for a in afxs |> Seq.map NuGetFramework.Parse do
114+ for b in bfxs |> Seq.map NuGetFramework.Parse do
115+ if DefaultCompatibilityProvider.Instance.IsCompatible( a, b) then
116+ yield a.GetShortFolderName()
117+ else if DefaultCompatibilityProvider.Instance.IsCompatible( b, a) then
118+ yield b.GetShortFolderName()
119+ }
120+
121+ let compatibleTfmSet ( fxSets : list < Set < string >>) : Set < string > =
122+ match fxSets.Length with
123+ | 0 -> Set.empty
124+ | 1 -> fxSets |> List.head
125+ | _ ->
126+ let firstSet = fxSets |> List.head
127+
128+ fxSets |> List.skip 1 |> Seq.fold compatibleTfmsOfTwoSets firstSet |> Set.ofSeq
129+
130+ let bestTfm ( frameworks : string seq ) : string option =
131+ let frameworks = frameworks |> Seq.map NuGetFramework.Parse |> List.ofSeq
132+
133+ match frameworks with
134+ | [] -> None
135+ | fxes ->
136+ let compatibleWithAllOtherFxes candidate =
137+ fxes
138+ |> Seq.forall ( fun f -> DefaultCompatibilityProvider.Instance.IsCompatible( candidate, f))
139+
140+ fxes
141+ |> Seq.maxBy ( fun fx -> compatibleWithAllOtherFxes fx, fx.HasPlatform, fx.Version)
142+ |> _. GetShortFolderName()
143+ |> Some
159144
160145let applyWorkspaceTargetFrameworkProp ( tfmsPerProject : Map < string , list < string >>) props : Map < string , string > =
161146 let selectedTfm =
@@ -164,14 +149,14 @@ let applyWorkspaceTargetFrameworkProp (tfmsPerProject: Map<string, list<string>>
164149 | _ ->
165150 tfmsPerProject.Values
166151 |> Seq.map Set.ofSeq
167- |> Set.intersectMany
168- |> selectLatestTfm
152+ |> List.ofSeq
153+ |> compatibleTfmSet
154+ |> bestTfm
169155
170156 match selectedTfm with
171157 | Some tfm -> props |> Map.add " TargetFramework" tfm
172158 | None -> props
173159
174-
175160let resolveDefaultWorkspaceProps projs : Map < string , string > =
176161 let tfmsPerProject = loadProjectTfms projs
177162
@@ -188,7 +173,6 @@ let solutionGetProjectForPath (solution: Solution) (filePath: string) : Project
188173
189174 solution.Projects |> Seq.filter fileOnProjectDir |> Seq.tryHead
190175
191-
192176let solutionTryAddDocument ( docFilePath : string ) ( text : string ) ( solution : Solution ) : Async < Document option > = async {
193177 let projectOnPath = solutionGetProjectForPath solution docFilePath
194178
@@ -211,7 +195,6 @@ let solutionTryAddDocument (docFilePath: string) (text: string) (solution: Solut
211195 return newDocumentMaybe
212196}
213197
214-
215198let selectPreferredSolution ( slnFiles : string list ) : option < string > =
216199 let getProjectCount ( slnPath : string ) =
217200 try
@@ -229,7 +212,6 @@ let selectPreferredSolution (slnFiles: string list) : option<string> =
229212 |> Seq.map snd
230213 |> Seq.tryHead
231214
232-
233215let solutionTryLoadOnPath ( lspClient : ILspClient ) ( solutionPath : string ) =
234216 assert Path.IsPathRooted solutionPath
235217 let progress = ProgressReporter lspClient
@@ -282,7 +264,6 @@ let solutionTryLoadOnPath (lspClient: ILspClient) (solutionPath: string) =
282264 return None
283265 }
284266
285-
286267let solutionTryLoadFromProjectFiles ( lspClient : ILspClient ) ( logMessage : string -> Async < unit >) ( projs : string list ) =
287268 let progress = ProgressReporter lspClient
288269
@@ -324,7 +305,6 @@ let solutionTryLoadFromProjectFiles (lspClient: ILspClient) (logMessage: string
324305 return Some msbuildWorkspace.CurrentSolution
325306 }
326307
327-
328308let solutionFindAndLoadOnDir ( lspClient : ILspClient ) dir = async {
329309 let fileNotOnNodeModules ( filename : string ) =
330310 filename.Split Path.DirectorySeparatorChar |> Seq.contains " node_modules" |> not
@@ -374,7 +354,6 @@ let solutionFindAndLoadOnDir (lspClient: ILspClient) dir = async {
374354 | Some solutionPath -> return ! solutionTryLoadOnPath lspClient solutionPath
375355}
376356
377-
378357let solutionLoadSolutionWithPathOrOnCwd ( lspClient : ILspClient ) ( solutionPathMaybe : string option ) ( cwd : string ) =
379358 match solutionPathMaybe with
380359 | Some solutionPath -> async {
0 commit comments