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

Fix calculation of implicit state for package dependencies #9370

Merged
Merged
Changes from 1 commit
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ protected internal virtual DiagnosticLevel GetDiagnosticLevel(bool? isResolved,
#endif

// This is a resolved dependency.
bool isImplicit = IsImplicit(projectFullPath, properties);
bool isImplicit = IsImplicit(projectFullPath, evaluation?.Properties, properties);
DiagnosticLevel diagnosticLevel = GetDiagnosticLevel(isResolved: true, properties);
string caption = GetResolvedCaption(itemSpec, id, properties);
ProjectImageMoniker icon = GetIcon(isImplicit, diagnosticLevel);
Expand Down Expand Up @@ -279,7 +279,7 @@ protected internal virtual DiagnosticLevel GetDiagnosticLevel(bool? isResolved,
Assumes.True(StringComparers.DependencyIds.Equals(id, itemSpec));
#endif

bool isImplicit = IsImplicit(projectFullPath, properties);
bool isImplicit = IsImplicit(projectFullPath, properties, null);
DiagnosticLevel diagnosticLevel = GetDiagnosticLevel(isResolved: isEvaluationOnlySnapshot, properties);
string caption = GetUnresolvedCaption(itemSpec, properties);
ProjectImageMoniker icon = GetIcon(isImplicit, diagnosticLevel);
Expand Down Expand Up @@ -348,7 +348,7 @@ internal bool TryUpdate(

bool isResolved = true;

bool isImplicit = IsImplicit(projectFullPath, properties);
bool isImplicit = IsImplicit(projectFullPath, properties, evaluation?.Properties);
DiagnosticLevel diagnosticLevel = GetDiagnosticLevel(isResolved, properties);
string caption = GetResolvedCaption(itemSpec, dependency.Id, properties);
ProjectImageMoniker icon = GetIcon(isImplicit, diagnosticLevel);
Expand Down Expand Up @@ -380,7 +380,7 @@ internal bool TryUpdate(

bool? isResolved = isEvaluationOnlySnapshot ? dependency.IsResolved : false;

bool isImplicit = IsImplicit(projectFullPath, properties);
bool isImplicit = IsImplicit(projectFullPath, null, properties);
DiagnosticLevel diagnosticLevel = GetDiagnosticLevel(isResolved, properties, defaultLevel: dependency.DiagnosticLevel);
string caption = GetUnresolvedCaption(itemSpec, properties);
ProjectImageMoniker icon = GetIcon(isImplicit, diagnosticLevel);
Expand Down Expand Up @@ -436,26 +436,47 @@ private ProjectImageMoniker GetIcon(bool isImplicit, DiagnosticLevel diagnosticL

private static bool IsImplicit(
string projectFullPath,
IImmutableDictionary<string, string> properties)
IImmutableDictionary<string, string>? evaluationProperties,
IImmutableDictionary<string, string>? buildProperties)
{
Requires.NotNull(projectFullPath);
Requires.NotNull(properties);
Assumes.True(evaluationProperties is not null || buildProperties is not null);

// We have two ways of determining whether a given dependency is implicit.
//
// 1. Checking its "IsImplicitlyDefined" metadata, and
// 2. Checking whether its "DefiningProjectFullPath" metadata matches the current project path.
//
// Additionally, we check both evaluation and build data where possible, because certain
// dependency types require this currently. For example, resolved package references (from
// build data) report "IsImplicitlyDefined" as "false" despite being defined outside the
// user's project. Therefore, we check "DefiningProjectFullPath" first, however that value is
// only defined (for packages) in evaluation data, hence the need to check both eval and build
// properties.
//
// Note that ideally the evaluation/build would produce consistent values for all
// dependencies, rather than us having to manipulate them here. We could fix that in
// MSBuild and SDK targets one day.

// Check for "IsImplicitlyDefined" metadata, which is available on certain items.
bool? isImplicitMetadata = properties.GetBoolProperty(ProjectItemMetadata.IsImplicitlyDefined);
// Check for "DefiningProjectFullPath" metadata and compare with the project file path.
// This is used by COM dependencies (and possibly others). It may only be present in
// evaluation properties, so we check both build and eval data.
string? definingProjectFullPath = buildProperties?.GetStringProperty(ProjectItemMetadata.DefiningProjectFullPath);
definingProjectFullPath ??= evaluationProperties?.GetStringProperty(ProjectItemMetadata.DefiningProjectFullPath);

if (isImplicitMetadata != null)
if (!string.IsNullOrEmpty(definingProjectFullPath))
{
return isImplicitMetadata.Value;
return !StringComparers.Paths.Equals(definingProjectFullPath, projectFullPath);
}

// Check for "DefiningProjectFullPath" metadata and compare with the project file path.
// This is used by COM dependencies (and possibly others).
string? definingProjectFullPath = properties.GetStringProperty(ProjectItemMetadata.DefiningProjectFullPath);
// Check for "IsImplicitlyDefined" metadata, which is available on certain items.
// Some items, such as package references, define this on evaluation data but not build data.
bool? isImplicitMetadata = buildProperties?.GetBoolProperty(ProjectItemMetadata.IsImplicitlyDefined);
isImplicitMetadata ??= evaluationProperties?.GetBoolProperty(ProjectItemMetadata.IsImplicitlyDefined);

if (!string.IsNullOrEmpty(definingProjectFullPath))
if (isImplicitMetadata != null)
{
return !StringComparers.Paths.Equals(definingProjectFullPath, projectFullPath);
return isImplicitMetadata.Value;
}

return false;
Expand Down