dotnet/roslyn

Add overload to Diagnostic Analyzer template to support extra MetadataReferences

Open

#2,369 opened on Apr 29, 2015

View on GitHub
 (8 comments) (0 reactions) (0 assignees)C# (20,414 stars) (4,257 forks)batch import
Area-AnalyzersTesthelp wanted

Description

My team has been writing some Roslyn diagnostic analyzers and all the new developers on our team have encountered this situation, so I thought I'd bring up this suggestion.

The Roslyn analyzers template auto-generates a test project along with verifiers. By default, they only compile the test source code with 4 assemblies (ie. mscorlib, System.Core, etc). We found ourselves in a situation where any symbols returned from the SyntaxTree is null and we were not sure why because the logic in the analyser looked good. We realised the null was because it wasn’t able to compile the test source code that we were using due to references from other assemblies like ComposablePartsCatalog in System.Composition.ComponentModel.dll.

We had to add an overload to DiagnosticVerifier.Helper.cs to accept more metadata references.

I think any developer who wants to use a class other than those 4 will find themselves confused and spend time debugging just to come to the same conclusion as we did.

This is the code we added to the existing template code in DiagnosticVerifier.Helper.cs.

        private static Diagnostic[] GetSortedDiagnostics(string[] sources, string language, params MetadataReference[] additionalReferences)
        { }
...
        /// <summary>
        /// Create a project using the inputted strings as sources.
        /// </summary>
        /// <param name="sources">Classes in the form of strings</param>
        /// <param name="language">The language the source code is in</param>
        /// <returns>A Project created out of the Documents created from the source strings</returns>
        private static Project CreateProject(string[] sources, string language = LanguageNames.CSharp, params MetadataReference[] additionalReferences)
        {
            string fileNamePrefix = DefaultFilePathPrefix;
            string fileExt = language == LanguageNames.CSharp ? CSharpDefaultFileExt : VisualBasicDefaultExt;

            var projectId = ProjectId.CreateNewId(debugName: TestProjectName);

            var solution = new AdhocWorkspace()
                .CurrentSolution
                .AddProject(projectId, TestProjectName, TestProjectName, language)
                .AddMetadataReference(projectId, CorlibReference)
                .AddMetadataReference(projectId, SystemCoreReference)
                .AddMetadataReference(projectId, CSharpSymbolsReference)
                .AddMetadataReference(projectId, CodeAnalysisReference)
                .AddMetadataReferences(projectId, additionalReferences);

            int count = 0;
            foreach (var source in sources)
            {
                var newFileName = fileNamePrefix + count + "." + fileExt;
                var documentId = DocumentId.CreateNewId(projectId, debugName: newFileName);
                solution = solution.AddDocument(documentId, newFileName, SourceText.From(source));
                count++;
            }
            return solution.GetProject(projectId);
        }

Contributor guide