Skip to content

Commit

Permalink
feat: verify compilation diagnostics (#8397)
Browse files Browse the repository at this point in the history
* feat: log compilation diagnostics

* fix assembly load

* Abort on compilation error

* Make csharp.csproj net7.0 only since net6.0 cannot load projects targeting net7.0

* fix bad test compilations

* remove known VB error due to implicit imports

* skip vb project on non-windows platform
  • Loading branch information
yufeih authored Feb 8, 2023
1 parent 1a2fba6 commit 177a751
Show file tree
Hide file tree
Showing 87 changed files with 6,549 additions and 22,925 deletions.
2 changes: 1 addition & 1 deletion samples/csharp/src/CSharp.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<TargetFrameworks>net7.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
Expand Down
6 changes: 1 addition & 5 deletions samples/csharp/src/CSharp11.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
#if NET7_0_OR_GREATER

namespace CSharp11;
namespace CSharp11;

public class StaticAbstractMembersInInterfaces
{
Expand Down Expand Up @@ -55,5 +53,3 @@ file class FileScopedType
{

}

#endif
4 changes: 3 additions & 1 deletion samples/extensions/src/ExampleClass.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System;

namespace MyExample
{
public class ExampleClass
Expand All @@ -6,7 +8,7 @@ public class ExampleClass

public string MyField;

public string Myroperty { get; set; }
public string MyProperty { get; set; }

public ExampleClass()
{
Expand Down
2 changes: 0 additions & 2 deletions src/Microsoft.DocAsCode.Common/Loggers/ConsoleLogListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
namespace Microsoft.DocAsCode.Common
{
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using Microsoft.DocAsCode.Plugins;
Expand Down Expand Up @@ -34,7 +33,6 @@ public void WriteLine(ILogItem item)

message.Append(item.Message);

Debug.WriteLine(message);
ConsoleUtility.WriteLine(message.ToString(), consoleColor);
}

Expand Down
2 changes: 2 additions & 0 deletions src/Microsoft.DocAsCode.Common/Loggers/Logger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace Microsoft.DocAsCode.Common
{
using System;
using System.Diagnostics;
using System.Threading;

public static class Logger
Expand Down Expand Up @@ -91,6 +92,7 @@ public static void Log(ILogItem item)
Interlocked.Increment(ref _errorCount);
}

Debug.WriteLine(item.Message);
_syncListener.WriteLine(item);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,51 @@ namespace Microsoft.DocAsCode.Metadata.ManagedReference
using Microsoft.CodeAnalysis;
using Microsoft.DocAsCode.Common;
using Microsoft.DocAsCode.Exceptions;

using CS = Microsoft.CodeAnalysis.CSharp;
using VB = Microsoft.CodeAnalysis.VisualBasic;

internal static class CompilationUtility
internal static class CompilationHelper
{
// Bootstrap code to ensure essential types like `System.Object` is loaded for assemblies
private static readonly SyntaxTree[] s_assemblyBootstrap = new[]
{
CS.SyntaxFactory.ParseSyntaxTree(
"""
class Bootstrap
{
public static void Main(string[] foo) { }
}
"""),
};

public static bool CheckDiagnostics(this Compilation compilation)
{
var errorCount = 0;

foreach (var diagnostic in compilation.GetDeclarationDiagnostics())
{
if (diagnostic.IsSuppressed)
continue;

if (diagnostic.Severity is DiagnosticSeverity.Warning)
{
Logger.LogWarning(diagnostic.ToString());
continue;
}

if (diagnostic.Severity is DiagnosticSeverity.Error)
{
Logger.LogError(diagnostic.ToString());

if (++errorCount >= 20)
break;
}
}

return errorCount > 0;
}

public static Compilation CreateCompilationFromCSharpFiles(IEnumerable<string> files)
{
return CS.CSharpCompilation.Create(
Expand All @@ -38,7 +78,7 @@ public static Compilation CreateCompilationFromVBFiles(IEnumerable<string> files
{
return VB.VisualBasicCompilation.Create(
assemblyName: "vb.temp.dll",
options: new VB.VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary, xmlReferenceResolver: XmlFileResolver.Default),
options: new VB.VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary, globalImports: GetVBGlobalImports(), xmlReferenceResolver: XmlFileResolver.Default),
syntaxTrees: files.Select(path => VB.SyntaxFactory.ParseSyntaxTree(File.ReadAllText(path), path: path)),
references: GetDefaultMetadataReferences("VB"));
}
Expand All @@ -47,41 +87,39 @@ public static Compilation CreateCompilationFromVBCode(string code, string name =
{
return VB.VisualBasicCompilation.Create(
name,
options: new VB.VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary, xmlReferenceResolver: XmlFileResolver.Default),
options: new VB.VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary, globalImports: GetVBGlobalImports(), xmlReferenceResolver: XmlFileResolver.Default),
syntaxTrees: new[] { VB.SyntaxFactory.ParseSyntaxTree(code) },
references: GetDefaultMetadataReferences("VB").Concat(references));
}

public static Compilation CreateCompilationFromAssembly(IEnumerable<string> assemblyPaths, IEnumerable<string> references = null)
public static (Compilation, IAssemblySymbol) CreateCompilationFromAssembly(string assemblyPath, IEnumerable<string> references = null)
{
return CS.CSharpCompilation.Create(
var metadataReference = CreateMetadataReference(assemblyPath);
var compilation = CS.CSharpCompilation.Create(
"EmptyProjectWithAssembly",
options: new CS.CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary),
syntaxTrees: Array.Empty<SyntaxTree>(),
references: assemblyPaths
.Concat(assemblyPaths.SelectMany(GetReferenceAssemblies))
syntaxTrees: s_assemblyBootstrap,
references: GetReferenceAssemblies(assemblyPath)
.Concat(references ?? Enumerable.Empty<string>())
.Select(CreateMetadataReference));
.Select(CreateMetadataReference)
.Append(metadataReference));

var assembly = (IAssemblySymbol)compilation.GetAssemblyOrModuleSymbol(metadataReference);
return (compilation, assembly);
}

public static IEnumerable<IAssemblySymbol> GetAssemblyFromAssemblyComplation(Compilation assemblyCompilation, IReadOnlyCollection<string> assemblyPaths)
private static IEnumerable<VB.GlobalImport> GetVBGlobalImports()
{
foreach (var reference in assemblyCompilation.References)
{
Logger.LogVerbose($"Loading assembly {reference.Display}...");
var assembly = (IAssemblySymbol)assemblyCompilation.GetAssemblyOrModuleSymbol(reference);
if (assembly == null)
{
Logger.LogWarning($"Unable to get symbol from {reference.Display}, ignored...");
continue;
}

if (reference is PortableExecutableReference portableReference &&
assemblyPaths.Any(path => portableReference.FilePath.Replace('\\', '/') == path.Replace('\\', '/')))
{
yield return assembly;
}
}
// See default global imports in project properties panel for a default VB classlib.
return VB.GlobalImport.Parse(
"Microsoft.VisualBasic",
"System",
"System.Collections",
"System.Collections.Generic",
"System.Diagnostics",
"System.Linq",
"System.Xml.Linq",
"System.Threading.Tasks");
}

private static IEnumerable<MetadataReference> GetDefaultMetadataReferences(string language)
Expand All @@ -95,11 +133,13 @@ private static IEnumerable<MetadataReference> GetDefaultMetadataReferences(strin
var path = Path.Combine(refDirectory, version, "ref", moniker);

Logger.LogInfo($"Compiling {language} files using .NET SDK {version} for {moniker}");
Logger.LogVerbose($"Using SDK reference assemblies in {path}");
return Directory.EnumerateFiles(path, "*.dll", SearchOption.TopDirectoryOnly)
.Select(CreateMetadataReference);
}
catch
catch (Exception ex)
{
Logger.LogVerbose(ex.ToString());
throw new DocfxException("Cannot find .NET Core SDK to compile the project.");
}
}
Expand All @@ -108,11 +148,32 @@ private static IEnumerable<string> GetReferenceAssemblies(string assemblyPath)
{
using var assembly = new PEFile(assemblyPath);
var assemblyResolver = new UniversalAssemblyResolver(assemblyPath, false, assembly.DetectTargetFrameworkId());
foreach (var reference in assembly.AssemblyReferences)
var result = new Dictionary<string, string>();

GetReferenceAssembliesCore(assembly);

void GetReferenceAssembliesCore(PEFile assembly)
{
if (assemblyResolver.FindAssemblyFile(reference) is { } file)
yield return file;
foreach (var reference in assembly.AssemblyReferences)
{
var file = assemblyResolver.FindAssemblyFile(reference);
if (file is null)
{
Logger.LogWarning($"Unable to resolve assembly reference {reference}");
continue;
}

Logger.LogVerbose($"Loaded {reference.Name} from {file}");

using var referenceAssembly = new PEFile(file);
if (result.TryAdd(referenceAssembly.Name, file))
{
GetReferenceAssembliesCore(referenceAssembly);
}
}
}

return result.Values;
}

private static MetadataReference CreateMetadataReference(string assemblyPath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,5 @@ public class ExtractMetadataOptions
public bool DisableDefaultFilter { get; set; }

public TocNamespaceStyle TocNamespaceStyle { get; set; }

[JsonIgnore]
public IMethodSymbol[] RoslynExtensionMethods { get; set; }
}
}
Loading

0 comments on commit 177a751

Please sign in to comment.