Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
340 commits
Select commit Hold shift + click to select a range
bac019e
Merge remote-tracking branch 'upstream/main' into useExtension
CyrusNajmabadi Jul 25, 2025
0ccbf92
Merge remote-tracking branch 'jjonescz/analyzers-version' into useExt…
CyrusNajmabadi Jul 25, 2025
9e774a8
Remove NetAnalyzers version override
jjonescz Jul 25, 2025
7b6d22d
Fix eol handling on the last token in a file when formatting code act…
CyrusNajmabadi Jul 25, 2025
44f1d20
Put back dotnet8 feed
jjonescz Jul 25, 2025
c18e69e
Fix analyzer violations
jjonescz Jul 25, 2025
f2e3e52
Add diagnostic provider for clients without dynamic registration (#77…
dibarbet Jul 25, 2025
71f0622
Address more analyzer violations
jjonescz Jul 25, 2025
f7d5eaa
Revert breaking fixes
jjonescz Jul 25, 2025
a21ed3c
Address more analyzer violations
jjonescz Jul 25, 2025
48a204e
Fix Xaml MEF import
tmat Jul 25, 2025
d834a2e
Fix Xaml MEF import (#79616)
dibarbet Jul 25, 2025
76030c5
Generate semantic search ref assemblies package
genlu Jul 25, 2025
b17682a
Change the delay for how often we synchronize solutions
jasonmalinowski Jul 24, 2025
2e1adee
Update dependencies from https://github.com/dotnet/dotnet build 276797
dotnet-maestro[bot] Jul 26, 2025
33fde18
PR feedback
davidwengier Jul 26, 2025
5d41fd9
Update dependencies from https://github.com/dotnet/dotnet build 276828
dotnet-maestro[bot] Jul 27, 2025
dc2b6c4
Use Append overload for repeating chars
slang25 Jul 27, 2025
0b126f8
Fix formatting of CDATA sections in quick info
CyrusNajmabadi Jul 28, 2025
c67cd6a
Fix
CyrusNajmabadi Jul 28, 2025
5a07425
Fix
CyrusNajmabadi Jul 28, 2025
620fb3a
Handle concurrent requests to update workspace contents and workspace…
CyrusNajmabadi Jul 28, 2025
0dbae8b
Fallout
CyrusNajmabadi Jul 28, 2025
15633cd
Add test
CyrusNajmabadi Jul 28, 2025
1b9cf50
Apply suggestions from code review
CyrusNajmabadi Jul 28, 2025
7d3b2ef
Docs
CyrusNajmabadi Jul 28, 2025
6446625
Docs
CyrusNajmabadi Jul 28, 2025
c3a6ffe
Produce a better return type when trying to return an anonymous type …
CyrusNajmabadi Jul 28, 2025
9b3cf24
Fix test
CyrusNajmabadi Jul 28, 2025
0ff7f8f
Generate semantic search ref assemblies package (#79618)
genlu Jul 28, 2025
28aa933
Fix formatting of CDATA sections in quick info (#79627)
CyrusNajmabadi Jul 28, 2025
3cefbb3
Use modern extension (#79550)
CyrusNajmabadi Jul 28, 2025
c510ecf
Fix issue with source generator diagnostics not refreshing on save in…
dibarbet Jul 28, 2025
de03b4e
Don't use a pool in SemanticTokensHelper.ComputeTokens (#79622)
ToddGrun Jul 28, 2025
e768aef
Refine Caching example (#79593)
yangrongwei Jul 28, 2025
5f10df9
Produce a better return type when trying to return an anonymous type …
CyrusNajmabadi Jul 28, 2025
a1aac3d
Add reference assemblies dir parameter (#79614)
tmat Jul 28, 2025
7074a21
Update Microsoft.ILVerification (#79555)
tmat Jul 28, 2025
dade052
Reduce allocations in CSharpVirtualCharService.TryConvertStringToVirt…
ToddGrun Jul 28, 2025
3dd0eb1
modified tagged text instead to resolve LSP issues
Fanominals Jul 28, 2025
6b52b0f
Remove unnecessary methods from interface
CyrusNajmabadi Jul 28, 2025
aa21fbd
Move logic into helper
CyrusNajmabadi Jul 28, 2025
a702b32
Better handle quick info for code with suppressions in it
CyrusNajmabadi Jul 28, 2025
2525c87
Remove UI thread use of UIContext (#79347)
jasonmalinowski Jul 28, 2025
6a91963
Simplify
CyrusNajmabadi Jul 28, 2025
992531b
Revert
CyrusNajmabadi Jul 28, 2025
723d6e9
Simplify
CyrusNajmabadi Jul 28, 2025
daa7042
fix diff
CyrusNajmabadi Jul 28, 2025
3753829
Use Append overload for repeating chars (#79626)
jasonmalinowski Jul 28, 2025
d6febbb
Merge branch 'main' into dev/t-gosingh/fix-list-items
Fanominals Jul 28, 2025
bbdb137
restore optionality
CyrusNajmabadi Jul 28, 2025
a461c84
Rename Razor source generated documents in all scenarios, and map edi…
davidwengier Jul 28, 2025
e8bbb65
Remove unnecessary feed (#79635)
tmat Jul 28, 2025
8fefbab
Remove most remaining workspace changed on UI thread (#79391)
jasonmalinowski Jul 28, 2025
c60bed9
Reduce some UI thread blocking
jasonmalinowski Jul 28, 2025
2736f00
Fixup quick info for suppressed nullable operations. (#79636)
CyrusNajmabadi Jul 28, 2025
b9de0ca
Pass in referenceAssembliesDir to ISemanticSearchSolutionService
genlu Jul 28, 2025
58989aa
reverted tests back to main
Fanominals Jul 29, 2025
ea81bdd
[main] Source code updates from dotnet/dotnet (#79620)
dibarbet Jul 29, 2025
afaf319
File-based program directive diagnostics in editor (#79421)
RikkiGibson Jul 29, 2025
8edc5e4
Sign contents of nupkg, but not the nupkg itself
dibarbet Jul 28, 2025
0721c3b
Pull publishdata from the branch being published
JoeRobich Jul 29, 2025
0ec994d
Update dependencies from https://github.com/dotnet/dotnet build 27698…
dotnet-maestro[bot] Jul 29, 2025
8d5a625
Incorporated PR feedback
JoeRobich Jul 29, 2025
a5ab93c
Show nullability of a local variable when hovering on the decl of it
CyrusNajmabadi Jul 29, 2025
28082bb
Add tests
CyrusNajmabadi Jul 29, 2025
06040f9
Add more var cases
CyrusNajmabadi Jul 29, 2025
24f4d16
Add work items
CyrusNajmabadi Jul 29, 2025
d2ef1fc
Docs
CyrusNajmabadi Jul 29, 2025
99a0f26
Share code
CyrusNajmabadi Jul 29, 2025
fecd080
nrt
CyrusNajmabadi Jul 29, 2025
2693539
Improve QuickInfo NRT info in the presence of nullability altering ch…
CyrusNajmabadi Jul 29, 2025
df94463
Simplify
CyrusNajmabadi Jul 29, 2025
d2c9ced
Simplify
CyrusNajmabadi Jul 29, 2025
16bbbff
Merge branch 'qiNullability' into nullabilityChecks
CyrusNajmabadi Jul 29, 2025
68e8c08
Simplify
CyrusNajmabadi Jul 29, 2025
f7231ee
Simplify
CyrusNajmabadi Jul 29, 2025
ff4d992
Show nullability of a local variable when hovering on the decl of it …
CyrusNajmabadi Jul 29, 2025
dac70e5
Merge branch 'main' into nullabilityChecks
CyrusNajmabadi Jul 29, 2025
c9d73ce
Add test cases
CyrusNajmabadi Jul 29, 2025
a852d51
Update src/Workspaces/Core/Portable/Workspace/Solution/SourceGenerato…
CyrusNajmabadi Jul 29, 2025
959edbb
Add tests
CyrusNajmabadi Jul 29, 2025
ed6ea96
Add tests
CyrusNajmabadi Jul 29, 2025
062eb47
Restore name
CyrusNajmabadi Jul 29, 2025
baffdc1
Improve QuickInfo NRT info in the presence of nullability altering ch…
CyrusNajmabadi Jul 29, 2025
f51bf07
Pass in referenceAssembliesDir to ISemanticSearchSolutionService (#79…
genlu Jul 29, 2025
6130770
Make nupkg signing exclusion conditional
dibarbet Jul 29, 2025
d55947d
Merge remote-tracking branch 'upstream/main' into sgMerging
CyrusNajmabadi Jul 29, 2025
6ad21c4
Fix logging when item counts change in LoadedProject (#79640)
RikkiGibson Jul 29, 2025
bf09940
Use checksum
CyrusNajmabadi Jul 29, 2025
9c8839d
Add lsp tests
CyrusNajmabadi Jul 29, 2025
72013e9
remove testing branch name
dibarbet Jul 29, 2025
38ae6df
reverted tests back to main
Fanominals Jul 29, 2025
162378e
Add comment for nuget package behavior
dibarbet Jul 29, 2025
c7752a0
Merge branch 'dev/t-gosingh/fix-list-items' of https://github.com/dot…
Fanominals Jul 29, 2025
518743b
Trap on-the-fly-doc exceptions in quick info
CyrusNajmabadi Jul 29, 2025
bd78a4e
Cleanup
CyrusNajmabadi Jul 29, 2025
cfce783
Update debugger.contracts to 18.0.0-beta.25379.1 (#79661)
tmat Jul 29, 2025
ba16c3b
Catch more
CyrusNajmabadi Jul 29, 2025
1a64b30
Catch more
CyrusNajmabadi Jul 29, 2025
53b8ac3
Trap on-the-fly-doc exceptions in quick info (#79668)
CyrusNajmabadi Jul 29, 2025
f837b59
Tweak map spans API to match document service, and call it
davidwengier Jul 30, 2025
b103032
Enable View -> Stack Trace Explorer by default
davkean Jul 30, 2025
f34c21a
Strongly type the mapping API, and allow Razor to check generator typ…
davidwengier Jul 30, 2025
d78966a
argh don't wanna talk about it
davidwengier Jul 30, 2025
d771134
Enable View -> Stack Trace Explorer by default (#79676)
CyrusNajmabadi Jul 30, 2025
145146d
Delete unused quick info code
CyrusNajmabadi Jul 30, 2025
d1fd8f0
Merge remote-tracking branch 'upstream/main' into deleteCode
CyrusNajmabadi Jul 30, 2025
75b1d2f
SelectAsArray
CyrusNajmabadi Jul 30, 2025
dd8ea14
Recognize known `ToString` methods inside interpolation
DoctorKrolic Jul 30, 2025
dabadc1
Fix extension-method add-import completion in syntactically ambiguous…
CyrusNajmabadi Jul 30, 2025
3ae4616
Docs
CyrusNajmabadi Jul 30, 2025
cfdb92a
Delete unused quick info code (#79680)
CyrusNajmabadi Jul 30, 2025
1bdda21
`comp` -> `compilation`
DoctorKrolic Jul 30, 2025
a67d969
Use pooled builder
DoctorKrolic Jul 30, 2025
759986d
Update src/Analyzers/Core/Analyzers/SimplifyInterpolation/AbstractSim…
DoctorKrolic Jul 30, 2025
87f12de
Update src/Analyzers/Core/Analyzers/SimplifyInterpolation/AbstractSim…
DoctorKrolic Jul 30, 2025
0e83a43
Check for `static` just in case
DoctorKrolic Jul 30, 2025
a6e4b68
Paranoia :)
DoctorKrolic Jul 30, 2025
0eb1369
Sort
CyrusNajmabadi Jul 30, 2025
0a88d90
Fix spelling
CyrusNajmabadi Jul 30, 2025
ee2691a
Fix extension-method add-import completion in syntactically ambiguous…
CyrusNajmabadi Jul 30, 2025
bfcea7c
Recognize known `ToString` methods inside interpolation (#79682)
CyrusNajmabadi Jul 30, 2025
0a3eba2
Merge remote-tracking branch 'upstream/main' into sgMerging
CyrusNajmabadi Jul 30, 2025
a272b5a
remove unnecessary code
CyrusNajmabadi Jul 30, 2025
80ed2f2
Allow PR val build insertion step to be re-run
dibarbet Jul 29, 2025
1b03f37
Simplify
CyrusNajmabadi Jul 30, 2025
78b4641
Spelling
CyrusNajmabadi Jul 30, 2025
3da0a85
Move tests
CyrusNajmabadi Jul 30, 2025
cc8dd5f
Remove
CyrusNajmabadi Jul 30, 2025
cb9aec5
Add back
CyrusNajmabadi Jul 30, 2025
82e46f3
Too many type name collisions in Razor tests
davidwengier Jul 30, 2025
3e0d00e
Revert "Move methods back to a place where TypeScript can reference t…
tmat Jul 30, 2025
0ea0f59
Fix Call Hierarchy false positives by filtering non-reference contexts
Fanominals Jul 23, 2025
0924e8d
test
Fanominals Jul 23, 2025
a091cee
added typeof filtering
Fanominals Jul 23, 2025
adf6d69
fix call hierarchy false positives by filtering out nameof and typeof…
Fanominals Jul 24, 2025
074a716
used ReferenceLocation for nameof and typeof detection
Fanominals Jul 28, 2025
1885d2f
added space as per CR
Fanominals Jul 29, 2025
cea89b6
wip tests
Fanominals Jul 30, 2025
f9090f4
Handle concurrent requests to update workspace contents and workspace…
CyrusNajmabadi Jul 30, 2025
c5150d5
Simplify determination of live vs. build diagnostics
dibarbet Jul 30, 2025
efe5faf
Razor span mapping in LSP for cohosting (#79677)
davidwengier Jul 30, 2025
ce4070b
Add Copilot.EA IVT
genlu Jul 31, 2025
d03d012
walk up functionality + nameof tests for call hierarchy
Fanominals Jul 31, 2025
1a2e3de
formatting issues
Fanominals Jul 31, 2025
3073df4
Allow PR val build insertion step to be re-run (#79666)
dibarbet Jul 31, 2025
a04b791
Add Copilot.EA IVT (#79692)
genlu Jul 31, 2025
3bd3f0c
Extract helper method
davidwengier Jul 31, 2025
5cc8101
Use span mapping in codelens
davidwengier Jul 31, 2025
84dbe08
Use span mapping in naviation
davidwengier Jul 31, 2025
ecd007e
Use span mapping in FAR
davidwengier Jul 31, 2025
b10ed1a
Fix spelling mistakes in tests. (#79687)
CyrusNajmabadi Jul 31, 2025
981ac6e
VB: EmitDelegateCreation - account for the fact that static methods c…
AlekseyTs Jul 31, 2025
15f46ce
Update based on review feedback
dibarbet Jul 31, 2025
c640e34
Update src/Compilers/Core/Portable/Diagnostic/WellKnownDiagnosticTags.cs
dibarbet Jul 31, 2025
6c405e8
defer tail slicing for efficiency
Fanominals Jul 31, 2025
0be066d
Remove untriaged label automation (#79701)
jaredpar Jul 31, 2025
9a48772
Simplify determination of live vs. build diagnostics (#79691)
dibarbet Jul 31, 2025
42af164
test member access read/write not affected by walkup
Fanominals Jul 31, 2025
77f4f8e
removed commented out test
Fanominals Jul 31, 2025
ec9aca1
Extensions: address instrumentation follow-ups (#79557)
Jul 31, 2025
92e0cf8
Move extension to helper class. Extensions on Document seemed a bit b…
davidwengier Aug 1, 2025
5b1b075
Remove a hack, and clarify another
davidwengier Aug 1, 2025
ee26fb8
Fix tests
davidwengier Aug 1, 2025
6f3fa21
Allow more lifecycle events in Razor cohosting
davidwengier Aug 1, 2025
1072c37
Fix formatting in use-auto-prop when attributes are present
CyrusNajmabadi Aug 1, 2025
11bb487
Move 'use auto prop' into code style layer
CyrusNajmabadi Aug 1, 2025
c142c3e
In progress
CyrusNajmabadi Aug 1, 2025
e308cb1
Move fix all helpers to shared location so that CodeStyle can referen…
CyrusNajmabadi Aug 1, 2025
5917ecf
Merge branch 'sharedFixAllCode' into codeStyleAutoProp
CyrusNajmabadi Aug 1, 2025
f11587d
IN progress
CyrusNajmabadi Aug 1, 2025
adbf6d6
in progress
CyrusNajmabadi Aug 1, 2025
d894c5b
Share more code
CyrusNajmabadi Aug 1, 2025
7dfd249
wip
CyrusNajmabadi Aug 1, 2025
99589b5
Working
CyrusNajmabadi Aug 1, 2025
ad58643
Simplify
CyrusNajmabadi Aug 1, 2025
fc530a7
Simplify
CyrusNajmabadi Aug 1, 2025
09a467f
Remove hacks
CyrusNajmabadi Aug 1, 2025
8c4a56d
Simplify
CyrusNajmabadi Aug 1, 2025
96ddfb3
Fix formatting in use-auto-prop when attributes are present (#79735)
CyrusNajmabadi Aug 1, 2025
bb47eaf
Add assert
CyrusNajmabadi Aug 1, 2025
1ef3f58
move service into shared location
CyrusNajmabadi Aug 1, 2025
f9715b2
Move fix all helpers to shared location so that CodeStyle can referen…
CyrusNajmabadi Aug 1, 2025
4ac37dd
Revert "Pull publishdata from the branch being published"
dibarbet Aug 1, 2025
814dd21
Merge branch 'main' into codeStyleAutoProp
CyrusNajmabadi Aug 1, 2025
257ee96
Move 'use auto prop' to code style layer. (#79737)
CyrusNajmabadi Aug 1, 2025
160f268
In PR validation, test sign contents of nupkg, but not the nupkg itse…
dibarbet Aug 1, 2025
8885c5c
helper method + formatting issues fix
Fanominals Aug 1, 2025
2f7c79b
merge conficts
Fanominals Aug 1, 2025
7686e68
made helper method into local method
Fanominals Aug 1, 2025
a6b4e7f
Add Copilot semantic search (#79673)
tmat Aug 2, 2025
a35df84
Add null check
JoeRobich Aug 2, 2025
69d3f98
Semantic search updates (#79742)
tmat Aug 2, 2025
0ac6929
Introduce helper to ensure span mapping is consistent everywhere (#79…
davidwengier Aug 2, 2025
8faa318
Better Razor cohosting lifecycle management (#79731)
davidwengier Aug 2, 2025
8db717b
[main] Source code updates from dotnet/dotnet (#79744)
dotnet-maestro[bot] Aug 4, 2025
ecc165b
Reduce some UI thread blocking (#79642)
jasonmalinowski Aug 4, 2025
f4c1858
Fixed irregular spacing between list items (#79388)
Fanominals Aug 4, 2025
24615d1
Refactor how TestWorkspaces interact with TestCompositions
jasonmalinowski Aug 1, 2025
99dcf19
Allow our LanguageServer tests to use Protocol.Test.Utilities
jasonmalinowski Aug 1, 2025
95b45e7
Run our LSP Miscellaneous Files tests against both implementations
jasonmalinowski Aug 1, 2025
9593910
Consolidate and unify the miscellaneous files tests more
jasonmalinowski Aug 1, 2025
9ae7e86
Fix file-based programs getting stuck in the host workspace
jasonmalinowski Aug 2, 2025
5e630a7
fix formatting issues
Fanominals Aug 4, 2025
aa440be
Fix file-based programs getting stuck in the host workspace (#79730)
jasonmalinowski Aug 4, 2025
ba365fa
Tests to ensure everything is hooked up
davidwengier Aug 4, 2025
e874683
Apply suggestions from code review
Fanominals Aug 4, 2025
d264f99
Allow Razor to control the lifetime of caches, rather than using statics
davidwengier Aug 5, 2025
97d8661
Don't know how that happened
davidwengier Aug 5, 2025
8de303b
Allow Razor to control the lifetime of caches, rather than using stat…
davidwengier Aug 5, 2025
f0ec750
Add a few tests to ensure Razor span mapping is hooked up (#79771)
davidwengier Aug 5, 2025
fda7045
use SelectAsArray
CyrusNajmabadi Aug 5, 2025
1d162fe
Where+Select
CyrusNajmabadi Aug 5, 2025
ed8dfdd
Use WhereAsArray
CyrusNajmabadi Aug 5, 2025
14ab013
Add docs
CyrusNajmabadi Aug 5, 2025
04ce44d
rename
CyrusNajmabadi Aug 5, 2025
ac5786a
Formatting
CyrusNajmabadi Aug 5, 2025
113f868
Simplify
CyrusNajmabadi Aug 5, 2025
6f485a4
Remove lazy enumerables
CyrusNajmabadi Aug 5, 2025
cc44e56
Delete unused functin
CyrusNajmabadi Aug 5, 2025
1fdacdd
Fix crash when generating explicit impl properties
CyrusNajmabadi Aug 5, 2025
f36b19d
Improve error reporting from RemoteInitializationService (#79761)
tmat Aug 5, 2025
109e18a
Fix nameof no longer appear in call hierarchy (#79578)
Fanominals Aug 5, 2025
9c6403e
Locate usable MSBuild when launching .NET Core BuildHost (#79494)
JoeRobich Aug 5, 2025
66b4fd6
Do not report 'no-effect' warning when active top-level code is updat…
tmat Aug 5, 2025
ec2df86
Allow Razor to call into codelens
davidwengier Jul 22, 2025
3c1c906
Make internal
davidwengier Aug 6, 2025
0df51d0
Update dependencies from https://github.com/dotnet/dotnet build 27802…
dotnet-maestro[bot] Aug 6, 2025
93efd6d
Allow Razor to call into codelens (#79795)
davidwengier Aug 6, 2025
fdd0ad9
Simplify code
CyrusNajmabadi Aug 6, 2025
8bb67be
remove comment
CyrusNajmabadi Aug 6, 2025
4a911a9
remove comment
CyrusNajmabadi Aug 6, 2025
bcd70bc
Support getting diagnostic descriptors from OOP
CyrusNajmabadi Aug 6, 2025
9374a90
Simplify
CyrusNajmabadi Aug 6, 2025
465c59f
Formatting
CyrusNajmabadi Aug 6, 2025
1db289b
Has predicate, so don't use count
CyrusNajmabadi Aug 6, 2025
042a013
Named parameters
CyrusNajmabadi Aug 6, 2025
0fd6301
Remove unused test impl of an interface
CyrusNajmabadi Aug 6, 2025
5c8f016
Simplify code that was always using a constant. (#79801)
CyrusNajmabadi Aug 6, 2025
e172459
Fix crash when generating explicit impl properties (#79780)
CyrusNajmabadi Aug 6, 2025
c43ef64
Merge remote-tracking branch 'upstream/main' into oopDiagnosticDescri…
CyrusNajmabadi Aug 6, 2025
d78da37
Cleanup
CyrusNajmabadi Aug 6, 2025
eaf5c79
Merge branch 'removeTestType' into oopDiagnosticDescriptors
CyrusNajmabadi Aug 6, 2025
f22f4db
Remove unused test impl of an interface (#79811)
CyrusNajmabadi Aug 6, 2025
498e8d3
Compute solution explorer diagnostic descriptors in OOP process. (#79…
CyrusNajmabadi Aug 6, 2025
4524dbf
Use Linq helpers. (#79775)
CyrusNajmabadi Aug 6, 2025
311d7e2
Update dependencies from https://github.com/dotnet/dotnet build 27822…
dotnet-maestro[bot] Aug 7, 2025
f733ba8
Remove lazy enumerables (#79776)
CyrusNajmabadi Aug 7, 2025
c86fcf2
Merge remote-tracking branch 'upstream/main' into merge-main
333fred Aug 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Incorporated PR feedback
- Restored removed BuildHost methods.
- Separated MSBuild instance finding from loading
- Removed loop in favor of a single relaunch
  • Loading branch information
JoeRobich committed Jul 29, 2025
commit 8d5a62574da9d636283eef114f6c66d44003340a
106 changes: 63 additions & 43 deletions src/Workspaces/MSBuild/BuildHost/BuildHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ internal sealed class BuildHost : IBuildHost
private readonly RpcServer _server;
private readonly object _gate = new object();
private ProjectBuildManager? _buildManager;
private MSBuildLocation? _msBuildLocation;

public BuildHost(BuildHostLogger logger, ImmutableDictionary<string, string> globalMSBuildProperties, string? binaryLogPath, RpcServer server)
{
Expand All @@ -33,74 +32,85 @@ public BuildHost(BuildHostLogger logger, ImmutableDictionary<string, string> glo
_server = server;
}

public MSBuildLocation? FindUsableMSBuild(string projectOrSolutionFilePath)
private bool TryEnsureMSBuildLoaded(string projectOrSolutionFilePath)
{
lock (_gate)
{
// If we've already created our MSBuild types, then there's nothing further to do.
if (MSBuildLocator.IsRegistered)
{
return _msBuildLocation;
return true;
}

if (!PlatformInformation.IsRunningOnMono)
var instance = FindMSBuild(projectOrSolutionFilePath, includeUnloadableInstances: false);
if (instance is null)
{
return false;
}

VisualStudioInstance? instance;

#if NETFRAMEWORK
MSBuildLocator.RegisterMSBuildPath(instance.Path);
_logger.LogInformation($"Registered MSBuild {instance.Version} instance at {instance.Path}");
return true;
}
}

// In this case, we're just going to pick the highest VS install on the machine, in case the projects are using some newer
// MSBuild features. Since we don't have something like a global.json we can't really know what the minimum version is.
private MSBuildLocation? FindMSBuild(string projectOrSolutionFilePath, bool includeUnloadableInstances)
{
if (!PlatformInformation.IsRunningOnMono)
{
VisualStudioInstance? instance;

// TODO: we should also check that the managed tools are actually installed
instance = MSBuildLocator.QueryVisualStudioInstances().OrderByDescending(vs => vs.Version).FirstOrDefault();
#if NETFRAMEWORK
// In this case, we're just going to pick the highest VS install on the machine, in case the projects are using some newer
// MSBuild features. Since we don't have something like a global.json we can't really know what the minimum version is.

// TODO: we should also check that the managed tools are actually installed
instance = MSBuildLocator.QueryVisualStudioInstances().OrderByDescending(vs => vs.Version).FirstOrDefault();
#else
// Locate the right SDK for this particular project; MSBuildLocator ensures in this case the first one is the preferred one.
// The includeUnloadableInstance parameter additionally locates SDKs from all installations regardless of whether they are
// loadable by the BuildHost process.
var options = new VisualStudioInstanceQueryOptions
{
DiscoveryTypes = DiscoveryType.DotNetSdk,
WorkingDirectory = Path.GetDirectoryName(projectOrSolutionFilePath),
AllowAllDotnetLocations = includeUnloadableInstances,
AllowAllRuntimeVersions = includeUnloadableInstances,
};

// Locate the right SDK for this particular project; MSBuildLocator ensures in this case the first one is the preferred one.
// TODO: we should pick the appropriate instance back in the main process and just use the one chosen here.
var options = new VisualStudioInstanceQueryOptions { DiscoveryTypes = DiscoveryType.DotNetSdk, WorkingDirectory = Path.GetDirectoryName(projectOrSolutionFilePath), AllowAllDotnetLocations = true, AllowAllRuntimeVersions = true };
instance = MSBuildLocator.QueryVisualStudioInstances(options).FirstOrDefault();

instance = MSBuildLocator.QueryVisualStudioInstances(options).FirstOrDefault();
#endif

if (instance != null)
{
MSBuildLocator.RegisterInstance(instance);
_msBuildLocation = new(instance.MSBuildPath, instance.Version.ToString());
_logger.LogInformation($"Registered MSBuild instance at {instance.MSBuildPath}");
}
else
{
_logger.LogCritical("No compatible MSBuild instance could be found.");
}
}
else
if (instance != null)
{
#if NETFRAMEWORK
return new(instance.MSBuildPath, instance.Version.ToString());
}

// We're running on Mono, but not all Mono installations have a usable MSBuild installation, so let's see if we have one that we can use.
var monoMSBuildDirectory = MonoMSBuildDiscovery.GetMonoMSBuildDirectory();
_logger.LogCritical("No compatible MSBuild instance could be found.");
}
else
{

if (monoMSBuildDirectory != null)
{
MSBuildLocator.RegisterMSBuildPath(monoMSBuildDirectory);
_msBuildLocation = new(monoMSBuildDirectory, MonoMSBuildDiscovery.GetMonoMSBuildVersion());
_logger.LogInformation($"Registered MSBuild instance at {monoMSBuildDirectory}");
}
else
#if NETFRAMEWORK
// We're running on Mono, but not all Mono installations have a usable MSBuild installation, so let's see if we have one that we can use.
var monoMSBuildDirectory = MonoMSBuildDiscovery.GetMonoMSBuildDirectory();
if (monoMSBuildDirectory != null)
{
var monoMSBuildVersion = MonoMSBuildDiscovery.GetMonoMSBuildVersion();
if (monoMSBuildVersion != null)
{
_logger.LogCritical("No Mono MSBuild installation could be found; see https://www.mono-project.com/ for installation instructions.");
return new(monoMSBuildDirectory, monoMSBuildVersion);
}
}

_logger.LogCritical("No Mono MSBuild installation could be found; see https://www.mono-project.com/ for installation instructions.");
#else
_logger.LogCritical("Trying to run the .NET Core BuildHost on Mono is unsupported.");
_logger.LogCritical("Trying to run the .NET Core BuildHost on Mono is unsupported.");
#endif
}

return _msBuildLocation;
}

return null;
}

[MemberNotNull(nameof(_buildManager))]
Expand All @@ -125,9 +135,19 @@ private void CreateBuildManager()
}
}

public MSBuildLocation? FindBestMSBuild(string projectOrSolutionFilePath)
{
return FindMSBuild(projectOrSolutionFilePath, includeUnloadableInstances: true);
}

public bool HasUsableMSBuild(string projectOrSolutionFilePath)
{
return TryEnsureMSBuildLoaded(projectOrSolutionFilePath);
}

private void EnsureMSBuildLoaded(string projectFilePath)
{
Contract.ThrowIfNull(FindUsableMSBuild(projectFilePath), $"We don't have an MSBuild to use; {nameof(FindUsableMSBuild)} should have been called first to check.");
Contract.ThrowIfFalse(TryEnsureMSBuildLoaded(projectFilePath), $"We don't have an MSBuild to use; {nameof(HasUsableMSBuild)} should have been called first to check.");
}

/// <summary>
Expand Down
21 changes: 19 additions & 2 deletions src/Workspaces/MSBuild/BuildHost/Rpc/Contracts/IBuildHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,27 @@ namespace Microsoft.CodeAnalysis.MSBuild;
/// </summary>
internal interface IBuildHost
{
MSBuildLocation? FindUsableMSBuild(string projectOrSolutionFilePath);
/// <summary>
/// Finds the best MSBuild instance installed for loading the given project or solution.
/// </summary>
/// <remarks>
/// This may return MSBuild instances that are not loadable by the BuildHost process.
/// </remarks>
MSBuildLocation? FindBestMSBuild(string projectOrSolutionFilePath);

/// <summary>
/// Determines whether there is a MSBuild instance that is loadable by the BuildHost process.
/// </summary>
/// <remarks>
/// This may return true even if the project or solution require a newer version of MSBuild.
/// </remarks>
bool HasUsableMSBuild(string projectOrSolutionFilePath);

Task<int> LoadProjectFileAsync(string projectFilePath, string languageName, CancellationToken cancellationToken);

/// <summary>Permits loading a project file which only exists in-memory, for example, for file-based program scenarios.</summary>
/// <summary>
/// Permits loading a project file which only exists in-memory, for example, for file-based program scenarios.
/// </summary>
/// <param name="projectFilePath">A path to a project file which may or may not exist on disk. Note that an extension that is known by MSBuild, such as .csproj or .vbproj, should be used here.</param>
/// <param name="projectContent">The project file XML content.</param>
int LoadProject(string projectFilePath, string projectContent, string languageName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,18 @@ namespace Microsoft.CodeAnalysis.MSBuild;
[DataContract]
internal sealed class MSBuildLocation(string path, string version)
{
/// <summary>
/// This is the path to the directory containing the MSBuild binaries.
/// </summary>
/// <remarks>
/// When running on .NET this will be the path to the SDK required for loading projects.
/// </remarks>
[DataMember(Order = 0)]
public string Path { get; } = path;

/// <summary>
/// This is the version of MSBuild at this location.
/// </summary>
[DataMember(Order = 1)]
public string Version { get; } = version;
}
112 changes: 62 additions & 50 deletions src/Workspaces/MSBuild/Core/MSBuild/BuildHostProcessManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ public async Task<RemoteBuildHost> GetBuildHostWithFallbackAsync(string projectF
/// </summary>
public async Task<(RemoteBuildHost buildHost, BuildHostProcessKind actualKind)> GetBuildHostWithFallbackAsync(BuildHostProcessKind buildHostKind, string projectOrSolutionFilePath, CancellationToken cancellationToken)
{
if (buildHostKind == BuildHostProcessKind.Mono && MonoMSBuildDiscovery.GetMonoMSBuildDirectory() == null)
if (buildHostKind == BuildHostProcessKind.Mono && MonoMSBuildDiscovery.GetMonoMSBuildVersion() == null)
{
_logger?.LogWarning($"An installation of Mono could not be found; {projectOrSolutionFilePath} will be loaded with the .NET Core SDK and may encounter errors.");
_logger?.LogWarning($"An installation of Mono MSBuild could not be found; {projectOrSolutionFilePath} will be loaded with the .NET Core SDK and may encounter errors.");
buildHostKind = BuildHostProcessKind.NetCore;
}

Expand All @@ -72,12 +72,11 @@ public async Task<RemoteBuildHost> GetBuildHostWithFallbackAsync(string projectF
// us to discover VS instances in .NET Framework hosts right now.
if (buildHostKind == BuildHostProcessKind.NetFramework)
{
var msbuildLocation = await buildHost.FindUsableMSBuildAsync(projectOrSolutionFilePath, cancellationToken).ConfigureAwait(false);
if (msbuildLocation is null)
if (!await buildHost.HasUsableMSBuildAsync(projectOrSolutionFilePath, cancellationToken).ConfigureAwait(false))
{
// It's not usable, so we'll fall back to the .NET Core one.
_logger?.LogWarning($"An installation of Visual Studio or the Build Tools for Visual Studio could not be found; {projectOrSolutionFilePath} will be loaded with the .NET Core SDK and may encounter errors.");
return await GetBuildHostWithFallbackAsync(BuildHostProcessKind.NetCore, projectOrSolutionFilePath, cancellationToken).ConfigureAwait(false);
return (await GetBuildHostAsync(BuildHostProcessKind.NetCore, projectOrSolutionFilePath, dotnetPath: null, cancellationToken).ConfigureAwait(false), BuildHostProcessKind.NetCore);
}
}

Expand All @@ -95,60 +94,73 @@ public async Task<RemoteBuildHost> GetBuildHostAsync(BuildHostProcessKind buildH
{
if (!_processes.TryGetValue(buildHostKind, out var buildHostProcess))
{
bool reload;
do
{
reload = false;

var pipeName = Guid.NewGuid().ToString();
var processStartInfo = CreateBuildHostStartInfo(buildHostKind, pipeName, dotnetPath);

var process = Process.Start(processStartInfo);
Contract.ThrowIfNull(process, "Process.Start failed to launch a process.");

buildHostProcess = new BuildHostProcess(process, pipeName, _loggerFactory);
buildHostProcess.Disconnected += BuildHostProcess_Disconnected;

// We've subscribed to Disconnected, but if the process crashed before that point we might have not seen it
if (process.HasExited)
{
buildHostProcess.LogProcessFailure();
throw new Exception($"BuildHost process exited immediately with {process.ExitCode}");
}

// When running on .NET Core, we need to find the right SDK location that can load our project and restart the BuildHost if required.
// When dotnetPath is null, the BuildHost is started with the default dotnet executable, which may not be the right one for the project.
if (buildHostKind == BuildHostProcessKind.NetCore
&& projectOrSolutionFilePath is not null
&& dotnetPath is null)
{
// The BuildHost will be able to search through all the SDK install locations for a usable MSBuild instance.
var msbuildLocation = await buildHostProcess.BuildHost.FindUsableMSBuildAsync(projectOrSolutionFilePath, cancellationToken).ConfigureAwait(false);
if (msbuildLocation is not null && GetProcessPath() is { } processPath)
{
// The layout of the SDK is such that the dotnet executable is always at the same relative path from the MSBuild location.
dotnetPath = Path.GetFullPath(Path.Combine(msbuildLocation.Path, $"../../{DotnetExecutable}"));
if (dotnetPath is not null && processPath != dotnetPath)
{
// We need to relaunch the .NET BuildHost from a different dotnet instance.
reload = true;
await buildHostProcess.DisposeAsync().ConfigureAwait(false);
_logger?.LogInformation($".NET BuildHost started from {processPath} reloading to start from {dotnetPath} to match necessary SDK location.");
}
}
}
} while (reload);
buildHostProcess = await NoLock_GetBuildHostAsync(buildHostKind, projectOrSolutionFilePath, dotnetPath, cancellationToken).ConfigureAwait(false);

_processes.Add(buildHostKind, buildHostProcess);
}

return buildHostProcess.BuildHost;
}

async Task<BuildHostProcess> NoLock_GetBuildHostAsync(BuildHostProcessKind buildHostKind, string? projectOrSolutionFilePath, string? dotnetPath, CancellationToken cancellationToken)
{
var pipeName = Guid.NewGuid().ToString();
var processStartInfo = CreateBuildHostStartInfo(buildHostKind, pipeName, dotnetPath);

var process = Process.Start(processStartInfo);
Contract.ThrowIfNull(process, "Process.Start failed to launch a process.");

var buildHostProcess = new BuildHostProcess(process, pipeName, _loggerFactory);
buildHostProcess.Disconnected += BuildHostProcess_Disconnected;

// We've subscribed to Disconnected, but if the process crashed before that point we might have not seen it
if (process.HasExited)
{
buildHostProcess.LogProcessFailure();
throw new Exception($"BuildHost process exited immediately with {process.ExitCode}");
}

if (buildHostKind != BuildHostProcessKind.NetCore
|| projectOrSolutionFilePath is null
|| dotnetPath is not null)
{
return buildHostProcess;
}

// When running on .NET Core, we need to find the right SDK location that can load our project and restart the BuildHost if required.
// When dotnetPath is null, the BuildHost is started with the default dotnet executable, which may not be the right one for the project.

var processPath = GetProcessPath();

// The running BuildHost will be able to search through all the SDK install locations for a usable MSBuild instance.
var msbuildLocation = await buildHostProcess.BuildHost.FindBestMSBuildAsync(projectOrSolutionFilePath, cancellationToken).ConfigureAwait(false);
if (msbuildLocation is null)
{
return buildHostProcess;
}

// The layout of the SDK is such that the dotnet executable is always at the same relative path from the MSBuild location.
dotnetPath = Path.GetFullPath(Path.Combine(msbuildLocation.Path, $"../../{DotnetExecutable}"));

// If the dotnetPath is null or the file doesn't exist, we can't do anything about it; the BuildHost will just use the default dotnet executable.
// If the dotnetPath is the same as processPath then we are already running from the right dotnet executable, so we don't need to relaunch.
if (dotnetPath is null || processPath == dotnetPath || !File.Exists(dotnetPath))
{
return buildHostProcess;
}

// We need to relaunch the .NET BuildHost from a different dotnet instance.
buildHostProcess.Disconnected -= BuildHostProcess_Disconnected;
await buildHostProcess.DisposeAsync().ConfigureAwait(false);
_logger?.LogInformation(".NET BuildHost started from {ProcessPath} reloading to start from {DotnetPath} to match necessary SDK location.", processPath, dotnetPath);

return await NoLock_GetBuildHostAsync(buildHostKind, projectOrSolutionFilePath, dotnetPath, cancellationToken).ConfigureAwait(false);
}

#if NET
static string? GetProcessPath() => Environment.ProcessPath;
static string GetProcessPath() => Environment.ProcessPath ?? throw new InvalidOperationException("Unable to determine the path of the current process.");
#else
static string? GetProcessPath() => Process.GetCurrentProcess().MainModule?.FileName;
static string GetProcessPath() => Process.GetCurrentProcess().MainModule?.FileName ?? throw new InvalidOperationException("Unable to determine the path of the current process.");
#endif
}

Expand Down
Loading
Loading