public async Task<AnalysisData> GetDocumentBodyAnalysisDataAsync( DiagnosticAnalyzer provider, ProviderId providerId, VersionArgument versions, DiagnosticAnalyzerDriver analyzerDriver, SyntaxNode root, SyntaxNode member, int memberId, bool supportsSemanticInSpan, MemberRangeMap.MemberRanges ranges) { try { var document = analyzerDriver.Document; var cancellationToken = analyzerDriver.CancellationToken; var state = AnalyzersAndState.GetOrCreateDiagnosticState(StateType.Document, providerId, provider, document.Project.Id, document.Project.Language); var existingData = await state.TryGetExistingDataAsync(document, cancellationToken).ConfigureAwait(false); ImmutableArray<DiagnosticData> diagnosticData; if (supportsSemanticInSpan && CanUseDocumentState(existingData, ranges.TextVersion, versions.DataVersion)) { var memberDxData = await GetSemanticDiagnosticsAsync(providerId, provider, analyzerDriver).ConfigureAwait(false); diagnosticData = _owner.UpdateDocumentDiagnostics(existingData, ranges.Ranges, memberDxData.AsImmutableOrEmpty(), root.SyntaxTree, member, memberId); ValidateMemberDiagnostics(providerId, provider, document, root, diagnosticData); } else { // if we can't re-use existing document state, only option we have is updating whole document state here. var dx = await GetSemanticDiagnosticsAsync(providerId, provider, analyzerDriver).ConfigureAwait(false); diagnosticData = dx.AsImmutableOrEmpty(); } return new AnalysisData(versions.TextVersion, versions.DataVersion, GetExistingItems(existingData), diagnosticData); } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
public static void Cache(DiagnosticAnalyzer analyzer, object key, CacheEntry entry) { AssertKey(key); // add new cache entry var analyzerMap = s_map.GetOrAdd(analyzer, _ => new ConcurrentDictionary<object, CacheEntry>(concurrencyLevel: 2, capacity: 10)); analyzerMap[key] = entry; }
public MemberRanges GetSavedMemberRange(DiagnosticAnalyzer analyzer, Document document) { var data = _map.GetOrAdd(document.Id, s_createMap); lock (data) { return GetSavedMemberRange_NoLock(data, analyzer, document); } }
public StateSet(string language, DiagnosticAnalyzer analyzer, string errorSourceName) { _language = language; _analyzer = analyzer; _errorSourceName = errorSourceName; _state = CreateDiagnosticStates(language, analyzer); }
/// <summary> /// Get the unique state name for the given {type, analyzer} tuple. /// Note that this name is used by the underlying persistence stream of the corresponding <see cref="DiagnosticState"/> to Read/Write diagnostic data into the stream. /// If any two distinct {type, analyzer} tuples have the same diagnostic state name, we will end up sharing the persistence stream between them, leading to duplicate/missing/incorrect diagnostic data. /// </summary> private static ValueTuple<string, VersionStamp> GetNameAndVersion(DiagnosticAnalyzer analyzer, StateType type) { Contract.ThrowIfNull(analyzer); // Get the unique ID for given diagnostic analyzer. // note that we also put version stamp so that we can detect changed analyzer. var tuple = analyzer.GetAnalyzerIdAndVersion(); return ValueTuple.Create(UserDiagnosticsPrefixTableName + "_" + type.ToString() + "_" + tuple.Item1, tuple.Item2); }
public void Touch(DiagnosticAnalyzer analyzer, Document document, VersionStamp version) { // only touch and updateMemberRange methods are allowed to update the dictionaries var data = _map.GetOrAdd(document.Id, s_createMap); lock (data) { Touch_NoLock(data, analyzer, document, version); } }
public StateSet GetOrCreateStateSet(Project project, DiagnosticAnalyzer analyzer) { var map = GetOrCreateAnalyzerMap(project); if (map.TryGetValue(analyzer, out var set)) { return set; } return null; }
public static void LogAnalyzerCrashCount(DiagnosticAnalyzer analyzer, Exception ex, LogAggregator logAggregator, ProjectId projectId) { if (logAggregator == null || analyzer == null || ex == null || ex is OperationCanceledException) { return; } // TODO: once we create description manager, pass that into here. bool telemetry = DiagnosticAnalyzerLogger.AllowsTelemetry(null, analyzer, projectId); var tuple = ValueTuple.Create(telemetry, analyzer.GetType(), ex.GetType()); logAggregator.IncreaseCount(tuple); }
public StateSet GetOrCreateStateSet(string language, DiagnosticAnalyzer analyzer) { var map = GetAnalyzerMap(language); StateSet set; if (map.TryGetValue(analyzer, out set)) { return set; } return null; }
public static bool TryGetValue(DiagnosticAnalyzer analyzer, object key, out CacheEntry entry) { AssertKey(key); entry = default(CacheEntry); if (!s_map.TryGetValue(analyzer, out var analyzerMap) || !analyzerMap.TryGetValue(key, out entry)) { return false; } return true; }
public AnalyzerInfo(DiagnosticAnalyzer analyzer, AnalyzerActions analyzerActions, bool telemetry) { CLRType = analyzer.GetType(); Telemetry = telemetry; Counts[0] = analyzerActions.CodeBlockEndActionsCount; Counts[1] = analyzerActions.CodeBlockStartActionsCount; Counts[2] = analyzerActions.CompilationEndActionsCount; Counts[3] = analyzerActions.CompilationStartActionsCount; Counts[4] = analyzerActions.SemanticModelActionsCount; Counts[5] = analyzerActions.SymbolActionsCount; Counts[6] = analyzerActions.SyntaxNodeActionsCount; Counts[7] = analyzerActions.SyntaxTreeActionsCount; }
public void UpdateAnalyzerTypeCount(DiagnosticAnalyzer analyzer, ActionCounts analyzerActions, Project projectOpt) { var telemetry = DiagnosticAnalyzerLogger.AllowsTelemetry(_owner, analyzer, projectOpt?.Id); ImmutableInterlocked.AddOrUpdate( ref _analyzerInfoMap, analyzer.GetType(), addValue: new AnalyzerInfo(analyzer, analyzerActions, telemetry), updateValueFactory: (k, ai) => { ai.SetAnalyzerTypeCount(analyzerActions); return ai; }); }
public static void Remove(DiagnosticAnalyzer analyzer, object key) { AssertKey(key); // remove the entry if (!s_map.TryGetValue(analyzer, out var analyzerMap)) { return; } analyzerMap.TryRemove(key, out var entry); if (analyzerMap.IsEmpty) { s_map.TryRemove(analyzer, out analyzerMap); } }
public static bool IsCompilerAnalyzer(DiagnosticAnalyzer analyzer) { // TODO: find better way. var typeString = analyzer.GetType().ToString(); if (typeString == CSharpCompilerAnalyzerTypeName) { return true; } if (typeString == VisualBasicCompilerAnalyzerTypeName) { return true; } return false; }
private static DiagnosticState[] CreateDiagnosticStates(string language, DiagnosticAnalyzer analyzer) { var states = new DiagnosticState[s_stateTypeCount]; for (int stateType = 0; stateType < s_stateTypeCount; stateType++) { var nameAndVersion = GetNameAndVersion(analyzer, (StateType)stateType); var name = nameAndVersion.Item1; var version = nameAndVersion.Item2; states[stateType] = new DiagnosticState(name, version, language); } return states; }
public DiagnosticAnalyzerMap(HostAnalyzerManager analyzerManager, string language, ImmutableDictionary<DiagnosticAnalyzer, StateSet> analyzerMap) { // hold directly on to compiler analyzer _compilerAnalyzer = analyzerManager.GetCompilerDiagnosticAnalyzer(language); // in test case, we might not have the compiler analyzer. if (_compilerAnalyzer == null) { _map = analyzerMap; return; } _compilerStateSet = analyzerMap[_compilerAnalyzer]; // hold rest of analyzers _map = analyzerMap.Remove(_compilerAnalyzer); }
public void UpdateMemberRange( DiagnosticAnalyzer analyzer, Document document, VersionStamp newVersion, int memberId, TextSpan span, MemberRanges oldRanges) { // only touch and updateMemberRange methods are allowed to update the dictionaries var data = _map.GetOrAdd(document.Id, s_createMap); lock (data) { // now update member range map UpdateMemberRange_NoLock(data, document, newVersion, memberId, span, oldRanges.TextVersion); // save analyzer version information Touch_NoLock(data, analyzer, document, newVersion); ValidateMemberRangeMap(document, newVersion); } }
private bool SupportAnalysisKind(DiagnosticAnalyzer analyzer, string language, AnalysisKind kind) { // compiler diagnostic analyzer always support all kinds if (HostAnalyzerManager.IsCompilerDiagnosticAnalyzer(language, analyzer)) { return true; } switch (kind) { case AnalysisKind.Syntax: return analyzer.SupportsSyntaxDiagnosticAnalysis(); case AnalysisKind.Semantic: return analyzer.SupportsSemanticDiagnosticAnalysis(); default: return Contract.FailWithReturn<bool>("shouldn't reach here"); } }
public StateSet(string language, DiagnosticAnalyzer analyzer, string errorSourceName) { _language = language; _analyzer = analyzer; _errorSourceName = errorSourceName; var nameAndVersion = GetNameAndVersion(_analyzer); _analyzerVersion = nameAndVersion.Item2; _stateName = nameAndVersion.Item1; _syntaxStateName = _stateName + ".Syntax"; _semanticStateName = _stateName + ".Semantic"; _nonLocalStateName = _stateName + ".NonLocal"; _activeFileStates = new ConcurrentDictionary<DocumentId, ActiveFileState>(concurrencyLevel: 2, capacity: 10); _projectStates = new ConcurrentDictionary<ProjectId, ProjectState>(concurrencyLevel: 2, capacity: 1); }
public static void Remove(DiagnosticAnalyzer analyzer, object key) { AssertKey(key); // remove the entry ConcurrentDictionary<object, CacheEntry> analyzerMap; if (!s_map.TryGetValue(analyzer, out analyzerMap)) { return; } CacheEntry entry; analyzerMap.TryRemove(key, out entry); if (analyzerMap.IsEmpty) { s_map.TryRemove(analyzer, out analyzerMap); } }
private void Touch_NoLock(DictionaryData data, DiagnosticAnalyzer analyzer, Document document, VersionStamp version) { VersionStamp oldVersion; if (data.VersionMap.TryGetValue(analyzer, out oldVersion)) { DecreaseVersion_NoLock(data, document.Id, oldVersion); } IncreaseVersion_NoLock(data, document.Id, version); data.VersionMap[analyzer] = version; ImmutableArray<TextSpan> range; if (this.TryCreateOrGetMemberRange_NoLock(data, document, version, out range)) { data.MemberRangeMap[version] = range; } ValidateVersionTracking(); }
public LatestDiagnosticsForSpanGetter( DiagnosticIncrementalAnalyzer owner, Document document, SyntaxNode root, TextSpan range, bool blockForData, List<DiagnosticData> diagnostics, CancellationToken cancellationToken) { _owner = owner; _document = document; _compilerAnalyzer = _owner.HostAnalyzerManager.GetCompilerDiagnosticAnalyzer(_document.Project.Language); _range = range; _blockForData = blockForData; _cancellationToken = cancellationToken; Diagnostics = diagnostics; // Share the diagnostic analyzer driver across all analyzers. var fullSpan = root?.FullSpan; _spanBasedDriver = new DiagnosticAnalyzerDriver(_document, _range, root, _owner, _cancellationToken); _documentBasedDriver = new DiagnosticAnalyzerDriver(_document, fullSpan, root, _owner, _cancellationToken); _projectDriver = new DiagnosticAnalyzerDriver(_document.Project, _owner, _cancellationToken); }
public async Task<AnalysisData> GetDocumentAnalysisDataAsync( DiagnosticAnalyzer provider, ProviderId providerId, VersionArgument versions, DiagnosticAnalyzerDriver analyzerDrvier) { try { var document = analyzerDrvier.Document; var cancellationToken = analyzerDrvier.CancellationToken; var state = AnalyzersAndState.GetOrCreateDiagnosticState(StateType.Document, providerId, provider, document.Project.Id, document.Project.Language); var existingData = await state.TryGetExistingDataAsync(document, cancellationToken).ConfigureAwait(false); if (CheckSemanticVersions(document, existingData, versions)) { return existingData; } var diagnosticData = await GetSemanticDiagnosticsAsync(providerId, provider, analyzerDrvier).ConfigureAwait(false); return new AnalysisData(versions.TextVersion, versions.DataVersion, GetExistingItems(existingData), diagnosticData.AsImmutableOrEmpty()); } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
private Task <IEnumerable <DiagnosticData> > GetSyntaxDiagnosticsAsync(DiagnosticAnalyzer analyzer, CancellationToken cancellationToken) { return(_owner._executor.ComputeDiagnosticsAsync(_analyzerDriverOpt, _document, analyzer, AnalysisKind.Syntax, _range, cancellationToken)); }
/// <summary> /// Given an analyzer and a collection of documents to apply it to, run the analyzer and gather an array of /// diagnostics found. The returned diagnostics are then ordered by location in the source documents. /// </summary> /// <param name="analyzer">The analyzer to run on the documents.</param> /// <param name="documents">The <see cref="Document"/>s that the analyzer will be run on.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that the task will observe.</param> /// <returns>A collection of <see cref="Diagnostic"/>s that surfaced in the source code, sorted by /// <see cref="Diagnostic.Location"/>.</returns> protected static async Task <ImmutableArray <Diagnostic> > GetSortedDiagnosticsFromDocumentsAsync(DiagnosticAnalyzer analyzer, Document[] documents, CancellationToken cancellationToken) { var projects = new HashSet <Project>(); foreach (var document in documents) { projects.Add(document.Project); } var diagnostics = ImmutableArray.CreateBuilder <Diagnostic>(); foreach (var project in projects) { var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer), null, cancellationToken); var compilerDiagnostics = compilation.GetDiagnostics(cancellationToken); var compilerErrors = compilerDiagnostics.Where(i => i.Severity == DiagnosticSeverity.Error); var diags = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().ConfigureAwait(false); foreach (var diag in diags.Concat(compilerErrors)) { if (diag.Location == Location.None || diag.Location.IsInMetadata) { diagnostics.Add(diag); } else { for (int i = 0; i < documents.Length; i++) { var document = documents[i]; var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (tree == diag.Location.SourceTree) { diagnostics.Add(diag); } } } } } var results = SortDistinctDiagnostics(diagnostics); return(results.ToImmutableArray()); }
private async Task <IEnumerable <DiagnosticData> > GetProjectDiagnosticsAsync(DiagnosticAnalyzer analyzer, CancellationToken cancellationToken) { if (_projectResultCache == null) { // execute whole project as one shot and cache the result. var forceAnalyzerRun = true; var analysisResult = await _owner._executor.GetProjectAnalysisDataAsync(_analyzerDriverOpt, _project, _stateSets, forceAnalyzerRun, cancellationToken).ConfigureAwait(false); _projectResultCache = analysisResult.Result; } if (!_projectResultCache.TryGetValue(analyzer, out var result)) { return(ImmutableArray <DiagnosticData> .Empty); } return(GetResult(result, AnalysisKind.NonLocal, _document.Id)); }
/// <summary> /// General method that gets a collection of actual diagnostics found in the source after the analyzer is run, /// then verifies each of them. /// </summary> /// <param name="sources">An array of strings to create source documents from to run the analyzers on</param> /// <param name="language">The language of the classes represented by the source strings</param> /// <param name="analyzer">The analyzer to be run on the source code</param> /// <param name="expected">DiagnosticResults that should appear after the analyzer is run on the sources</param> private static async Task VerifyDiagnosticsAsync(string[] sources, string language, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expected) { var diagnostics = await GetSortedDiagnosticsAsync(sources, language, analyzer).ConfigureAwait(false); VerifyDiagnosticResults(diagnostics, analyzer, expected); }
private async Task <Diagnostic[]> GetSortedDiagnostics(DiagnosticAnalyzer analyzer) { var documents = await GetDocuments().ConfigureAwait(false); return(await GetSortedDiagnosticsFromDocuments(analyzer, documents, compileSolution : true).ConfigureAwait(false)); }
/// <summary> /// General method that gets a collection of actual diagnostics found in the source after the analyzer is run, /// then verifies each of them. /// </summary> /// <param name="sources">An array of strings to create source documents from to run the analyzers on</param> /// <param name="analyzer">The analyzer to be run on the source code</param> /// <param name="expected">DiagnosticResults that should appear after the analyzer is run on the sources</param> private void VerifyDiagnostics(string[] sources, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expected) { var diagnostics = GetSortedDiagnostics(sources, analyzer); VerifyDiagnosticResults(diagnostics, analyzer, expected); }
private async Task <IEnumerable <DiagnosticData> > GetCompilerSemanticDiagnosticsAsync(DiagnosticAnalyzer analyzer, CancellationToken cancellationToken) { var model = await _document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); VerifyDiagnostics(model); var root = await _document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var adjustedSpan = AdjustSpan(_document, root, _range); var diagnostics = model.GetDeclarationDiagnostics(adjustedSpan, cancellationToken).Concat(model.GetMethodBodyDiagnostics(adjustedSpan, cancellationToken)); return(_owner._executor.ConvertToLocalDiagnostics(_document, diagnostics, _range)); }
/// <summary> /// Given classes in the form of strings, their language, and an IDiagnosticAnlayzer to apply to it, return the /// diagnostics found in the string after converting it to a document. /// </summary> /// <param name="sources">Classes in the form of strings</param> /// <param name="language">The language the source classes are in</param> /// <param name="analyzer">The analyzer to be run on the sources</param> /// <returns>An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location</returns> private static Diagnostic[] GetSortedDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer) { return(GetSortedDiagnosticsFromDocuments(analyzer, GetDocuments(sources, language))); }
private static string GetProjectLogMessage(Project project, DiagnosticAnalyzer analyzer) { return string.Format("project: {0}, {1}", project.FilePath ?? project.Name, analyzer.ToString()); }
private static async Task<IEnumerable<DiagnosticData>> GetProjectDiagnosticsAsync(DiagnosticAnalyzerDriver userDiagnosticDriver, DiagnosticAnalyzer analyzer) { using (Logger.LogBlock(FunctionId.Diagnostics_ProjectDiagnostic, GetProjectLogMessage, userDiagnosticDriver.Project, analyzer, userDiagnosticDriver.CancellationToken)) { try { Contract.ThrowIfNull(analyzer); var diagnostics = await userDiagnosticDriver.GetProjectDiagnosticsAsync(analyzer).ConfigureAwait(false); return GetDiagnosticData(userDiagnosticDriver.Project, diagnostics); } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } } }
private async Task VerifyDiagnostics(DiagnosticAnalyzer analyzer, IList <DiagnosticResult> expected) { var diagnostics = await GetSortedDiagnostics(analyzer).ConfigureAwait(false); VerifyDiagnosticResults(diagnostics, analyzer, expected); }
/// <summary> /// Given classes in the form of strings, their language, and an <see cref="DiagnosticAnalyzer"/> to apply to /// it, return the <see cref="Diagnostic"/>s found in the string after converting it to a /// <see cref="Document"/>. /// </summary> /// <param name="sources">Classes in the form of strings.</param> /// <param name="language">The language the source classes are in. Values may be taken from the /// <see cref="LanguageNames"/> class.</param> /// <param name="analyzer">The analyzer to be run on the sources.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that the task will observe.</param> /// <returns>A collection of <see cref="Diagnostic"/>s that surfaced in the source code, sorted by /// <see cref="Diagnostic.Location"/>.</returns> private static Task <ImmutableArray <Diagnostic> > GetSortedDiagnosticsAsync(string[] sources, string language, DiagnosticAnalyzer analyzer, CancellationToken cancellationToken) { return(GetSortedDiagnosticsFromDocumentsAsync(analyzer, GetDocuments(sources, language), cancellationToken)); }
/// <summary> /// General method that gets a collection of actual diagnostics found in the source after the analyzer is run, /// then verifies each of them. /// </summary> /// <param name="sources">An array of strings to create source documents from to run the analyzers on</param> /// <param name="language">The language of the classes represented by the source strings</param> /// <param name="analyzer">The analyzer to be run on the source code</param> /// <param name="expected">DiagnosticResults that should appear after the analyzer is run on the sources</param> private void VerifyDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expected) { var diagnostics = GetSortedDiagnostics(sources, language, analyzer, parseOptions: null, compilationOptions: null); VerifyDiagnosticResults(diagnostics, analyzer, expected); }
/// <summary> /// General method that gets a collection of actual diagnostics found in the source after the analyzer is run, /// then verifies each of them. /// </summary> /// <param name="sources">An array of strings to create source documents from to run the analyzers on</param> /// <param name="language">The language of the classes represented by the source strings</param> /// <param name="analyzer">The analyzer to be run on the source code</param> /// <param name="expected">DiagnosticResults that should appear after the analyzer is run on the sources</param> private void VerifyDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expected) { var diagnostics = GetSortedDiagnostics(workspace, sources, language, analyzer); VerifyDiagnosticResults(diagnostics, analyzer, expected); }
/// <summary> /// Checks each of the actual Diagnostics found and compares them with the corresponding DiagnosticResult in the array of expected results. /// Diagnostics are considered equal only if the DiagnosticResultLocation, Id, Severity, and Message of the DiagnosticResult match the actual diagnostic. /// </summary> /// <param name="actualResults">The Diagnostics found by the compiler after running the analyzer on the source code</param> /// <param name="analyzer">The analyzer that was being run on the sources</param> /// <param name="expectedResults">Diagnostic Results that should have appeared in the code</param> private static void VerifyDiagnosticResults(IEnumerable <Diagnostic> actualResults, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expectedResults) { int expectedCount = expectedResults.Length; int actualCount = actualResults.Count(); if (expectedCount != actualCount) { string diagnosticsOutput = actualResults.Any() ? FormatDiagnostics(analyzer, actualResults.ToArray()) : " NONE."; Assert.True(false, string.Format("Mismatch between number of diagnostics returned, expected \"{0}\" actual \"{1}\"\r\n\r\nDiagnostics:\r\n{2}\r\n", expectedCount, actualCount, diagnosticsOutput)); } for (int i = 0; i < expectedResults.Length; i++) { var actual = actualResults.ElementAt(i); var expected = expectedResults[i]; if (expected.Line == -1 && expected.Column == -1) { if (actual.Location != Location.None) { Assert.True(false, string.Format("Expected:\nA project diagnostic with No location\nActual:\n{0}", FormatDiagnostics(analyzer, actual))); } } else { VerifyDiagnosticLocation(analyzer, actual, actual.Location, expected.Locations.First()); var additionalLocations = actual.AdditionalLocations.ToArray(); if (additionalLocations.Length != expected.Locations.Length - 1) { Assert.True(false, string.Format("Expected {0} additional locations but got {1} for Diagnostic:\r\n {2}\r\n", expected.Locations.Length - 1, additionalLocations.Length, FormatDiagnostics(analyzer, actual))); } for (int j = 0; j < additionalLocations.Length; ++j) { VerifyDiagnosticLocation(analyzer, actual, additionalLocations[j], expected.Locations[j + 1]); } } if (actual.Id != expected.Id) { Assert.True(false, string.Format("Expected diagnostic id to be \"{0}\" was \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", expected.Id, actual.Id, FormatDiagnostics(analyzer, actual))); } if (actual.Severity != expected.Severity) { Assert.True(false, string.Format("Expected diagnostic severity to be \"{0}\" was \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", expected.Severity, actual.Severity, FormatDiagnostics(analyzer, actual))); } if (actual.GetMessage() != expected.Message) { Assert.True(false, string.Format("Expected diagnostic message to be \"{0}\" was \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", expected.Message, actual.GetMessage(), FormatDiagnostics(analyzer, actual))); } } }
private static void VerifyDiagnosticResults(IEnumerable <Diagnostic> actualResults, DiagnosticAnalyzer analyzer, IList <DiagnosticResult> expectedResults) { var expectedCount = expectedResults.Count; var actualCount = actualResults.Count(); if (expectedCount != actualCount) { var diagnosticsOutput = actualResults.Any() ? FormatDiagnostics(analyzer, actualResults.ToArray()) : " NONE."; Assert.True(false, $"Mismatch between number of diagnostics returned, expected \"{expectedCount}\" actual \"{actualCount}\"\r\n\r\nDiagnostics:\r\n{diagnosticsOutput}\r\n"); } for (var i = 0; i < expectedResults.Count; i++) { var actual = actualResults.ElementAt(i); var expected = expectedResults[i]; if (expected.Line == -1 && expected.Column == -1) { if (actual.Location != Location.None) { Assert.True(false, string.Format(CultureInfo.InvariantCulture, "Expected:\nA project diagnostic with No location\nActual:\n{0}", FormatDiagnostics(analyzer, actual))); } } else { VerifyDiagnosticLocation(analyzer, actual, actual.Location, expected.Locations[0]); var additionalLocations = actual.AdditionalLocations.ToArray(); if (additionalLocations.Length != expected.Locations.Count - 1) { Assert.True(false, string.Format(CultureInfo.InvariantCulture, "Expected {0} additional locations but got {1} for Diagnostic:\r\n {2}\r\n", expected.Locations.Count - 1, additionalLocations.Length, FormatDiagnostics(analyzer, actual))); } for (var j = 0; j < additionalLocations.Length; ++j) { VerifyDiagnosticLocation(analyzer, actual, additionalLocations[j], expected.Locations[j + 1]); } } if (expected.Id != null && !string.Equals(actual.Id, expected.Id, StringComparison.Ordinal)) { Assert.True(false, string.Format(CultureInfo.InvariantCulture, "Expected diagnostic id to be \"{0}\" was \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", expected.Id, actual.Id, FormatDiagnostics(analyzer, actual))); } if (expected.Severity != null && actual.Severity != expected.Severity) { Assert.True(false, string.Format(CultureInfo.InvariantCulture, "Expected diagnostic severity to be \"{0}\" was \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", expected.Severity, actual.Severity, FormatDiagnostics(analyzer, actual))); } if (expected.Message != null && !string.Equals(actual.GetMessage(), expected.Message, StringComparison.Ordinal)) { Assert.True(false, string.Format(CultureInfo.InvariantCulture, "Expected diagnostic message to be \"{0}\" was \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", expected.Message, actual.GetMessage(), FormatDiagnostics(analyzer, actual))); } } }
/// <summary> /// General method that gets a collection of actual diagnostics found in the source after the analyzer is run, /// then verifies each of them. /// </summary> /// <param name="sources">An array of strings to create source documents from to run the analyzers on</param> /// <param name="language">The language of the classes represented by the source strings</param> /// <param name="analyzer">The analyzer to be run on the source code</param> /// <param name="expected">DiagnosticResults that should appear after the analyzer is run on the sources</param> private static void VerifyDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expected) { Diagnostic[] diagnostics = GetSortedDiagnostics(sources, language, analyzer); VerifyDiagnosticResults(diagnostics, analyzer, expected); }
private static bool ShouldRunAnalyzerForStateType(DiagnosticAnalyzer analyzer, StateType stateTypeId, ImmutableHashSet<string> diagnosticIds = null, Func<DiagnosticAnalyzer, ImmutableArray<DiagnosticDescriptor>> getDescriptors = null) { if (diagnosticIds != null && getDescriptors(analyzer).All(d => !diagnosticIds.Contains(d.Id))) { return false; } switch (stateTypeId) { case StateType.Syntax: return analyzer.SupportsSyntaxDiagnosticAnalysis(); case StateType.Document: return analyzer.SupportsSemanticDiagnosticAnalysis(); case StateType.Project: return analyzer.SupportsProjectDiagnosticAnalysis(); default: throw ExceptionUtilities.Unreachable; } }
private static string GetBuildToolName(HostAnalyzerManager analyzerManager, string language, DiagnosticAnalyzer analyzer) { var packageName = analyzerManager.GetDiagnosticAnalyzerPackageName(language, analyzer); if (packageName == null) { return null; } if (packageName == RoslynLanguageServices) { return PredefinedBuildTools.Live; } return $"{analyzer.GetAnalyzerAssemblyName()} [{packageName}]"; }
private static string GetSemanticLogMessage(Document document, TextSpan? span, DiagnosticAnalyzer analyzer) { return string.Format("semantic: {0}, {1}, {2}", document.FilePath ?? document.Name, span.HasValue ? span.Value.ToString() : "Full", analyzer.ToString()); }
/// <summary> /// Verifies that <paramref name="solution"/> produces no diagnostics when analyzed with <paramref name="analyzer"/>. /// </summary> /// <param name="analyzer">The <see cref="DiagnosticAnalyzer"/> to check <paramref name="solution"/> with.</param> /// <param name="solution">The <see cref="Solution"/> for which no errors or warnings are expected.</param> public static void NoAnalyzerDiagnostics(DiagnosticAnalyzer analyzer, Solution solution) { var diagnostics = Analyze.GetDiagnostics(analyzer, solution); NoDiagnostics(diagnostics); }
private bool ShouldRunForFullProject(DiagnosticAnalyzer analyzer, Project project) { // PERF: Don't query descriptors for compiler analyzer, always execute it. if (HostAnalyzerManager.IsCompilerDiagnosticAnalyzer(project.Language, analyzer)) { return true; } // most of analyzers, number of descriptor is quite small, so this should be cheap. return Owner.GetDiagnosticDescriptors(analyzer).Any(d => GetEffectiveSeverity(d, project.CompilationOptions) != ReportDiagnostic.Hidden); }
private async Task <IEnumerable <DiagnosticData> > GetCompilerSyntaxDiagnosticsAsync(DiagnosticAnalyzer analyzer, CancellationToken cancellationToken) { var root = await _document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var diagnostics = root.GetDiagnostics(); return(_owner._executor.ConvertToLocalDiagnostics(_document, diagnostics, _range)); }
/// <summary> /// Return <see cref="StateSet"/> for the given <see cref="DiagnosticAnalyzer"/> in the context of <see cref="Project"/>. /// This will either return already created <see cref="StateSet"/> for the specific snapshot of <see cref="Project"/> or /// It will create new <see cref="StateSet"/> for the <see cref="Project"/>. /// This will not have any side effect. /// </summary> public StateSet GetOrCreateStateSet(Project project, DiagnosticAnalyzer analyzer) { var stateSet = _hostStates.GetOrCreateStateSet(project.Language, analyzer); if (stateSet != null) { return stateSet; } return _projectStates.GetOrCreateStateSet(project, analyzer); }
public async Task InProperty(DiagnosticAnalyzer analyzer) { var fooCode = @" namespace RoslynSandbox { using System; using System.ComponentModel; using System.Drawing; using System.Runtime.CompilerServices; public class Foo { private Point point; private double h1; public event PropertyChangedEventHandler PropertyChanged; public int Value1 => this.Value1; public int Value2 => Value2; public int Value3 => this.Value1; public int Value4 { get { return this.Value4; } set { if (value == this.Value4) { return; } this.Value4 = value; this.OnPropertyChanged(); } } public int Value5 { get => this.Value5; set { if (value == this.Value5) { return; } this.Value5 = value; this.OnPropertyChanged(); } } public int Value6 { get => this.Value5; set { if (value == this.Value5) { return; } this.Value5 = value; this.OnPropertyChanged(); } } public int X { get => this.X; set { if (value == this.point.X) { return; } this.point = new Point(value, this.point.Y); this.OnPropertyChanged(); } } public int Y { get { return this.Y; } set { if (value == this.point.Y) { return; } this.point = new Point(this.point.X, value); this.OnPropertyChanged(); } } public double H1 { get => this.h1; set { if (value.Equals(this.h1)) { return; } this.h1 = value; this.OnPropertyChanged(); this.OnPropertyChanged(nameof(this.Height)); this.OnPropertyChanged(nameof(this.Height2)); } } public double Height { get { return this.Height; } } public double Height2 { get { return Math.Min(this.Height2, this.H1); } } protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }"; await Analyze.GetDiagnosticsAsync(analyzer, new[] { fooCode }, AnalyzerAssert.MetadataReferences).ConfigureAwait(false); }