Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correctly handle <ProjectReferences> that don't produce references #1956

Merged

Conversation

jasonmalinowski
Copy link
Contributor

elements can have metadata that specify what type of item to create, or that they shouldn't create items at all. The existing code that was processing references wasn't checking for this metadata, so you could end up with project references between projects that shouldn't be there.

The approach to take here is to never look at the items directly, rather only look at the ReferencePath items that are produced, and if we see metadata that indicates it came from a project, convert it to a project reference at that point.


var originalItemSpec = referencePathItem.GetMetadataValue(MetadataNames.OriginalItemSpec);
if (originalItemSpec.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase))
var sourceProjectFile = referencePathItem.GetMetadataValue(MetadataNames.MSBuildSourceProjectFile);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still confirming with the MSBuild team precise which property should be used here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • OriginalItemSpec: available on all RAR outputs. The Include value of the RAR input that caused that output. (This is actually automatically set in the engine whenever populating an item from another item)

  • ProjectReferenceOriginalItemSpec: available on RAR outputs that were resolved from @(ProjectReference) items. The OriginalItemSpec value of the Reference that ResolveProjectReferences produced from the ProjectReference item--so the ProjectReference's Include.

  • `OriginalProjectReferenceItemSpec: ¯\(°_o)/¯

    Copy OriginalItemSpec to OriginalProjectReferenceItemSpec, so that when ResolveAssemblyReferences
    takes these items and resolves them to ReferencePath, we can still recover the real OriginalItemSpec
    for the unresolved reference items.

    Doesn't appear to be used anywhere. My advice: avoid.

  • MSBuildSourceProjectFile: available on all items that are outputs of the <MSBuild task. Points to the project that created the item. For RAR outputs, inherited from the Reference generated by <MSBuild in ResolveProjectReferences

So the thing that most matches your use case is ProjectReferenceOriginalItemSpec. It has a weakness though: it's a relative path, not fully resolved. As long as you deal with that I'd go with it. MSBuildSourceProjectFile should always be an absolute path which is nice but it could get confused with custom reference-resolution schemes.

Copy link
Member

@JoeRobich JoeRobich Sep 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rainersigwald What we noticed is that the fully qualified MSBuildSourceProjectFile prepends the /private/ folder name on MacOS for the shadowcopied unit tests. This causes them to be different that the paths we qualify with Path.GetFullPath. I'll take your advice and update to use ProjectReferenceOriginalItemSpec.

Comment on lines +9 to +10
<OutputItemType>Analyzer</OutputItemType>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a pattern we're seeing is more common with people writing source generators, since you often want to have the generator in your same solution as the project itself. It's not the best supported because reloading the analyzer is often difficult if it changes on disk.

@JoeRobich
Copy link
Member

@jasonmalinowski If for any reason you need your test project to be built prior to your new unit test running then you can add the folder name to this list

@jasonmalinowski
Copy link
Contributor Author

@JoeRobich Shouldn't be necessary, and honestly if it was that'd be a bug in it's own right.

Copy link
Member

@filipw filipw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks good to me, can we "undraft" it?

@jasonmalinowski jasonmalinowski force-pushed the fix-handling-of-projectreferences branch 2 times, most recently from e8ee7fd to c5caf6d Compare September 28, 2020 19:09
@jasonmalinowski jasonmalinowski marked this pull request as ready for review September 28, 2020 19:10
@filipw
Copy link
Member

filipw commented Sep 28, 2020

sorry! it needs another rebase/merge due to a merge of #1964

jasonmalinowski and others added 2 commits September 28, 2020 12:20
<ProjectReference> elements can have metadata that specify what type
of item to create, or that they shouldn't create items at all.
The existing code that was processing references wasn't checking for
this metadata, so you could end up with project references between
projects that shouldn't be there.

The approach to take here is to never look at the <ProjectReference>
items directly, rather only look at the ReferencePath items that are
produced, and if we see metadata that indicates it came from a project,
convert it to a project reference at that point.
@jasonmalinowski
Copy link
Contributor Author

@filipw Rebased. I swear you're the only repo I know that actually has that 'must be up to date' thing checked. 😄

Copy link
Member

@filipw filipw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit: thank you!

@filipw
Copy link
Member

filipw commented Sep 28, 2020

also, I learnt something here and I can now drop ProjectReferenceOriginalItemSpec in some casual conversation around project structures

@jasonmalinowski
Copy link
Contributor Author

@filipw And note that generally, in Visual Studio for Windows we don't look at that property, and instead just wire up things based on output paths. So if project A is producing a DLL to an output path and project B is consuming that same (exact, full) path, we wire them up at that point. That may be something that needs to happen here longer term; this fix at least will help in unblocking us investigating other issues.

@JoeRobich
Copy link
Member

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants