Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
31 changes: 31 additions & 0 deletions src/Loggers/MSVC/CentralLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,29 @@ namespace ReferenceTrimmer.Loggers.MSVC;
/// </summary>
public sealed class CentralLogger : Logger
{
private sealed class LocalEventRedirector : IEventRedirector
{
private readonly Action<CustomBuildEventArgs> _forwardEvent;

public LocalEventRedirector(Action<CustomBuildEventArgs> forwardEvent)
{
_forwardEvent = forwardEvent;
}

public void ForwardEvent(BuildEventArgs buildEvent)
{
if (buildEvent is not CustomBuildEventArgs customBuildEvent)
{
throw new LoggerException($"Unexpected local forwarding event type: {buildEvent.GetType().FullName}");
}

_forwardEvent(customBuildEvent);
}
}

private readonly object _jsonLogWriteLock = new();
private Lazy<StreamWriter>? _lazyJsonLogFileStreamWriter;
private ForwardingLogger? _localForwardingLogger;
private bool _firstEvent = true;
private string? _jsonLogFilePath;

Expand Down Expand Up @@ -42,11 +63,21 @@ public override void Initialize(IEventSource eventSource)
});

eventSource.CustomEventRaised += CustomEventHandler;

_localForwardingLogger = new ForwardingLogger
{
BuildEventRedirector = new LocalEventRedirector(e => CustomEventHandler(this, e)),
Parameters = Parameters,
Verbosity = Verbosity,
};
_localForwardingLogger.Initialize(eventSource);
}

/// <inheritdoc />
public override void Shutdown()
{
_localForwardingLogger?.Shutdown();

lock (_jsonLogWriteLock)
{
if (_lazyJsonLogFileStreamWriter is not null && _lazyJsonLogFileStreamWriter.IsValueCreated)
Expand Down
85 changes: 74 additions & 11 deletions src/Loggers/MSVC/ForwardingLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,18 @@ private enum LibType

private sealed class ProjectStateLibs
{
public ProjectStateLibs(string projectFilePath)
{
ProjectFilePath = projectFilePath;
}

public string ProjectFilePath { get; }
public State ProjectState { get; set; }
public SortedSet<string> UnusedProjectLibPaths { get; } = new(StringComparer.OrdinalIgnoreCase);
}

private IEventSource? _eventSource;
private readonly ConcurrentDictionary<(int NodeId, int ProjectContextId), ProjectStateLibs> _buildContexts = new();
private readonly ConcurrentDictionary<string, ProjectStateLibs> _projects = new(StringComparer.OrdinalIgnoreCase);

public const string HelpKeyword = "ReferenceTrimmerUnusedMSVCLibraries";
Expand Down Expand Up @@ -114,27 +121,39 @@ public void Shutdown()

private void OnTaskStarted(object sender, TaskStartedEventArgs e)
{
if (!string.IsNullOrEmpty(e.ProjectFile) && e.TaskName.Equals(LinkTaskName, StringComparison.OrdinalIgnoreCase))
string? projectFilePath = e.ProjectFile;
if (!string.IsNullOrEmpty(projectFilePath) && e.TaskName.Equals(LinkTaskName, StringComparison.OrdinalIgnoreCase))
{
_projects[e.ProjectFile] = new ProjectStateLibs { ProjectState = State.LinkStarted };
var projectState = new ProjectStateLibs(projectFilePath)
{
ProjectState = State.LinkStarted,
};

if (TryGetProjectContextKey(e, out (int NodeId, int ProjectContextId) projectContextKey))
{
_buildContexts[projectContextKey] = projectState;
}
else
{
_projects[projectFilePath] = projectState;
}
}
}

private void OnTaskFinished(object sender, TaskFinishedEventArgs e)
{
if (string.IsNullOrEmpty(e.ProjectFile) || e.TaskName != LinkTaskName || !e.Succeeded)
if (!e.TaskName.Equals(LinkTaskName, StringComparison.OrdinalIgnoreCase) || !e.Succeeded)
{
return;
}

string projectFilePath = e.ProjectFile;

// Project state present in map if the Link task was detected running in OnTaskStarted.
if (!_projects.TryGetValue(projectFilePath, out ProjectStateLibs projState))
if (!TryGetProjectState(e, e.ProjectFile, out ProjectStateLibs projState))
{
return;
}

string projectFilePath = projState.ProjectFilePath;

if (projState.ProjectState is State.UnusedLibsStarted or State.UnusedLibsEnded &&
projState.UnusedProjectLibPaths.Count > 0)
{
Expand Down Expand Up @@ -219,7 +238,7 @@ private void OnTaskFinished(object sender, TaskFinishedEventArgs e)
jsonSb.ToString()));
}

_projects.TryRemove(projectFilePath, out _);
RemoveProjectState(e, projectFilePath);
}

private static string EscapeJsonChars(string str)
Expand All @@ -229,15 +248,14 @@ private static string EscapeJsonChars(string str)

private void OnMessageRaised(object sender, BuildMessageEventArgs e)
{
string? projectFilePath = e.ProjectFile;
string? message = e.Message;

if (string.IsNullOrEmpty(projectFilePath) || message is null)
if (message is null)
{
return;
}

if (!_projects.TryGetValue(projectFilePath, out ProjectStateLibs? projState))
if (!TryGetProjectState(e, e.ProjectFile, out ProjectStateLibs projState))
{
return;
}
Expand Down Expand Up @@ -280,4 +298,49 @@ private void OnMessageRaised(object sender, BuildMessageEventArgs e)
break;
}
}

private bool TryGetProjectState(BuildEventArgs e, string? projectFilePath, out ProjectStateLibs projectState)
{
if (TryGetProjectContextKey(e, out (int NodeId, int ProjectContextId) projectContextKey))
{
return _buildContexts.TryGetValue(projectContextKey, out projectState!);
}

if (projectFilePath is { Length: > 0 })
{
return _projects.TryGetValue(projectFilePath, out projectState!);
}

projectState = null!;
return false;
}

private void RemoveProjectState(BuildEventArgs e, string projectFilePath)
{
if (TryGetProjectContextKey(e, out (int NodeId, int ProjectContextId) projectContextKey))
{
_buildContexts.TryRemove(projectContextKey, out _);
}
else
{
_projects.TryRemove(projectFilePath, out _);
}
}

private static bool TryGetProjectContextKey(
BuildEventArgs e,
out (int NodeId, int ProjectContextId) projectContextKey)
{
BuildEventContext? context = e.BuildEventContext;
if (context is not null &&
context.NodeId != BuildEventContext.InvalidNodeId &&
context.ProjectContextId != BuildEventContext.InvalidProjectContextId)
{
projectContextKey = (context.NodeId, context.ProjectContextId);
return true;
}

projectContextKey = default;
return false;
}
}
Loading
Loading