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
32 changes: 23 additions & 9 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,52 @@
Global references are included in ALL projects in this repository
-->
<ItemGroup>
<GlobalPackageReference Include="Ubiquity.NET.Versioning.Build.Tasks" Version="5.0.7" />
<GlobalPackageReference Include="Ubiquity.NET.Versioning.Build.Tasks" Version="5.0.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</GlobalPackageReference>
<GlobalPackageReference Include="IDisposableAnalyzers" Version="4.0.8" Condition="'$(NoCommonAnalyzers)' !=' true'" />
<GlobalPackageReference Include="MustUseRetVal" Version="0.0.2" Condition="'$(NoCommonAnalyzers)' !=' true'" />
<!--
NOTE: This analyzer is sadly, perpetually in "pre-release mode". There have been many issues/discussion on the point
and it has all fallen on deaf ears. So policies regarding "NO-Prerelease" components need to be overruled on this one
-->
-->
<GlobalPackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556" Condition="'$(UseStyleCop)' != 'false'" />
</ItemGroup>

<!--
Package versions made consistent across all packages referenced in this repository
-->
<ItemGroup>
<!-- Roslyn Analyzers ***MUST*** target older framework -->
<PackageVersion Include="AnsiCodes" Version="0.2.1" />
<PackageVersion Include="Microsoft.Bcl.HashCode" Version="6.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis" Version="4.14.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="4.14.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Common" Version="4.14.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Features" Version="4.14.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing" Version="1.1.2" />
<PackageVersion Include="Microsoft.CodeAnalysis.VisualBasic" Version="4.14.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.VisualBasic.Features" Version="4.14.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.VisualBasic.SourceGenerators.Testing" Version="1.1.2" />
<PackageVersion Include="Basic.Reference.Assemblies.Net80" Version="1.8.3" />
<PackageVersion Include="PolySharp" Version="1.15.0" />
<PackageVersion Include="System.Buffers" Version="4.6.1" />
<PackageVersion Include="System.Collections.Immutable" Version="9.0.10" />
<PackageVersion Include="System.Memory" Version="4.5.5" />

<!-- Currently, only in preview -->
<PackageVersion Include="System.CommandLine" Version="2.0.0-rc.2.25502.107" />

<!-- Security vulnerability overrides -->
<!-- Workaround(2): https://github.com/dotnet/roslyn-sdk/issues/1191 -->
<PackageVersion Include="System.Formats.Asn1" Version="9.0.10" />
<!-- https://github.com/dotnet/roslyn-sdk/issues/1191 -->
<PackageVersion Include="System.Formats.Asn1" Version="10.0.0" />
<!-- https://github.com/advisories/GHSA-7jgj-8wvc-jh57 -->
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
<!-- https://github.com/advisories/GHSA-cmhx-cq75-c4mj -->
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />

<!-- Common packages for solution -->
<!-- Common packages for solution -->
<PackageVersion Include="System.Linq.Async" Version="6.0.3" />
<PackageVersion Include="Ubiquity.NET.LibLLVM" Version="20.1.8" />
<PackageVersion Include="Ubiquity.NET.Versioning" Version="6.0.2-beta" />
Expand All @@ -46,9 +60,9 @@
<PackageVersion Include="System.CodeDom" Version="9.0.7" />

<!-- Tests all use the same framework versions -->
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
<PackageVersion Include="MSTest.TestAdapter" Version="4.0.1" />
<PackageVersion Include="MSTest.TestFramework" Version="4.0.1" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageVersion Include="MSTest.TestAdapter" Version="4.0.2" />
<PackageVersion Include="MSTest.TestFramework" Version="4.0.2" />
<PackageVersion Include="Tmds.ExecFunction" Version="0.8.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing" Version="1.1.2" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.CodeFix.Testing" Version="1.1.2" />
Expand Down
22 changes: 11 additions & 11 deletions docfx/ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,12 @@ Since this is generated it is listed in the [.gitignore](#gitignore) file.
These folders (named after the `*` portion of the [api-*](#api-*) folder names contains
manually written additional files, articles, samples etc... related to a given library.

## Guid to wrting XML DOC comments
When dealing with doc comments the XML can get in the way of general readability of the
source code. There is an inherent tension beween how a particular editor renders the docs
for a symbol/method (VS calls this "Quick Info") and how it is rendered in the final
documentation by docfx. This guides general use to simplify things as much as possible.
## Guide to wrting XML DOC comments
When dealing with doc comments the XML can sometimes get in the way of general readability
of the source code. There is an inherent tension beween how a particular editor renders the
docs for a symbol/method (VS calls this "Quick Info") and how it is rendered in the final
documentation by a tool like docfx. This guides general use to simplify things as much as
possible.

### Lists
The largest intrusion of the XML into the source is that of lists. The XML doc comments
Expand Down Expand Up @@ -115,7 +116,6 @@ versus:
/// 3) Act on the results as proper for the application<br/>
/// a. This might include actions parsed but generally isolating the various stages is an easier to understand/maintain model<br/>
/// b. Usually this is just app specific code that uses the bound results to adapt behavior<br/>
///
```

Which one would ***YOU*** rather encounter in code? Which one is easier to understand when
Expand All @@ -126,7 +126,7 @@ should reconsider... :grinning:)
There is little that can be done to alter the rendering of any editor support, at most an
editor might allow specification of a CSS file, but that is the lowest priority of doc
comments. Readability by maintainers of the docs AND the rendering for final docs used by
consumers of of VASTLY higher importance. Still, the editor rendering ***is*** of value to
consumers is of VASTLY higher importance. Still, the editor rendering ***is*** of value to
maintainers so should not be forgotten as it can make a "right mess of things" even if they
render properly in final docs.

Expand All @@ -135,8 +135,8 @@ render properly in final docs.
a) Doing so will break the docfx rendering that allows for markdown lists
2) Use `</br>' tags to indicate a line break. This is used by the editor rendering to mark
the end of a line and start a new one. (Stops auto reflow)
3) Accept that the in edotr rendering might "trim" the lines it shows, eliminating any
indentation.
3) Accept that the in editor rendering might "trim" the lines it shows, eliminating any
indentation. [Grrr... Looking at you VS!]
a) Sadly, there is no avoiding this. Addition of any sort of "markup" to control that
will interfere with the readability AND the final docs rendering.
4) Always use a different numbering style for sub lists/items
Expand All @@ -147,6 +147,6 @@ render properly in final docs.
API signaure and parameter info. Different editors may allow control of that.
i) In VS [2019|2022] for C# it is controlled by
`Text Editor > C# > Advanced > Editor Help: "Show remarks in Quick Info."`
ii) Turning this off can greatly reduce the noise AND reduce the problems of
different rende
1) Turning this off can greatly reduce the noise AND reduce the problems of
different rendering as lists are generally not used in the other elements.

6 changes: 6 additions & 0 deletions src/Interop/Ubiquity.NET.Llvm.Interop/Library.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ public static ILibLlvm InitializeLLVM( )
}

// Verify the version of LibLLVM.
string verString = LibLLVMGetVersion()?.ToString() ?? string.Empty;
if(string.IsNullOrWhiteSpace(verString))
{
throw new InvalidOperationException("Internal error: LLVM reported an empty string for version!");
}

var libVersion = SemVer.Parse(LibLLVMGetVersion()?.ToString() ?? string.Empty, SemVerFormatProvider.CaseInsensitive);
if( libVersion is CSemVerCI semVerCI)
{
Expand Down
32 changes: 27 additions & 5 deletions src/Samples/CodeGenWithDebugInfo/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,35 @@ public static void Main( string[] args )
, constArray
);

var bar = module.AddGlobal( fooType, false, 0, barValue, "bar" );
var bar = module.AddGlobal( fooType, false, 0, barValue, "bar"u8 );
bar.Alignment = module.Layout.AbiAlignmentOf( fooType );
bar.AddDebugInfo( diBuilder.CreateGlobalVariableExpression( compilationUnit, "bar", string.Empty, diFile, 8, fooType.DebugInfoType, false, null ) );

var baz = module.AddGlobal( fooType, false, Linkage.Common, Constant.NullValueFor( fooType ), "baz" );
bar.AddDebugInfo(
diBuilder.CreateGlobalVariableExpression(
compilationUnit,
"bar"u8,
linkageName: string.Empty,
diFile,
lineNo: 8,
fooType.DebugInfoType,
isLocalToUnit: false,
value: null
)
);

var baz = module.AddGlobal( fooType, false, Linkage.Common, Constant.NullValueFor( fooType ), "baz"u8 );
baz.Alignment = module.Layout.AbiAlignmentOf( fooType );
baz.AddDebugInfo( diBuilder.CreateGlobalVariableExpression( compilationUnit, "baz", string.Empty, diFile, 9, fooType.DebugInfoType, false, null ) );
baz.AddDebugInfo(
diBuilder.CreateGlobalVariableExpression(
compilationUnit,
"baz"u8,
linkageName: string.Empty,
diFile,
lineNo: 9,
fooType.DebugInfoType,
isLocalToUnit: false,
value: null
)
);

// add module flags and compiler identifiers...
// this can technically occur at any point, though placing it here makes
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) Ubiquity.NET Contributors. All rights reserved.
// Licensed under the Apache-2.0 WITH LLVM-exception license. See the LICENSE.md file in the project root for full license information.

// Mostly from https://github.com/Sergio0694/PolySharp/blob/main/src/PolySharp.SourceGenerators/Extensions/AnalyzerConfigOptionsProviderExtensions.cs
// Reformatted and made to conform to repo guides

namespace Ubiquity.NET.CodeAnalysis.Utils
{
/// <summary>Extension methods for the <see cref="AnalyzerConfigOptionsProvider"/> type.</summary>
public static class AnalyzerConfigOptionsProviderExtensions
{
/// <summary>Checks whether the input property has a valid <see cref="bool"/> value.</summary>
/// <param name="options">The input <see cref="AnalyzerConfigOptionsProvider"/> instance.</param>
/// <param name="propertyName">The Build property name.</param>
/// <param name="propertyValue">The resulting property value, if invalid.</param>
/// <returns>Whether the target property is a valid <see cref="bool"/> value.</returns>
public static bool IsValidBoolBuildProperty(
this AnalyzerConfigOptionsProvider options,
string propertyName,
[NotNullWhen( false )] out string? propertyValue
)
{
return !options.GlobalOptions.TryGetValue( $"{BuildProperty}.{propertyName}", out propertyValue )
|| string.IsNullOrEmpty( propertyValue )
|| string.Equals( propertyValue, bool.TrueString, StringComparison.OrdinalIgnoreCase )
|| string.Equals( propertyValue, bool.FalseString, StringComparison.OrdinalIgnoreCase );
}

/// <summary>Gets the value of a <see cref="bool"/> build property.</summary>
/// <param name="options">The input <see cref="AnalyzerConfigOptionsProvider"/> instance.</param>
/// <param name="propertyName">The build property name.</param>
/// <returns>The value of the specified build property.</returns>
/// <remarks>
/// The return value is equivalent to a (case insensitive) <c>'$(PropertyName)' == 'true'</c> check.
/// That is, any other value, including empty/not present, is considered <see langword="true"/>.
/// </remarks>
public static bool GetBoolBuildProperty( this AnalyzerConfigOptionsProvider options, string propertyName )
{
return options.GlobalOptions.TryGetValue( $"{BuildProperty}.{propertyName}", out string? propertyValue )
&& string.Equals( propertyValue, bool.TrueString, StringComparison.OrdinalIgnoreCase );
}

/// <summary>Gets the value of a Build property representing a semicolon-separated list of strings.</summary>
/// <param name="options">The input <see cref="AnalyzerConfigOptionsProvider"/> instance.</param>
/// <param name="propertyName">The build property name.</param>
/// <returns>The value of the specified build property.</returns>
public static ImmutableArray<string> GetStringArrayBuildProperty( this AnalyzerConfigOptionsProvider options, string propertyName )
{
return options.GlobalOptions.TryGetValue( $"{BuildProperty}.{propertyName}", out string? propertyValue )
? [ .. propertyValue.Split( ',', ';' ) ]
: [];
}

// MSBuild properties that are visible to the compiler are available with the "build_property." prefix
// See: https://andrewlock.net/creating-a-source-generator-part-13-providing-and-accessing-msbuild-settings-in-source-generators/
private const string BuildProperty = "build_property";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright (c) Ubiquity.NET Contributors. All rights reserved.
// Licensed under the Apache-2.0 WITH LLVM-exception license. See the LICENSE.md file in the project root for full license information.

namespace Ubiquity.NET.CodeAnalysis.Utils
{
/// <summary>Utility type to provide extensions for <see cref="BaseTypeDeclarationSyntax"/></summary>
public static class BaseTypeDeclarationSyntaxExtensions
{
// The following 2 extension methods are based on:
// https://andrewlock.net/creating-a-source-generator-part-5-finding-a-type-declarations-namespace-and-type-hierarchy/

/// <summary>Gets the declared namespace for a <see cref="BaseTypeDeclarationSyntax"/></summary>
/// <param name="syntax">Syntax to get the namespace for</param>
/// <returns>Namespace of <paramref name="syntax"/></returns>
public static string GetDeclaredNamespace(this BaseTypeDeclarationSyntax syntax)
{
// If we don't have a namespace at all we'll return an empty string
// This accounts for the "default namespace" case
string nameSpace = string.Empty;

// Get the containing syntax node for the type declaration
// (could be a nested type, for example)
SyntaxNode? potentialNamespaceParent = syntax.Parent;

// Keep moving "out" of nested classes etc until we get to a namespace
// or until we run out of parents
while (potentialNamespaceParent != null
&& potentialNamespaceParent is not NamespaceDeclarationSyntax
&& potentialNamespaceParent is not FileScopedNamespaceDeclarationSyntax)
{
potentialNamespaceParent = potentialNamespaceParent.Parent;
}

// Build up the final namespace by looping until we no longer have a namespace declaration
if (potentialNamespaceParent is BaseNamespaceDeclarationSyntax namespaceParent)
{
// We have a namespace. Use that as the type
nameSpace = namespaceParent.Name.ToString();

// Keep moving "out" of the namespace declarations until there
// are no more nested namespace declarations.
while (true)
{
if (namespaceParent.Parent is not NamespaceDeclarationSyntax parent)
{
break;
}

// Add the outer namespace as a prefix to the final namespace
nameSpace = $"{namespaceParent.Name}.{nameSpace}";
namespaceParent = parent;
}
}

// return the final namespace
return nameSpace;
}

/// <summary>Gets the nested class name for a <see cref="BaseTypeDeclarationSyntax"/></summary>
/// <param name="syntax">Syntax to get the name for</param>
/// <param name="includeSelf">Flag to indicate if the type itself is included in the name [Default: <see langword="false"/></param>
/// <returns><see cref="NestedClassName"/> of the syntax or <see langword="null"/></returns>
public static NestedClassName? GetNestedClassName( this BaseTypeDeclarationSyntax syntax, bool includeSelf = false)
{
// Try and get the parent syntax. If it isn't a type like class/struct, this will be null
TypeDeclarationSyntax? parentSyntax = includeSelf ? syntax as TypeDeclarationSyntax : syntax.Parent as TypeDeclarationSyntax;
NestedClassName? parentClassInfo = null;

// We can only be nested in class/struct/record

// Keep looping while we're in a supported nested type
while (parentSyntax is not null)
{
// NOTE: due to bug https://github.com/dotnet/roslyn/issues/78042 this
// is not using a local static function to evaluate this in the condition
// of the while loop [Workaround: go back to "old" extension syntax...]
var rawKind = parentSyntax.Kind();
bool isAllowedKind
= rawKind == SyntaxKind.ClassDeclaration
|| rawKind == SyntaxKind.StructDeclaration
|| rawKind == SyntaxKind.RecordDeclaration;

if (!isAllowedKind)
{
break;
}

// Record the parent type keyword (class/struct etc), name, and constraints
parentClassInfo = new NestedClassName(
keyword: parentSyntax.Keyword.ValueText,
name: parentSyntax.Identifier.ToString() + parentSyntax.TypeParameterList,
constraints: parentSyntax.ConstraintClauses.ToString(),
children: parentClassInfo is null ? [] : [parentClassInfo]); // set the child link (null initially)

// Move to the next outer type
parentSyntax = parentSyntax.Parent as TypeDeclarationSyntax;
}

// return a link to the outermost parent type
return parentClassInfo;
}
}
}
Loading
Loading