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

Ensure that we respect source suppressions for IDE analyzer diagnosti… #11343

Merged
merged 1 commit into from
May 17, 2016
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
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,22 @@ internal sealed class AnalyzerDependencyCheckingService
private Task<AnalyzerDependencyResults> _task = Task.FromResult(AnalyzerDependencyResults.Empty);
private ImmutableHashSet<string> _analyzerPaths = ImmutableHashSet.Create<string>(StringComparer.OrdinalIgnoreCase);

private readonly DiagnosticDescriptor _missingAnalyzerReferenceRule = new DiagnosticDescriptor(
id: IDEDiagnosticIds.MissingAnalyzerReferenceId,
title: ServicesVSResources.WRN_MissingAnalyzerReferenceTitle,
messageFormat: ServicesVSResources.WRN_MissingAnalyzerReferenceMessage,
category: FeaturesResources.ErrorCategory,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

private readonly DiagnosticDescriptor _analyzerDependencyConflictRule = new DiagnosticDescriptor(
id: IDEDiagnosticIds.AnalyzerDependencyConflictId,
title: ServicesVSResources.WRN_AnalyzerDependencyConflictTitle,
messageFormat: ServicesVSResources.WRN_AnalyzerDependencyConflictMessage,
category: FeaturesResources.ErrorCategory,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

[ImportingConstructor]
public AnalyzerDependencyCheckingService(
VisualStudioWorkspaceImpl workspace,
Expand Down Expand Up @@ -74,15 +90,25 @@ public async void CheckForConflictsAsync()
if (project.CurrentProjectAnalyzersContains(conflict.AnalyzerFilePath1) ||
project.CurrentProjectAnalyzersContains(conflict.AnalyzerFilePath2))
{
builder.Add(CreateDiagnostic(project.Id, conflict));
var messageArguments = new string[] { conflict.AnalyzerFilePath1, conflict.AnalyzerFilePath2, conflict.Identity.ToString() };
DiagnosticData diagnostic;
if (DiagnosticData.TryCreate(_analyzerDependencyConflictRule, messageArguments, project.Id, _workspace, out diagnostic))
{
builder.Add(diagnostic);
}
}
}

foreach (var missingDependency in missingDependencies)
{
if (project.CurrentProjectAnalyzersContains(missingDependency.AnalyzerPath))
{
builder.Add(CreateDiagnostic(project.Id, missingDependency));
var messageArguments = new string[] { missingDependency.AnalyzerPath, missingDependency.DependencyIdentity.ToString() };
DiagnosticData diagnostic;
if (DiagnosticData.TryCreate(_missingAnalyzerReferenceRule, messageArguments, project.Id, _workspace, out diagnostic))
{
builder.Add(diagnostic);
}
}
}

Expand Down Expand Up @@ -123,57 +149,6 @@ private void LogMissingDependency(MissingAnalyzerDependency missingDependency)
}));
}

private DiagnosticData CreateDiagnostic(ProjectId projectId, AnalyzerDependencyConflict conflict)
{
string message = string.Format(
ServicesVSResources.WRN_AnalyzerDependencyConflictMessage,
conflict.AnalyzerFilePath1,
conflict.AnalyzerFilePath2,
conflict.Identity.ToString());

DiagnosticData data = new DiagnosticData(
IDEDiagnosticIds.AnalyzerDependencyConflictId,
FeaturesResources.ErrorCategory,
message,
ServicesVSResources.WRN_AnalyzerDependencyConflictMessage,
severity: DiagnosticSeverity.Warning,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true,
warningLevel: 0,
customTags: ImmutableArray<string>.Empty,
properties: ImmutableDictionary<string, string>.Empty,
workspace: _workspace,
projectId: projectId,
title: ServicesVSResources.WRN_AnalyzerDependencyConflictTitle);

return data;
}

private DiagnosticData CreateDiagnostic(ProjectId projectId, MissingAnalyzerDependency missingDependency)
{
string message = string.Format(
ServicesVSResources.WRN_MissingAnalyzerReferenceMessage,
missingDependency.AnalyzerPath,
missingDependency.DependencyIdentity.ToString());

DiagnosticData data = new DiagnosticData(
IDEDiagnosticIds.MissingAnalyzerReferenceId,
FeaturesResources.ErrorCategory,
message,
ServicesVSResources.WRN_MissingAnalyzerReferenceMessage,
severity: DiagnosticSeverity.Warning,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true,
warningLevel: 0,
customTags: ImmutableArray<string>.Empty,
properties: ImmutableDictionary<string, string>.Empty,
workspace: _workspace,
projectId: projectId,
title: ServicesVSResources.WRN_MissingAnalyzerReferenceTitle);

return data;
}

private Task<AnalyzerDependencyResults> GetConflictsAsync()
{
ImmutableHashSet<string> currentAnalyzerPaths = _workspace.CurrentSolution
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ internal sealed class AnalyzerFileWatcherService

private readonly object _guard = new object();

private readonly DiagnosticDescriptor _analyzerChangedRule = new DiagnosticDescriptor(
id: IDEDiagnosticIds.AnalyzerChangedId,
title: ServicesVSResources.WRN_AnalyzerChangedTitle,
messageFormat: ServicesVSResources.WRN_AnalyzerChangedMessage,
category: FeaturesResources.ErrorCategory,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

[ImportingConstructor]
public AnalyzerFileWatcherService(
VisualStudioWorkspaceImpl workspace,
Expand Down Expand Up @@ -67,21 +75,12 @@ internal void RemoveAnalyzerAlreadyLoadedDiagnostics(ProjectId projectId, string

private void RaiseAnalyzerChangedWarning(ProjectId projectId, string analyzerPath)
{
string message = string.Format(ServicesVSResources.WRN_AnalyzerChangedMessage, analyzerPath);

DiagnosticData data = new DiagnosticData(
IDEDiagnosticIds.AnalyzerChangedId,
FeaturesResources.ErrorCategory,
message,
ServicesVSResources.WRN_AnalyzerChangedMessage,
severity: DiagnosticSeverity.Warning,
isEnabledByDefault: true,
warningLevel: 0,
workspace: _workspace,
projectId: projectId,
title: ServicesVSResources.WRN_AnalyzerChangedTitle);

_updateSource.UpdateDiagnosticsForProject(projectId, Tuple.Create(s_analyzerChangedErrorId, analyzerPath), SpecializedCollections.SingletonEnumerable(data));
var messageArguments = new string[] { analyzerPath };
DiagnosticData diagnostic;
if (DiagnosticData.TryCreate(_analyzerChangedRule, messageArguments, projectId, _workspace, out diagnostic))
{
_updateSource.UpdateDiagnosticsForProject(projectId, Tuple.Create(s_analyzerChangedErrorId, analyzerPath), SpecializedCollections.SingletonEnumerable(diagnostic));
}
}

private DateTime? GetLastUpdateTimeUtc(string fullPath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ internal abstract partial class AbstractProject : IVisualStudioHostProject
private static readonly EventHandler<bool> s_additionalDocumentClosingEventHandler = OnAdditionalDocumentClosing;
private static readonly EventHandler s_additionalDocumentUpdatedOnDiskEventHandler = OnAdditionalDocumentUpdatedOnDisk;

private readonly DiagnosticDescriptor _errorReadingRulesetRule = new DiagnosticDescriptor(
id: IDEDiagnosticIds.ErrorReadingRulesetId,
title: ServicesVSResources.ERR_CantReadRulesetFileTitle,
messageFormat: ServicesVSResources.ERR_CantReadRulesetFileMessage,
category: FeaturesResources.ErrorCategory,
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true);

public AbstractProject(
VisualStudioProjectTracker projectTracker,
Func<ProjectId, IVsReportExternalErrors> reportExternalErrorCreatorOpt,
Expand Down Expand Up @@ -1166,20 +1174,12 @@ protected void UpdateRuleSetError(IRuleSetFile ruleSetFile)
}
else
{
string message = string.Format(ServicesVSResources.ERR_CantReadRulesetFileMessage, ruleSetFile.FilePath, ruleSetFile.GetException().Message);
var data = new DiagnosticData(
id: IDEDiagnosticIds.ErrorReadingRulesetId,
category: FeaturesResources.ErrorCategory,
message: message,
enuMessageForBingSearch: ServicesVSResources.ERR_CantReadRulesetFileMessage,
severity: DiagnosticSeverity.Error,
isEnabledByDefault: true,
warningLevel: 0,
workspace: this.Workspace,
projectId: this.Id,
title: ServicesVSResources.ERR_CantReadRulesetFileTitle);

this.HostDiagnosticUpdateSource.UpdateDiagnosticsForProject(this.Id, RuleSetErrorId, SpecializedCollections.SingletonEnumerable(data));
var messageArguments = new string[] { ruleSetFile.FilePath, ruleSetFile.GetException().Message };
DiagnosticData diagnostic;
if (DiagnosticData.TryCreate(_errorReadingRulesetRule, messageArguments, this.Id, this.Workspace, out diagnostic))
{
this.HostDiagnosticUpdateSource.UpdateDiagnosticsForProject(this.Id, RuleSetErrorId, SpecializedCollections.SingletonEnumerable(diagnostic));
}
}
}

Expand Down
29 changes: 29 additions & 0 deletions src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,35 @@ public static DiagnosticData Create(Document document, Diagnostic diagnostic)
isSuppressed: diagnostic.IsSuppressed);
}

public static bool TryCreate(DiagnosticDescriptor descriptor, string[] messageArguments, ProjectId projectId, Workspace workspace, out DiagnosticData diagnosticData, CancellationToken cancellationToken = default(CancellationToken))
{
diagnosticData = null;
var project = workspace.CurrentSolution.GetProject(projectId);
if (project == null)
{
return false;
}

var diagnostic = Diagnostic.Create(descriptor, Location.None, messageArguments);
if (project.SupportsCompilation)
{
// Get diagnostic with effective severity.
// Additionally, if the diagnostic was suppressed by a source suppression, effectiveDiagnostics will have a diagnostic with IsSuppressed = true.
var compilation = project.GetCompilationAsync(cancellationToken).WaitAndGetResult(cancellationToken);
Copy link
Contributor

Choose a reason for hiding this comment

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

will this be okay?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure, but all the current callsites are sync. We can revisit in future.

var effectiveDiagnostics = CompilationWithAnalyzers.GetEffectiveDiagnostics(SpecializedCollections.SingletonEnumerable(diagnostic), compilation);
if (effectiveDiagnostics == null || effectiveDiagnostics.IsEmpty())
{
// Rule is disabled by compilation options.
return false;
}

diagnostic = effectiveDiagnostics.Single();
}

diagnosticData = diagnostic.ToDiagnosticData(project);
return true;
}

private static void GetLocationInfo(Document document, Location location, out TextSpan sourceSpan, out FileLinePositionSpan originalLineInfo, out FileLinePositionSpan mappedLineInfo)
{
var diagnosticSpanMappingService = document.Project.Solution.Workspace.Services.GetService<IWorkspaceVenusSpanMappingService>();
Expand Down