From 63c86b8421f40474d382bd329981c8673cc3b44d Mon Sep 17 00:00:00 2001 From: Carl de Billy Date: Wed, 30 Jun 2021 09:23:37 -0400 Subject: [PATCH 1/2] chore: Update GitHub links --- doc/Class Lifecycle Generation.md | 2 +- doc/Immutable Generation.md | 2 +- readme.md | 2 +- .../Uno.ClassLifecycle.csproj | 8 +++++--- .../ClassLifecycleGenerator.cs | 2 +- .../Uno.CodeGen.ClassLifecycle.csproj | 8 +++++--- src/Uno.CodeGen/EqualityGenerator.cs | 4 ++-- src/Uno.CodeGen/ImmutableGenerator.cs | 2 +- src/Uno.CodeGen/InjectableGenerator.cs | 2 +- src/Uno.CodeGen/Uno.CodeGen.csproj | 8 +++++--- src/Uno.Equality/Uno.Equality.csproj | 8 +++++--- src/Uno.Immutables/Uno.Immutables.csproj | 8 +++++--- src/Uno.Injectable/Uno.Injectable.csproj | 8 +++++--- src/uno.png | Bin 0 -> 10901 bytes 14 files changed, 38 insertions(+), 26 deletions(-) create mode 100644 src/uno.png diff --git a/doc/Class Lifecycle Generation.md b/doc/Class Lifecycle Generation.md index cce3508..311cebc 100644 --- a/doc/Class Lifecycle Generation.md +++ b/doc/Class Lifecycle Generation.md @@ -28,7 +28,7 @@ } ``` -1. Compile ([the generation process occurs at compile time](https://github.com/nventive/Uno.SourceGeneration/issues/9)). +1. Compile ([the generation process occurs at compile time](https://github.com/unoplatform/Uno.SourceGeneration/issues/9)). 1. It will generate the following public methods for you: ``` csharp partial class MyClass : IDisposable diff --git a/doc/Immutable Generation.md b/doc/Immutable Generation.md index 6b88135..1426822 100644 --- a/doc/Immutable Generation.md +++ b/doc/Immutable Generation.md @@ -255,7 +255,7 @@ The generated code will produce the following effect: ``` > For more information on the `Uno.Core` package: -> * On Github: +> * On Github: > * On Nuget: # FAQ diff --git a/readme.md b/readme.md index b3766b4..1147fb7 100644 --- a/readme.md +++ b/readme.md @@ -60,7 +60,7 @@ Features: # Have questions? Feature requests? Issues? -Make sure to visit our [FAQ](doc/faq.md), [StackOverflow](https://stackoverflow.com/questions/tagged/uno-platform), [create an issue](https://github.com/nventive/Uno.CodeGen/issues) or [visit our gitter](https://gitter.im/uno-platform/Lobby). +Make sure to visit our [FAQ](doc/faq.md), [StackOverflow](https://stackoverflow.com/questions/tagged/uno-platform), [create an issue](https://github.com/unoplatform/Uno.CodeGen/issues) or [visit our gitter](https://gitter.im/uno-platform/Lobby). # Contributing diff --git a/src/Uno.ClassLifecycle/Uno.ClassLifecycle.csproj b/src/Uno.ClassLifecycle/Uno.ClassLifecycle.csproj index 553ee7f..394835a 100644 --- a/src/Uno.ClassLifecycle/Uno.ClassLifecycle.csproj +++ b/src/Uno.ClassLifecycle/Uno.ClassLifecycle.csproj @@ -15,9 +15,9 @@ This package is part of the Uno.CodeGen to generate object life cycle methods in Uno bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml Copyright (C) 2015-2018 nventive inc. - all rights reserved - https://github.com/nventive/Uno.CodeGen - https://github.com/nventive/Uno.CodeGen - https://nv-assets.azurewebsites.net/logos/uno.png + https://github.com/unoplatform/Uno.CodeGen + https://github.com/unoplatform/Uno.CodeGen + uno.png @@ -27,5 +27,7 @@ This package is part of the Uno.CodeGen to generate object life cycle methods in all runtime; build; native; contentfiles; analyzers + + diff --git a/src/Uno.CodeGen.ClassLifecycle/ClassLifecycleGenerator.cs b/src/Uno.CodeGen.ClassLifecycle/ClassLifecycleGenerator.cs index 55da4b5..a0d8f18 100644 --- a/src/Uno.CodeGen.ClassLifecycle/ClassLifecycleGenerator.cs +++ b/src/Uno.CodeGen.ClassLifecycle/ClassLifecycleGenerator.cs @@ -124,7 +124,7 @@ private void Generate(LifecycleMethods methods) { writer.WriteLine("// "); writer.WriteLine("// ***************************************************************************************************************************"); - writer.WriteLine("// This file has been generated by Uno.CodeGen (ClassLifecycleGenerator), available at https://github.com/nventive/Uno.CodeGen"); + writer.WriteLine("// This file has been generated by Uno.CodeGen (ClassLifecycleGenerator), available at https://github.com/unoplatform/Uno.CodeGen"); writer.WriteLine("// ***************************************************************************************************************************"); writer.WriteLine("// "); writer.WriteLine("#pragma warning disable"); diff --git a/src/Uno.CodeGen.ClassLifecycle/Uno.CodeGen.ClassLifecycle.csproj b/src/Uno.CodeGen.ClassLifecycle/Uno.CodeGen.ClassLifecycle.csproj index 138a786..445a295 100644 --- a/src/Uno.CodeGen.ClassLifecycle/Uno.CodeGen.ClassLifecycle.csproj +++ b/src/Uno.CodeGen.ClassLifecycle/Uno.CodeGen.ClassLifecycle.csproj @@ -15,9 +15,9 @@ This package is part of the Uno.CodeGen to generate classes lifecycle methods in your project. Uno Copyright (C) 2015-2018 nventive inc. - all rights reserved - https://github.com/nventive/Uno.CodeGen - https://github.com/nventive/Uno.CodeGen - https://nv-assets.azurewebsites.net/logos/uno.png + https://github.com/unoplatform/Uno.CodeGen + https://github.com/unoplatform/Uno.CodeGen + uno.png @@ -48,6 +48,8 @@ This package is part of the Uno.CodeGen to generate classes lifecycle methods in true build + + diff --git a/src/Uno.CodeGen/EqualityGenerator.cs b/src/Uno.CodeGen/EqualityGenerator.cs index 242a16a..9367848 100644 --- a/src/Uno.CodeGen/EqualityGenerator.cs +++ b/src/Uno.CodeGen/EqualityGenerator.cs @@ -153,7 +153,7 @@ private void GenerateEquality(INamedTypeSymbol typeSymbol) builder.AppendLineInvariant("// "); builder.AppendLineInvariant("// **********************************************************************************************************************"); - builder.AppendLineInvariant("// This file has been generated by Uno.CodeGen (ImmutableGenerator), available at https://github.com/nventive/Uno.CodeGen"); + builder.AppendLineInvariant("// This file has been generated by Uno.CodeGen (ImmutableGenerator), available at https://github.com/unoplatform/Uno.CodeGen"); builder.AppendLineInvariant("// **********************************************************************************************************************"); builder.AppendLineInvariant("// "); builder.AppendLineInvariant("#pragma warning disable"); @@ -618,7 +618,7 @@ private void GenerateHashLogic(INamedTypeSymbol typeSymbol, IndentedStringBuilde Warning( builder, "There is no members marked with [Uno.EqualityHash] or [Uno.EqualityKey]. " + - "You should add at least one. Documentation: https://github.com/nventive/Uno.CodeGen/blob/master/doc/Equality%20Generation.md"); + "You should add at least one. Documentation: https://github.com/unoplatform/Uno.CodeGen/blob/master/doc/Equality%20Generation.md"); builder.AppendLineInvariant("return 0; // no members to compute hash"); } diff --git a/src/Uno.CodeGen/ImmutableGenerator.cs b/src/Uno.CodeGen/ImmutableGenerator.cs index 79c890c..4e9ed66 100644 --- a/src/Uno.CodeGen/ImmutableGenerator.cs +++ b/src/Uno.CodeGen/ImmutableGenerator.cs @@ -263,7 +263,7 @@ private void GenerateImmutable(INamedTypeSymbol typeSymbol, builder.AppendLineInvariant("// "); builder.AppendLineInvariant("// **********************************************************************************************************************"); - builder.AppendLineInvariant("// This file has been generated by Uno.CodeGen (ImmutableGenerator), available at https://github.com/nventive/Uno.CodeGen"); + builder.AppendLineInvariant("// This file has been generated by Uno.CodeGen (ImmutableGenerator), available at https://github.com/unoplatform/Uno.CodeGen"); builder.AppendLineInvariant("// **********************************************************************************************************************"); builder.AppendLineInvariant("// "); builder.AppendLineInvariant("#pragma warning disable"); diff --git a/src/Uno.CodeGen/InjectableGenerator.cs b/src/Uno.CodeGen/InjectableGenerator.cs index 7111f87..4336bc3 100644 --- a/src/Uno.CodeGen/InjectableGenerator.cs +++ b/src/Uno.CodeGen/InjectableGenerator.cs @@ -65,7 +65,7 @@ private void GenerateInjectable((INamedTypeSymbol type, IEnumerable<(ISymbol mem builder.AppendLineInvariant("// "); builder.AppendLineInvariant("// **************************************************************(********************************************************"); - builder.AppendLineInvariant("// This file has been generated by Uno.CodeGen (InjectableGenerator), available at https://github.com/nventive/Uno.CodeGen"); + builder.AppendLineInvariant("// This file has been generated by Uno.CodeGen (InjectableGenerator), available at https://github.com/unoplatform/Uno.CodeGen"); builder.AppendLineInvariant("// ***********************************************************************************************************************"); builder.AppendLineInvariant("// "); builder.AppendLineInvariant("#pragma warning disable"); diff --git a/src/Uno.CodeGen/Uno.CodeGen.csproj b/src/Uno.CodeGen/Uno.CodeGen.csproj index f2cfa26..6df42b0 100644 --- a/src/Uno.CodeGen/Uno.CodeGen.csproj +++ b/src/Uno.CodeGen/Uno.CodeGen.csproj @@ -9,11 +9,11 @@ bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml nventive nventive - https://github.com/nventive/Uno.CodeGen - https://nv-assets.azurewebsites.net/logos/uno.png - https://github.com/nventive/Uno.CodeGen + https://github.com/unoplatform/Uno.CodeGen + https://github.com/unoplatform/Uno.CodeGen This package provides tooling for code generation. Copyright (C) 2015-2018 nventive inc. - all rights reserved + uno.png @@ -45,6 +45,8 @@ true build + + diff --git a/src/Uno.Equality/Uno.Equality.csproj b/src/Uno.Equality/Uno.Equality.csproj index efddefe..09384e5 100644 --- a/src/Uno.Equality/Uno.Equality.csproj +++ b/src/Uno.Equality/Uno.Equality.csproj @@ -15,9 +15,9 @@ This package is part of the Uno.CodeGen to generate equality members in your pro Uno.Equality bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml Copyright (C) 2015-2018 nventive inc. - all rights reserved - https://github.com/nventive/Uno.CodeGen - https://github.com/nventive/Uno.CodeGen - https://nv-assets.azurewebsites.net/logos/uno.png + https://github.com/unoplatform/Uno.CodeGen + https://github.com/unoplatform/Uno.CodeGen + uno.png @@ -27,6 +27,8 @@ This package is part of the Uno.CodeGen to generate equality members in your pro all runtime; build; native; contentfiles; analyzers + + diff --git a/src/Uno.Immutables/Uno.Immutables.csproj b/src/Uno.Immutables/Uno.Immutables.csproj index 8f8914d..5a3701b 100644 --- a/src/Uno.Immutables/Uno.Immutables.csproj +++ b/src/Uno.Immutables/Uno.Immutables.csproj @@ -14,10 +14,10 @@ This package is part of the Uno.CodeGen to generate immutable entities in your project. Uno bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml - https://github.com/nventive/Uno.CodeGen - https://github.com/nventive/Uno.CodeGen - https://nv-assets.azurewebsites.net/logos/uno.png + https://github.com/unoplatform/Uno.CodeGen + https://github.com/unoplatform/Uno.CodeGen Copyright (C) 2015-2018 nventive inc. - all rights reserved + uno.png @@ -28,6 +28,8 @@ This package is part of the Uno.CodeGen to generate immutable entities in your p all runtime; build; native; contentfiles; analyzers + + diff --git a/src/Uno.Injectable/Uno.Injectable.csproj b/src/Uno.Injectable/Uno.Injectable.csproj index 7150fa1..656a875 100644 --- a/src/Uno.Injectable/Uno.Injectable.csproj +++ b/src/Uno.Injectable/Uno.Injectable.csproj @@ -14,10 +14,10 @@ This package is part of the Uno.CodeGen to generate injectable entities in your project. Uno bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml - https://github.com/nventive/Uno.CodeGen - https://github.com/nventive/Uno.CodeGen - https://nv-assets.azurewebsites.net/logos/uno.png + https://github.com/unoplatform/Uno.CodeGen + https://github.com/unoplatform/Uno.CodeGen Copyright (C) 2015-2018 nventive inc. - all rights reserved + uno.png @@ -27,6 +27,8 @@ This package is part of the Uno.CodeGen to generate injectable entities in your all runtime; build; native; contentfiles; analyzers + + diff --git a/src/uno.png b/src/uno.png new file mode 100644 index 0000000000000000000000000000000000000000..7b9b432a6398d1856ff8e51cac3ab1debebc8f7f GIT binary patch literal 10901 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 Q0pLD06>a4zr8lAf2X3|zyZ`_I literal 0 HcmV?d00001 From ccd74d14833c650bd66e1c517ed5b2c5508eef30 Mon Sep 17 00:00:00 2001 From: Carl de Billy Date: Wed, 30 Jun 2021 09:25:13 -0400 Subject: [PATCH 2/2] WIP - Trying to update to a more recent version of SourceGen... --- .../Uno.ClassLifecycle.csproj | 2 +- .../Uno.CodeGen.ClassLifecycle.csproj | 99 +-- .../Extensions/DisposableAction.cs | 42 ++ .../Extensions/IIndentedStringBuilder.cs | 74 +++ .../Extensions/IndentedStringBuilder.cs | 98 +++ .../IndentedStringBuilderExtensions.cs | 58 ++ .../Extensions/StringExtensions.cs | 35 ++ .../Helpers/CyclomaticComplexityWalker.cs | 134 +++++ .../Helpers/ExtendedSyntaxType.cs | 362 +++++++++++ .../Helpers/SyntaxSymbolPairing.cs | 55 ++ .../CodeAnalysis/MethodSymbolExtensions.cs | 275 +++++++++ .../CodeAnalysis/SymbolExtensions.cs | 398 ++++++++++++ .../CodeAnalysis/SyntaxNodeExtensions.cs | 540 +++++++++++++++++ .../TypeParameterSymbolExtensions.cs | 104 ++++ .../CodeAnalysis/TypeSymbolExtensions.cs | 567 ++++++++++++++++++ .../Uno.CodeGen.RoslynHelpers.projitems | 26 + .../Uno.CodeGen.RoslynHelpers.shproj | 13 + .../Uno.CodeGen.Tests.ExternalClasses.csproj | 6 +- .../Uno.CodeGen.Tests.JsonDisabled.csproj | 4 +- .../Uno.CodeGen.Tests.MinimalDeps.csproj | 2 +- .../Uno.CodeGen.Tests.csproj | 99 +-- src/Uno.CodeGen.sln | 10 +- src/Uno.CodeGen/Uno.CodeGen.csproj | 12 +- src/Uno.Equality/Uno.Equality.csproj | 48 +- src/Uno.Immutables/Uno.Immutables.csproj | 54 +- src/Uno.Injectable/Uno.Injectable.csproj | 46 +- 26 files changed, 2980 insertions(+), 183 deletions(-) create mode 100644 src/Uno.CodeGen.RoslynHelpers/Extensions/DisposableAction.cs create mode 100644 src/Uno.CodeGen.RoslynHelpers/Extensions/IIndentedStringBuilder.cs create mode 100644 src/Uno.CodeGen.RoslynHelpers/Extensions/IndentedStringBuilder.cs create mode 100644 src/Uno.CodeGen.RoslynHelpers/Extensions/IndentedStringBuilderExtensions.cs create mode 100644 src/Uno.CodeGen.RoslynHelpers/Extensions/StringExtensions.cs create mode 100644 src/Uno.CodeGen.RoslynHelpers/Helpers/CyclomaticComplexityWalker.cs create mode 100644 src/Uno.CodeGen.RoslynHelpers/Helpers/ExtendedSyntaxType.cs create mode 100644 src/Uno.CodeGen.RoslynHelpers/Helpers/SyntaxSymbolPairing.cs create mode 100644 src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/MethodSymbolExtensions.cs create mode 100644 src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/SymbolExtensions.cs create mode 100644 src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/SyntaxNodeExtensions.cs create mode 100644 src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/TypeParameterSymbolExtensions.cs create mode 100644 src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/TypeSymbolExtensions.cs create mode 100644 src/Uno.CodeGen.RoslynHelpers/Uno.CodeGen.RoslynHelpers.projitems create mode 100644 src/Uno.CodeGen.RoslynHelpers/Uno.CodeGen.RoslynHelpers.shproj diff --git a/src/Uno.ClassLifecycle/Uno.ClassLifecycle.csproj b/src/Uno.ClassLifecycle/Uno.ClassLifecycle.csproj index 394835a..0cf72d0 100644 --- a/src/Uno.ClassLifecycle/Uno.ClassLifecycle.csproj +++ b/src/Uno.ClassLifecycle/Uno.ClassLifecycle.csproj @@ -23,7 +23,7 @@ This package is part of the Uno.CodeGen to generate object life cycle methods in - + all runtime; build; native; contentfiles; analyzers diff --git a/src/Uno.CodeGen.ClassLifecycle/Uno.CodeGen.ClassLifecycle.csproj b/src/Uno.CodeGen.ClassLifecycle/Uno.CodeGen.ClassLifecycle.csproj index 445a295..9f8794f 100644 --- a/src/Uno.CodeGen.ClassLifecycle/Uno.CodeGen.ClassLifecycle.csproj +++ b/src/Uno.CodeGen.ClassLifecycle/Uno.CodeGen.ClassLifecycle.csproj @@ -1,59 +1,64 @@ - + net461;netstandard1.3;netstandard2.0 - true - Generator of class lifecycle - true - True - - full - True - nventive - nventive + true + Generator of class lifecycle + true + True + + full + True + nventive + nventive This package provides a generator which generates the class life cycle method using the attributes from Uno.ClassLifecycle. This package is part of the Uno.CodeGen to generate classes lifecycle methods in your project. - Uno - Copyright (C) 2015-2018 nventive inc. - all rights reserved + Uno + Copyright (C) 2015-2018 nventive inc. - all rights reserved https://github.com/unoplatform/Uno.CodeGen https://github.com/unoplatform/Uno.CodeGen uno.png - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers - - - NU1701 - - - - - - - - - - - true - build - + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + NU1701 + + + + + + + + + + + true + build + - + + + + + - - - - diff --git a/src/Uno.CodeGen.RoslynHelpers/Extensions/DisposableAction.cs b/src/Uno.CodeGen.RoslynHelpers/Extensions/DisposableAction.cs new file mode 100644 index 0000000..c22df97 --- /dev/null +++ b/src/Uno.CodeGen.RoslynHelpers/Extensions/DisposableAction.cs @@ -0,0 +1,42 @@ +// ****************************************************************** +// Copyright � 2015-2018 nventive inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ****************************************************************** +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Uno.RoslynHelpers +{ + internal partial class DisposableAction : IDisposable + { + public DisposableAction(Action action) + { + Action = action; + } + + public Action Action { get; private set; } + + #region IDisposable Members + + public void Dispose() + { + Action(); + } + + #endregion + } +} diff --git a/src/Uno.CodeGen.RoslynHelpers/Extensions/IIndentedStringBuilder.cs b/src/Uno.CodeGen.RoslynHelpers/Extensions/IIndentedStringBuilder.cs new file mode 100644 index 0000000..ca113a4 --- /dev/null +++ b/src/Uno.CodeGen.RoslynHelpers/Extensions/IIndentedStringBuilder.cs @@ -0,0 +1,74 @@ +// ****************************************************************** +// Copyright � 2015-2018 nventive inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ****************************************************************** +using System; + +namespace Uno.RoslynHelpers +{ + internal partial interface IIndentedStringBuilder + { + /// + /// Gets the current indentation level + /// + int CurrentLevel { get; } + + /// + /// Appends text using the current indentation level + /// + /// + void Append(string text); + + /// + /// Appends formatted text using the current indentation level + /// + void AppendFormat(IFormatProvider formatProvider, string pattern, params object[] replacements); + + /// + /// Appends a line using the current indentation level + /// + void AppendLine(); + + /// + /// Writes the provided text and adds line using the current indentation level + /// + void AppendLine(string text); + + /// + /// Creates an indentation block + /// + /// The indentation level of the new block. + /// A disposable that will close the block + IDisposable Block(int count = 1); + + /// + /// Creates an indentation block, e.g. using a C# curly braces. + /// + /// A disposable that will close the block + IDisposable Block(IFormatProvider formatProvider, string pattern, params object[] parameters); + + /// + /// Adds an indentation + /// + /// + /// + IDisposable Indent(int count = 1); + + /// + /// Provides a string representing the complete builder. + /// + string ToString(); + } +} \ No newline at end of file diff --git a/src/Uno.CodeGen.RoslynHelpers/Extensions/IndentedStringBuilder.cs b/src/Uno.CodeGen.RoslynHelpers/Extensions/IndentedStringBuilder.cs new file mode 100644 index 0000000..5fff3c4 --- /dev/null +++ b/src/Uno.CodeGen.RoslynHelpers/Extensions/IndentedStringBuilder.cs @@ -0,0 +1,98 @@ +// ****************************************************************** +// Copyright � 2015-2018 nventive inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ****************************************************************** +using System; +using System.Collections.Generic; +using System.Text; + +namespace Uno.RoslynHelpers +{ + /// + /// A C# code indented builder. + /// + internal partial class IndentedStringBuilder : IIndentedStringBuilder + { + private readonly StringBuilder _stringBuilder; + + public int CurrentLevel { get; private set; } + + public IndentedStringBuilder() + : this(new StringBuilder()) + { + } + + public IndentedStringBuilder(StringBuilder stringBuilder) + { + _stringBuilder = stringBuilder; + } + + public virtual IDisposable Indent(int count = 1) + { + CurrentLevel += count; + return new DisposableAction(() => CurrentLevel -= count); + } + + public virtual IDisposable Block(int count = 1) + { + var current = CurrentLevel; + + CurrentLevel += count; + Append("{".Indent(current)); + AppendLine(); + + return new DisposableAction(() => + { + CurrentLevel -= count; + Append("}".Indent(current)); + AppendLine(); + }); + } + + public virtual IDisposable Block(IFormatProvider formatProvider, string pattern, params object[] parameters) + { + AppendFormat(formatProvider, pattern, parameters); + AppendLine(); + + return Block(); + } + + public virtual void Append(string text) + { + _stringBuilder.Append(text); + } + + public virtual void AppendFormat(IFormatProvider formatProvider, string pattern, params object[] replacements) + { + _stringBuilder.AppendFormat(formatProvider, pattern.Indent(CurrentLevel), replacements); + } + + public virtual void AppendLine() + { + _stringBuilder.AppendLine(); + } + + public virtual void AppendLine(string text) + { + _stringBuilder.Append(text.Indent(CurrentLevel)); + } + + public override string ToString() + { + return _stringBuilder.ToString(); + } + } + +} diff --git a/src/Uno.CodeGen.RoslynHelpers/Extensions/IndentedStringBuilderExtensions.cs b/src/Uno.CodeGen.RoslynHelpers/Extensions/IndentedStringBuilderExtensions.cs new file mode 100644 index 0000000..68acbe2 --- /dev/null +++ b/src/Uno.CodeGen.RoslynHelpers/Extensions/IndentedStringBuilderExtensions.cs @@ -0,0 +1,58 @@ +// ****************************************************************** +// Copyright � 2015-2018 nventive inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ****************************************************************** +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; + +namespace Uno.RoslynHelpers +{ + internal static partial class IndentedStringBuilderExtensions + { + public static void AppendLine(this IIndentedStringBuilder builder, IFormatProvider formatProvider, string pattern, params object[] replacements) + { + builder.AppendFormat(formatProvider, pattern, replacements); + builder.AppendLine(); + } + + public static void AppendLine(this IIndentedStringBuilder builder, IFormatProvider formatProvider, int indentLevel, string pattern, params object[] replacements) + { + builder.AppendFormat(formatProvider, pattern.Indent(indentLevel), replacements); + builder.AppendLine(); + } + + public static void AppendLineInvariant(this IIndentedStringBuilder builder, string pattern, params object[] replacements) + { + builder.AppendLine(CultureInfo.InvariantCulture, pattern, replacements); + } + + public static void AppendLineInvariant(this IIndentedStringBuilder builder, int indentLevel, string pattern, params object[] replacements) + { + builder.AppendLine(CultureInfo.InvariantCulture, indentLevel, pattern, replacements); + } + + public static void AppendFormatInvariant(this IIndentedStringBuilder builder, string pattern, params object[] replacements) + { + builder.AppendFormat(CultureInfo.InvariantCulture, pattern, replacements); + } + + public static IDisposable BlockInvariant(this IIndentedStringBuilder builder, string pattern, params object[] parameters) + { + return builder.Block(CultureInfo.InvariantCulture, pattern, parameters); + } + } +} diff --git a/src/Uno.CodeGen.RoslynHelpers/Extensions/StringExtensions.cs b/src/Uno.CodeGen.RoslynHelpers/Extensions/StringExtensions.cs new file mode 100644 index 0000000..7b2e312 --- /dev/null +++ b/src/Uno.CodeGen.RoslynHelpers/Extensions/StringExtensions.cs @@ -0,0 +1,35 @@ +// ****************************************************************** +// Copyright � 2015-2018 nventive inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ****************************************************************** +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Uno.RoslynHelpers +{ + internal static partial class StringExtensions + { + private static readonly Regex _newLineRegex = new Regex(@"^", RegexOptions.Compiled | RegexOptions.Multiline); + + public static string Indent(this string text, int indentCount = 1) + { + return _newLineRegex.Replace(text, new String('\t', indentCount)); + } + } +} diff --git a/src/Uno.CodeGen.RoslynHelpers/Helpers/CyclomaticComplexityWalker.cs b/src/Uno.CodeGen.RoslynHelpers/Helpers/CyclomaticComplexityWalker.cs new file mode 100644 index 0000000..73454ef --- /dev/null +++ b/src/Uno.CodeGen.RoslynHelpers/Helpers/CyclomaticComplexityWalker.cs @@ -0,0 +1,134 @@ +// ****************************************************************** +// Copyright � 2015-2018 nventive inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ****************************************************************** +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Uno.RoslynHelpers.Helpers +{ + public class CyclomaticComplexityWalker : CSharpSyntaxWalker + { + private Dictionary _codeRegionInfos; + private SyntaxNode _currentCodeRegionRoot; + private int _nestingLevel = 0; + private SemanticModel _model; + + public IEnumerable Results { get { return _codeRegionInfos.Values; } } + + public CyclomaticComplexityWalker(SyntaxNode entryNode, SemanticModel model) + { + _codeRegionInfos = new Dictionary(); + _codeRegionInfos[entryNode] = new RegionInfo(entryNode); + _model = model; + } + + + public override void Visit(SyntaxNode node) + { + var priorRegion = _currentCodeRegionRoot; + if (node is MethodDeclarationSyntax) + { + _currentCodeRegionRoot = node; + if (!_codeRegionInfos.ContainsKey(_currentCodeRegionRoot)) + { + _codeRegionInfos[_currentCodeRegionRoot] = new RegionInfo(_currentCodeRegionRoot); + } + } + + bool isSimplePredicate = node.IsExtendedSyntaxOfType(ExtendedSyntaxType.SimplePredicate); + bool isAnonymousFunction = node.IsExtendedSyntaxOfType(ExtendedSyntaxType.AnonymousFunctionExpression); + + if (isAnonymousFunction && _currentCodeRegionRoot != null) + { + if (!IsBuildDefinition(node)) + { + _nestingLevel++; + _codeRegionInfos[_currentCodeRegionRoot].PredicateCount += _nestingLevel; + } + else + { + _codeRegionInfos[_currentCodeRegionRoot].PredicateCount += 1; + } + } + + if (isSimplePredicate && _currentCodeRegionRoot != null) + { + _codeRegionInfos[_currentCodeRegionRoot].PredicateCount += 1; + } + + base.Visit(node); + + if (isAnonymousFunction && !IsBuildDefinition(node)) + { + _nestingLevel--; + } + + _currentCodeRegionRoot = priorRegion; + } + + private bool IsBuildDefinition(SyntaxNode node) + { + var simpleLambda = node as SimpleLambdaExpressionSyntax; + + if (simpleLambda != null) + { + var parameterSymbol = _model.GetDeclaredSymbol(simpleLambda.Parameter); + + var isBuilderType = parameterSymbol?.ToDisplayString()?.EndsWith("Builder"); + + if (isBuilderType ?? false) + { + return true; + } + } + + return false; + } + + private static int Factorial(int input) + { + if (input < 0) + { + throw new ArgumentOutOfRangeException("Factorial is only defined for non-negative integers."); + } + + int answer = 1; + + while (input > 1) + { + answer *= input--; + } + + return answer; + } + + public class RegionInfo + { + public SyntaxNode RegionRoot { get; } + public int PredicateCount { get; set; } + public int CyclomaticComplexity { get { return PredicateCount + 1; } } + + public RegionInfo(SyntaxNode regionRoot) + { + RegionRoot = regionRoot; + } + } + } +} diff --git a/src/Uno.CodeGen.RoslynHelpers/Helpers/ExtendedSyntaxType.cs b/src/Uno.CodeGen.RoslynHelpers/Helpers/ExtendedSyntaxType.cs new file mode 100644 index 0000000..0d484d2 --- /dev/null +++ b/src/Uno.CodeGen.RoslynHelpers/Helpers/ExtendedSyntaxType.cs @@ -0,0 +1,362 @@ +// ****************************************************************** +// Copyright � 2015-2018 nventive inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ****************************************************************** +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Uno.RoslynHelpers.Helpers +{ + /// + /// Used to provided delegate predicates, wrapped as ExtendedSyntaxType objects, to facilitate the + /// identification of more complex or composite syntax types that do not exist by default. + /// + public class ExtendedSyntaxType + { + public const bool DefaultConsiderParametersAsPotentialTargets = false; + + /// + /// Provides all the potential syntax kinds that define binary expressions. Does not + /// include the various member access expression ("a.b", "a?.b", "a->b") syntax kinds + /// + public static readonly SyntaxKind[] BinaryExpressionSyntaxKinds = + Enum.GetValues(typeof(SyntaxKind)) + .Cast() + .Select(SyntaxFacts.GetBinaryExpression) + .Where(kind => kind != SyntaxKind.None) + .ToArray(); + + private static readonly HashSet _simplePredicateTypes = new HashSet + { + typeof (IfStatementSyntax), + typeof (CaseSwitchLabelSyntax), + typeof (ConditionalExpressionSyntax), + typeof (WhileStatementSyntax), + typeof (ForStatementSyntax), + typeof (DoStatementSyntax) + }; + + private static readonly HashSet _binaryExpressionPredicateConnectors = new HashSet + { + SyntaxKind.LogicalOrExpression, + SyntaxKind.LogicalAndExpression, + SyntaxKind.CoalesceExpression + }; + + private static readonly HashSet _syntaxTypesWithOptionalBlock = new HashSet() + { + typeof(IfStatementSyntax), + typeof(ElseClauseSyntax), + typeof(ForStatementSyntax), + typeof(ForEachStatementSyntax), + typeof(WhileStatementSyntax), + typeof(DoStatementSyntax), + typeof(UsingStatementSyntax), + typeof(SimpleLambdaExpressionSyntax), + typeof(ParenthesizedLambdaExpressionSyntax), + typeof(FixedStatementSyntax), + typeof(LockStatementSyntax) + }; + + #region Delegate declarations + + public delegate bool CheckExtendedSyntaxKindDelegate(SyntaxNode node); + + #endregion + + #region Exposed delegate verification strategies + + public CheckExtendedSyntaxKindDelegate CheckIfExtendedType { get; } + + #endregion + + + #region Util methods + + /// + /// Returns the extended version of the given syntax node, so that it can be used in methods that require extended syntax types + /// + /// The syntax node type + /// The extended syntax version of the given node + public static ExtendedSyntaxType AsExtended() where T : SyntaxNode + { + return new ExtendedSyntaxType(node => node is T); + } + + #endregion + + + #region Exposed extended rules + + /// + /// Indicates if the given node is a loop (for, while, foreach, etc) + /// + public static readonly ExtendedSyntaxType LoopStatementSyntax = new ExtendedSyntaxType(IsLoopStatementSyntax); + + /// + /// Indicates if the given node is returned as part of a "return" statement + /// + public static readonly ExtendedSyntaxType Returned = new ExtendedSyntaxType(IsReturned); + + /// + /// Indicates if the given node is a conditional expression or a binary expression defined with a coalesce (??) operator + /// + public static readonly ExtendedSyntaxType ConditionalOrCoalesce = new ExtendedSyntaxType(IsConditionalOrCoalesce); + + /// + /// Indicates if the given node is a reference boundary, which is to say that it is either a statement, a lambda expression, + /// or the condition of a conditional expression + /// + public static readonly ExtendedSyntaxType ReferenceBoundary = new ExtendedSyntaxType(IsReferenceBoundary); + + /// + /// Indicates if the given node is the condition of a conditional expression + /// + public static readonly ExtendedSyntaxType ConditionInConditionalExpression = new ExtendedSyntaxType(IsNodeConditionInConditionalExpression); + + /// + /// Indicates if the given node is a lambda expression + /// + public static readonly ExtendedSyntaxType LambdaExpression = new ExtendedSyntaxType(IsLambdaExpression); + + /// + /// Indicates if the given node is an anonymous function (either a lambda or an anonymous method) + /// + public static readonly ExtendedSyntaxType AnonymousFunctionExpression = new ExtendedSyntaxType(IsAnonymousFunctionExpression); + + /// + /// Indicates if the given node is a predicate that results in different conditional execution + /// paths when encountered (if statement, loop, binary operators, etc) + /// + public static readonly ExtendedSyntaxType SimplePredicate = new ExtendedSyntaxType(IsSimplePredicate); + public static readonly ExtendedSyntaxType BodiedLambda = new ExtendedSyntaxType(IsBodiedLambda); + + public static readonly ExtendedSyntaxType TakesOptionalBlock = new ExtendedSyntaxType(CanTakeOptionalBlock); + + public static readonly ExtendedSyntaxType VariableAssignmentOrDeclarationTarget = new ExtendedSyntaxType(IsAssignmentOrDeclarationTarget); + public static readonly ExtendedSyntaxType VariableAssignmentOrDeclarationSource = new ExtendedSyntaxType(IsAnonymousFunctionExpression); + + public static readonly ExtendedSyntaxType VariableAssignmentTarget = new ExtendedSyntaxType(IsAssignmentTarget); + public static readonly ExtendedSyntaxType VariableAssignmentSource = new ExtendedSyntaxType(IsAssignmentSource); + public static readonly ExtendedSyntaxType VariableDeclarationTarget = new ExtendedSyntaxType(IsDeclarationTarget); + public static readonly ExtendedSyntaxType VariableDeclarationSource = new ExtendedSyntaxType(IsDeclarationSource); + + #endregion + + protected ExtendedSyntaxType(CheckExtendedSyntaxKindDelegate extendedCheckDelegate) + { + CheckIfExtendedType = extendedCheckDelegate; + } + + #region Extended syntax check predicates + + private static bool IsAnonymousFunctionExpression(SyntaxNode node) + { + return IsLambdaExpression(node) || node.IsSyntaxOfType(); + } + + private static bool IsLoopStatementSyntax(SyntaxNode node) + { + var loopAncestor = + node.FirstAncestorOrSelf() + ?? node.FirstAncestorOrSelf() + ?? node.FirstAncestorOrSelf() + ?? (StatementSyntax)node.FirstAncestorOrSelf(); + + return loopAncestor != null; + } + + private static bool IsConditionalOrCoalesce(SyntaxNode node) + { + return node.IsSyntaxOfType() || node.IsKind(SyntaxKind.CoalesceExpression); + } + + /// + /// Returns true if a node is a 'boundary' in the sense that its ancestors have no direct reference to its descendants. (eg a StatementSyntax, + /// a lambda expression, a ConditionalStatement that the node is on the far left-hand side of, etc.) + /// + /// The syntax node to check. + /// True if the node is a boundary, false otherwise. + private static bool IsReferenceBoundary(SyntaxNode node) + { + return node is StatementSyntax || + IsLambdaExpression(node) || + IsNodeConditionInConditionalExpression(node) || + node is ArgumentListSyntax; + } + + /// + /// Indicates if this node is directly or conditionally returned in the context of its declaration (whether in a lambda or a declared method) + /// + /// The node to check + /// Is the node is an active member of a return statement + private static bool IsReturned(SyntaxNode node) + { + // Checks if the given node is a lambda statement or is a non-lambda method return statement + Func isLambdaOrMethodReturnPredicate = targetNode => + { + return IsLambdaExpression(targetNode) || + (targetNode.Parent.IsSyntaxOfType() && + targetNode.Parent.GetFirstAncestorWhere(ancestor => IsLambdaExpression(targetNode)) == null); + }; + + + if (isLambdaOrMethodReturnPredicate(node.Parent)) + { + return true; + } + + // Get all the ancestors while we haven't encountered a return or a lambda statement, + // skipping over conditional, coalesce, cast, and parenthesized expressions. + var ancestorSyntaxTypesThatCanBeEncountered = new[] + { + ConditionalOrCoalesce, + AsExtended(), + AsExtended() + }; + + var ancestorsUntilReturnOrLambda = node + .Ancestors() + .TakeWhile(ancestor => !isLambdaOrMethodReturnPredicate(ancestor) && + node.IsOneOfThoseExtendedSyntaxTypes(ancestorSyntaxTypesThatCanBeEncountered)); + + var returnOrLambdaAncestorNode = ancestorsUntilReturnOrLambda.LastOrDefault()?.Parent; + + // Get what is returned + // ReturnStatementSyntax: return + // SimpleLambdaExpressionSyntax: () => + // ParenthesizedLambdaExpressionSyntax: () => { return } + SyntaxNode returnedTarget; + if (returnOrLambdaAncestorNode.IsSyntaxOfType()) + { + returnedTarget = returnOrLambdaAncestorNode + .GetAsSyntaxOfType() + .Expression; + } + else if (node.IsSyntaxOfType()) + { + returnedTarget = returnOrLambdaAncestorNode + .GetAsSyntaxOfType() + .Body + ?.GetAsSyntaxOfType() + ?.Expression; + } + else if (node.IsSyntaxOfType()) + { + returnedTarget = returnOrLambdaAncestorNode + .GetAsSyntaxOfType() + .Body + .GetAsSyntaxOfType() + .Statements + .FirstOrDefault(); + } + else + { + return false; + } + + // One final check to see if the returned target is not a condition of a conditional expression (in which case it is not returned) + return returnedTarget != null && returnedTarget.GetAsSyntaxOfType()?.Condition != node; + } + + private static bool IsLambdaExpression(SyntaxNode node) + { + return node.IsSyntaxOfType() || + node.IsSyntaxOfType(); + } + + private static bool IsNodeConditionInConditionalExpression(SyntaxNode node) + { + return node != null && (node.Parent as ConditionalExpressionSyntax)?.Condition == node; + } + private static bool IsAssignmentTarget(SyntaxNode node) + { + return node != null && node.Parent.GetAsSyntaxOfType()?.Left == node; + } + + private static bool IsDeclarationTarget(SyntaxNode node) + { + return node.IsSyntaxOfType() || node.IsSyntaxOfType(); + } + + private static bool IsAssignmentOrDeclarationTarget(SyntaxNode node) + { + return IsAssignmentTarget(node) || IsDeclarationTarget(node); + } + + private static bool IsAssignmentSource(SyntaxNode node) + { + return node != null && node.Parent.GetAsSyntaxOfType()?.Right == node; + } + + private static bool IsDeclarationSource(SyntaxNode node) + { + var grandParent = node?.Parent?.Parent; + if (grandParent == null) + { + return false; + } + + return (grandParent.GetAsSyntaxOfType()?.Initializer?.Value == node); + } + + private static bool IsAssignmentOrDeclarationSource(SyntaxNode node) + { + return IsAssignmentSource(node) || IsDeclarationSource(node); + } + + private static bool IsSimplePredicate(SyntaxNode node) + { + return _simplePredicateTypes.Contains(node.GetType()) || _binaryExpressionPredicateConnectors.Contains(node.Kind()); + } + + /// + /// Indicates if the syntax node is a type that may optionally be followed by a BlockSyntax (curly brackets): if, else, loops, usings, lambdas... + /// + /// + /// + private static bool CanTakeOptionalBlock(SyntaxNode node) + { + return _syntaxTypesWithOptionalBlock.Contains(node.GetType()); + } + + private static bool IsBodiedLambda(SyntaxNode node) + { + var nodeAsSimpleLambda = node as SimpleLambdaExpressionSyntax; + if (nodeAsSimpleLambda != null) + { + return nodeAsSimpleLambda.Body is BlockSyntax; + } + + var nodeAsParenthesizedLambda = node as ParenthesizedLambdaExpressionSyntax; + if (nodeAsParenthesizedLambda != null) + { + return nodeAsParenthesizedLambda.Body is BlockSyntax; + } + + return false; + } + + + #endregion + } +} diff --git a/src/Uno.CodeGen.RoslynHelpers/Helpers/SyntaxSymbolPairing.cs b/src/Uno.CodeGen.RoslynHelpers/Helpers/SyntaxSymbolPairing.cs new file mode 100644 index 0000000..616950e --- /dev/null +++ b/src/Uno.CodeGen.RoslynHelpers/Helpers/SyntaxSymbolPairing.cs @@ -0,0 +1,55 @@ +// ****************************************************************** +// Copyright � 2015-2018 nventive inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ****************************************************************** +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; + +namespace Uno.RoslynHelpers.Helpers +{ + /// + /// Used to pair a syntax node to a custom semantic representation of that node + /// + /// The type of the syntax node + /// The type of the symbol that is chosen as the semantic representation of the node + public class SyntaxSymbolPairing + where TSyntax : SyntaxNode + where TSymbol : ISymbol + { + private readonly Lazy _lazyTypeSymbolInitializer; + private readonly Lazy _lazySymbolInitializer; + + public ITypeSymbol TypeSymbol => _lazyTypeSymbolInitializer.Value; + public TSymbol Symbol => _lazySymbolInitializer.Value; + public TSyntax Node { get; } + + public SyntaxSymbolPairing(TSyntax node, Func syntaxTransform, Func typeSymbolTransform = null) + { + Node = node; + + _lazySymbolInitializer = new Lazy(() => syntaxTransform == null ? default(TSymbol) : syntaxTransform.Invoke(Node)); + _lazyTypeSymbolInitializer = new Lazy(() => typeSymbolTransform?.Invoke(Node)); + } + + public SyntaxSymbolPairing(TSyntax node, TSymbol symbol, ITypeSymbol typeSymbol = null) + : this(node, syntax => symbol, syntax => typeSymbol) + { + } + } +} diff --git a/src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/MethodSymbolExtensions.cs b/src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/MethodSymbolExtensions.cs new file mode 100644 index 0000000..5a21950 --- /dev/null +++ b/src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/MethodSymbolExtensions.cs @@ -0,0 +1,275 @@ +// ****************************************************************** +// Copyright � 2015-2018 nventive inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ****************************************************************** +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.CodeAnalysis +{ + public static class MethodSymbolExtensions + { + private const bool DefaultMatchUsingInheritance = true; + + private static bool HasMatchingParametersWith(this IMethodSymbol current, IMethodSymbol other) + { + var currentArgTypes = current.Parameters.Select(param => param.Type); + var otherArgTypes = other.Parameters.Select(param => param.Type); + return currentArgTypes.SequenceEqual(otherArgTypes); + } + + /// + /// Check if two methods have the same signature, which means same name, return type and parameters + /// + /// The current method + /// Another method + /// If true, the name of the methods will be used for the equality comparaison + /// True if the methods have the same signature + public static bool IsSameSignatureAs(this IMethodSymbol current, IMethodSymbol other, bool considerNameForEquivalence = true) + { + current = current.GetReducedFromOrSelf(); + other = other.GetReducedFromOrSelf(); + + return (!considerNameForEquivalence || current.Name == other.Name) && + current.ReturnType.EqualsType(other.ReturnType) && + current.HasMatchingParametersWith(other); + } + + /// + /// Indicates if a candidate method is the async equivalent of another target method + /// + /// The potential method symbol that is the async equivalent of the target + /// The target method + /// The analysis context + /// + /// If true, the comparison will include a check to see if the candidate has a matching Task as its return type + /// For example, Task<int> Foo() is the equivalent of int Foo() + /// + /// If true, a positive match will require the candidate method to be declared with the async keyword + /// True if the candidate method is the async equivalent of the target method + public static bool IsAsyncEquivalentOf( + this IMethodSymbol asyncCandidate, + IMethodSymbol target, + SyntaxNodeAnalysisContext context, + bool compareUsingTaskEquivalence = false, + bool needsToHaveAsyncKeyword = false) + { + if (needsToHaveAsyncKeyword && !asyncCandidate.IsAsync) + { + return false; + } + + var hasMatchingParameters = asyncCandidate.HasMatchingParametersWith(target); + var matchingAsyncEquivalentName = $"{target.Name}Async"; + + asyncCandidate = asyncCandidate.GetReducedFromOrSelf(); + target = target.GetReducedFromOrSelf(); + + if (!asyncCandidate.Name.Equals(matchingAsyncEquivalentName, StringComparison.OrdinalIgnoreCase) || + !hasMatchingParameters) + { + return false; + } + + if (!compareUsingTaskEquivalence) + { + return true; + } + + var asyncCandidateReturnType = asyncCandidate.ReturnType as INamedTypeSymbol; + + return asyncCandidateReturnType != null && + asyncCandidateReturnType.IsGenericType && + asyncCandidate.ReturnType.OriginalDefinition.DerivesFromType(context) && + asyncCandidateReturnType.TypeArguments.FirstOrDefault()?.Equals(target.ReturnType) == true; + } + + /// + /// Indicates if the current method is of a given name and part of a given type + /// + /// The current method symbol + /// The name of the to check in the provided type + /// The name of the type that the current method must be contained in + /// The context + /// If true, the comparison will involve checking if the method's containing type derives from the given type. + /// If false, the comparison will compare the method's containing type and the given type directly for equality instead + /// True if a method with the same name as the current method exists in the given type + public static bool IsNamedMethodOnType( + this IMethodSymbol methodSymbol, + string methodName, + string typeName, + SyntaxNodeAnalysisContext context, + bool matchUsingInheritance = DefaultMatchUsingInheritance) + { + if (methodSymbol == null || methodSymbol.Name != methodName) + { + return false; + } + + return matchUsingInheritance + ? methodSymbol.ContainingType.DerivesFromType(typeName, context) + : methodSymbol.ContainingType.IsOfType(typeName, context); + } + + /// + /// Indicates if the current method is of a given name and contained in a given type + /// + /// The type that the current method must be contained in + /// The current method symbol + /// The name that the current moethod name must match + /// The context + /// If true, the comparison will involve checking if the method's containing type derives from the given type. + /// If false, the comparison will compare the method's containing type and the given type directly for equality instead + /// True if a method with the same name as the current method exists in the given type + public static bool IsNamedMethodOnType( + this IMethodSymbol methodSymbol, + string methodName, + SyntaxNodeAnalysisContext context, + bool matchUsingInheritance = DefaultMatchUsingInheritance) + { + if (methodSymbol == null || methodSymbol.Name != methodName) + { + return false; + } + + return matchUsingInheritance + ? methodSymbol.ContainingType.DerivesFromType(context) + : methodSymbol.ContainingType.IsOfType(context); + } + + /// + /// Indicates if the current method is of a given name and contained in any of the given types + /// + /// The current method symbol + /// The name that the current moethod name must match + /// The context + /// If true, the types will be compared by checking if the method's containing type derives from any of the given types. + /// If false, the types will be compared for equality instead + /// The name of the types in one of which the current method must be contained + /// True if a method with the same name as the current method exists in the given type + public static bool IsNamedMethodOnAnyOfTheseTypes( + this IMethodSymbol methodSymbol, + string methodName, + SyntaxNodeAnalysisContext context, + bool matchUsingInheritance = DefaultMatchUsingInheritance, + params string[] typeNames) + { + return typeNames.Any(typeName => methodSymbol.IsNamedMethodOnType(methodName, typeName, context, matchUsingInheritance)); + } + + /// + /// Checks if a similar method is declared and accessible in a given type + /// + /// The method to check + /// The type to check agaisnt + /// The syntax analysis context + /// If true, the name of the methods will be used for the equality comparaison + /// True if the method belongs to this + public static bool HasSimilarMethodDeclaredInType( + this IMethodSymbol currentMethod, + ITypeSymbol type, + SyntaxNodeAnalysisContext context, + bool considerNameForEquivalence = true) + { + var typeMethods = currentMethod.ContainingType.EqualsType(type) + ? type.GetAllAccessibleMethodsFromWithinType(context, false, false, currentMethod.Name) + : type.GetAllPubliclyAccessibleMethodsFromType(context, false, false, currentMethod.Name); + + return typeMethods.Any(m => m.IsSameSignatureAs(currentMethod, considerNameForEquivalence)); + } + + /// + /// Checks if a similar method is declared and accessible in a given type or any of its ancestor + /// + /// The method to check + /// The type to check agaisnt + /// The syntax analysis context + /// If true, the name of the methods will be used for the equality comparaison + /// True if the method belongs to this + public static bool HasSimilarMethodDeclaredInTypeOrAncestors( + this IMethodSymbol currentMethod, + ITypeSymbol type, + SyntaxNodeAnalysisContext context, + bool considerNameForEquivalence = true) + { + var typeAndAncestorsMethods = currentMethod.ContainingType.EqualsType(type) + ? type.GetAllAccessibleMethodsFromWithinType(context, true, false, currentMethod.Name) + : type.GetAllPubliclyAccessibleMethodsFromType(context, true, false, currentMethod.Name); + + return typeAndAncestorsMethods.Any(m => m.IsSameSignatureAs(currentMethod, considerNameForEquivalence)); + } + + /// + /// Returns the reduced version of this method or the method itself + /// + /// The method to check + /// The method the current method was reduced from or the current method itself + public static IMethodSymbol GetReducedFromOrSelf(this IMethodSymbol currentMethod) + { + return currentMethod.ReducedFrom ?? currentMethod; + } + + /// + /// Indicates if the current method is a constructor (normal, static, shared) or a destructor + /// + /// The current method + /// True if the current method is a constructor or a destructor + public static bool IsConstructorOrDestructor(this IMethodSymbol currentMethod) => currentMethod.IsConstructor() || currentMethod.IsDestructor(); + + /// + /// Indicates if the current method is a constructor (normal, static, shared) + /// + /// The current method + /// True if the current method is a constructor or a destructor + public static bool IsDestructor(this IMethodSymbol currentMethod) => + currentMethod.MethodKind == MethodKind.SharedConstructor || + currentMethod.MethodKind == MethodKind.StaticConstructor; + + /// + /// Indicates if the current method is a destructor (normal, static, shared) + /// + /// The current method + /// True if the current method is a constructor or a destructor + public static bool IsConstructor(this IMethodSymbol currentMethod) => + currentMethod.MethodKind == MethodKind.Constructor || + currentMethod.MethodKind == MethodKind.Destructor; + + /// + /// Indicates if the method is a delegate invocation + /// + /// TThe current method + /// True if the method is a delegate invocation + public static bool IsDelegateInvocation(this IMethodSymbol currentMethod) + { + return currentMethod.MethodKind == MethodKind.DelegateInvoke; + } + + /// + /// Indicates if the method if a lambda of an anonymous function declaration + /// + /// + /// True if the method is a lambda or delegate declaration + public static bool IsLambdaOrDelegateDeclaration(this IMethodSymbol currentMethod) + { + return currentMethod.MethodKind == MethodKind.LambdaMethod || currentMethod.MethodKind == MethodKind.AnonymousFunction; + } + } +} diff --git a/src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/SymbolExtensions.cs b/src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/SymbolExtensions.cs new file mode 100644 index 0000000..bece9e9 --- /dev/null +++ b/src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/SymbolExtensions.cs @@ -0,0 +1,398 @@ +// ****************************************************************** +// Copyright � 2015-2018 nventive inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ****************************************************************** +using Microsoft.CodeAnalysis; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Microsoft.CodeAnalysis +{ + /// + /// Roslyn symbol extensions + /// + internal static class SymbolExtensions + { + public static IEnumerable GetProperties(this INamedTypeSymbol symbol) => symbol.GetMembers().OfType(); + + public static IEnumerable GetAllEvents(this INamedTypeSymbol symbol) + { + do + { + foreach (var member in GetEvents(symbol)) + { + yield return member; + } + + symbol = symbol.BaseType; + + if (symbol == null) + { + break; + } + + } while (symbol.Name != "Object"); + } + + public static IEnumerable GetEvents(INamedTypeSymbol symbol) => symbol.GetMembers().OfType(); + + /// + /// Determines if the symbol inherits from the specified type. + /// + /// The current symbol + /// A potential base class. + public static bool Is(this INamedTypeSymbol symbol, string typeName) + { + do + { + if (symbol.ToDisplayString() == typeName) + { + return true; + } + + symbol = symbol.BaseType; + + if (symbol == null) + { + break; + } + + } while (symbol.Name != "Object"); + + return false; + } + + /// + /// Determines if the symbol inherits from the specified type. + /// + /// The current symbol + /// A potential base class. + public static bool Is(this INamedTypeSymbol symbol, INamedTypeSymbol other) + { + do + { + if (symbol == other) + { + return true; + } + + symbol = symbol.BaseType; + + if (symbol == null) + { + break; + } + + } while (symbol.Name != "Object"); + + return false; + } + + public static bool IsPublic(this ISymbol symbol) => symbol.DeclaredAccessibility == Accessibility.Public; + + /// + /// Returns true if the symbol can be accessed from the current module + /// + /// + /// + public static bool IsLocallyPublic(this ISymbol symbol, IModuleSymbol currentSymbol) => + symbol.DeclaredAccessibility == Accessibility.Public + || + ( + symbol.Locations.Any(l => l.MetadataModule == currentSymbol) + && symbol.DeclaredAccessibility == Accessibility.Internal + ); + + public static IEnumerable GetMethods(this INamedTypeSymbol resolvedType) + { + return resolvedType.GetMembers().OfType(); + } + + public static IEnumerable GetFields(this INamedTypeSymbol resolvedType) + { + return resolvedType.GetMembers().OfType(); + } + + public static IEnumerable GetFieldsWithAttribute(this ITypeSymbol resolvedType, string name) + { + return resolvedType + .GetMembers() + .OfType() + .Where(f => f.FindAttribute(name) != null); + } + + public static AttributeData FindAttribute(this ISymbol property, string attributeClassFullName) + { + return property.GetAttributes().FirstOrDefault(a => a.AttributeClass.ToDisplayString() == attributeClassFullName); + } + + public static AttributeData FindAttribute(this ISymbol property, INamedTypeSymbol attributeClassSymbol) + { + return property.GetAttributes().FirstOrDefault(a => a.AttributeClass == attributeClassSymbol); + } + + public static AttributeData FindAttributeFlattened(this ISymbol property, INamedTypeSymbol attributeClassSymbol) + { + return property.GetAllAttributes().FirstOrDefault(a => a.AttributeClass == attributeClassSymbol); + } + + /// + /// Returns the element type of the IEnumerable, if any. + /// + /// + /// + public static ITypeSymbol EnumerableOf(this ITypeSymbol resolvedType) + { + var intf = resolvedType + .GetAllInterfaces(includeCurrent: true) + .FirstOrDefault(i => i.ToDisplayString().StartsWith("System.Collections.Generic.IEnumerable", StringComparison.OrdinalIgnoreCase)); + + return intf?.TypeArguments.First(); + } + + public static IEnumerable GetAllInterfaces(this ITypeSymbol symbol, bool includeCurrent = true) + { + if (symbol != null) + { + if (includeCurrent && symbol.TypeKind == TypeKind.Interface) + { + yield return (INamedTypeSymbol)symbol; + } + + do + { + foreach (var intf in symbol.Interfaces) + { + yield return intf; + + foreach (var innerInterface in intf.GetAllInterfaces()) + { + yield return innerInterface; + } + } + + symbol = symbol.BaseType; + + if (symbol == null) + { + break; + } + + } while (symbol.Name != "Object"); + } + } + + public static bool IsNullable(this ITypeSymbol type) + { + return ((type as INamedTypeSymbol)?.IsGenericType ?? false) + && type.OriginalDefinition.ToDisplayString().Equals("System.Nullable", StringComparison.OrdinalIgnoreCase); + } + + public static bool IsNullable(this ITypeSymbol type, out ITypeSymbol nullableType) + { + if (type.IsNullable()) + { + nullableType = ((INamedTypeSymbol)type).TypeArguments.First(); + return true; + } + else + { + nullableType = null; + return false; + } + } + + public static ITypeSymbol NullableOf(this ITypeSymbol type) + { + return type.IsNullable() + ? ((INamedTypeSymbol)type).TypeArguments.First() + : null; + } + + public static IEnumerable GetNamespaceTypes(this INamespaceSymbol sym) + { + foreach (var child in sym.GetTypeMembers()) + { + yield return child; + } + + foreach (var ns in sym.GetNamespaceMembers()) + { + foreach (var child2 in GetNamespaceTypes(ns)) + { + yield return child2; + } + } + } + private static readonly Dictionary _fullNamesMaping = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + {"string", typeof(string).ToString()}, + {"long", typeof(long).ToString()}, + {"int", typeof(int).ToString()}, + {"short", typeof(short).ToString()}, + {"ulong", typeof(ulong).ToString()}, + {"uint", typeof(uint).ToString()}, + {"ushort", typeof(ushort).ToString()}, + {"byte", typeof(byte).ToString()}, + {"double", typeof(double).ToString()}, + {"float", typeof(float).ToString()}, + {"decimal", typeof(decimal).ToString()}, + {"bool", typeof(bool).ToString()}, + }; + + public static string GetFullName(this INamespaceOrTypeSymbol type) + { + IArrayTypeSymbol arrayType = type as IArrayTypeSymbol; + if (arrayType != null) + { + return $"{arrayType.ElementType.GetFullName()}[]"; + } + + ITypeSymbol t; + if ((type as ITypeSymbol).IsNullable(out t)) + { + return $"System.Nullable`1[{t.GetFullName()}]"; + } + + var name = type.ToDisplayString(); + + string output; + + if (_fullNamesMaping.TryGetValue(name, out output)) + { + output = name; + } + + return output; + } + + public static string GetFullMetadataName(this INamespaceOrTypeSymbol symbol) + { + ISymbol s = symbol; + var sb = new StringBuilder(s.MetadataName); + + var last = s; + s = s.ContainingSymbol; + + if (s == null) + { + return symbol.GetFullName(); + } + + while (!IsRootNamespace(s)) + { + if (s is ITypeSymbol && last is ITypeSymbol) + { + sb.Insert(0, '+'); + } + else + { + sb.Insert(0, '.'); + } + sb.Insert(0, s.MetadataName); + + s = s.ContainingSymbol; + } + + var namedType = symbol as INamedTypeSymbol; + + if (namedType?.TypeArguments.Any() ?? false) + { + var genericArgs = string.Join(",", namedType.TypeArguments.Select(GetFullMetadataName)); + sb.Append($"[{ genericArgs }]"); + } + + return sb.ToString(); + } + + private static bool IsRootNamespace(ISymbol s) + { + return s is INamespaceSymbol && ((INamespaceSymbol)s).IsGlobalNamespace; + } + /// + /// Return attributes on the current type and all its ancestors + /// + /// + /// + public static IEnumerable GetAllAttributes(this ISymbol symbol) + { + while (symbol != null) + { + foreach (var attribute in symbol.GetAttributes()) + { + yield return attribute; + } + + symbol = (symbol as INamedTypeSymbol)?.BaseType; + } + } + + /// + /// Return properties of the current type and all of its ancestors + /// + /// + /// + public static IEnumerable GetAllProperties(this INamedTypeSymbol symbol) + { + while (symbol != null) + { + foreach (var property in symbol.GetMembers().OfType()) + { + yield return property; + } + + symbol = symbol.BaseType; + } + } + + /// + /// Converts declared accessibility on a symbol to a string usable in generated code. + /// + /// The symbol to get an accessibility string for. + /// Accessibility in format "public", "protected internal", etc. + public static string GetAccessibilityAsCSharpCodeString(this ISymbol symbol) + { + switch (symbol.DeclaredAccessibility) + { + case Accessibility.Private: + return "private"; + case Accessibility.ProtectedOrInternal: + return "protected internal"; + case Accessibility.Protected: + return "protected"; + case Accessibility.Internal: + return "internal"; + case Accessibility.Public: + return "public"; + } + + throw new ArgumentOutOfRangeException($"{symbol.DeclaredAccessibility} is not supported."); + } + + /// + /// Returns a boolean value indicating whether the symbol is decorated with all the given attributes + /// + /// The extended symbol + /// The given attributes + /// + public static bool HasAttributes(this ISymbol symbol, params INamedTypeSymbol[] attributes) + { + var currentSymbolAttributes = symbol.GetAttributes(); + return currentSymbolAttributes.Any() && currentSymbolAttributes.All(x => attributes.Contains(x.AttributeClass)); + } + } +} diff --git a/src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/SyntaxNodeExtensions.cs b/src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/SyntaxNodeExtensions.cs new file mode 100644 index 0000000..6c45ec4 --- /dev/null +++ b/src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/SyntaxNodeExtensions.cs @@ -0,0 +1,540 @@ +// ****************************************************************** +// Copyright � 2015-2018 nventive inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ****************************************************************** +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.IO; +using Uno.RoslynHelpers.Helpers; + +namespace Microsoft.CodeAnalysis +{ + public static class SyntaxNodeExtensions + { + public const bool DefaultConsiderParametersAsPotentialTargets = false; + public const bool DefaultPrioritizeSkip = false; + + /// + /// Returns the semantic symbol of the provided syntax node + /// + /// The syntax node + /// The syntax analysis context + /// The symbol of the provided syntax node + public static ISymbol GetSymbol(this SyntaxNode syntaxNode, SyntaxNodeAnalysisContext context) + { + return context.SemanticModel.GetSymbolInfo(syntaxNode).Symbol; + } + + /// + /// Returns the semantic symbol of the provided syntax node + /// + /// The syntax node + /// The syntax semantic model + /// The symbol of the provided syntax node + public static ISymbol GetSymbol(this SyntaxNode syntaxNode, SemanticModel model) + { + return model.GetSymbolInfo(syntaxNode).Symbol; + } + + /// + /// Returns the semantic declared symbol of the provided syntax node as the provided symbol type + /// + /// The syntax node + /// The syntax semantic model + /// The symbol of the provided syntax node + public static ISymbol GetDeclaredSymbol(this SyntaxNode syntaxNode, SemanticModel model) + { + return model.GetDeclaredSymbol(syntaxNode); + } + + /// + /// Returns the semantic declared symbol of the provided syntax node as the provided symbol type + /// + /// The syntax node + /// The syntax analysis context + /// The symbol of the provided syntax node + public static ISymbol GetDeclaredSymbol(this SyntaxNode syntaxNode, SyntaxNodeAnalysisContext context) + { + return context.SemanticModel.GetDeclaredSymbol(syntaxNode); + } + + /// + /// Returns the semantic symbol of the provided syntax node, or the declared symbol if the previous cast was invalid + /// + /// The syntax node + /// The syntax analysis context + /// The symbol or declared symbol of the provided syntax node + public static ISymbol GetSymbolOrDeclared(this SyntaxNode syntaxNode, SyntaxNodeAnalysisContext context) + { + return syntaxNode.GetSymbol(context) ?? syntaxNode.GetDeclaredSymbol(context); + } + + /// + /// Returns the semantic symbol of the provided syntax node, or the declared symbol if the previous cast was invalid + /// + /// + /// + /// The symbol or declared symbol of the provided syntax node + public static ISymbol GetSymbolOrDeclared(this SyntaxNode syntaxNode, SemanticModel semanticModel) + { + return semanticModel.GetSymbolInfo(syntaxNode).Symbol ?? semanticModel.GetDeclaredSymbol(syntaxNode); + } + + /// + /// The the enclosing symbol for the current syntax node + /// + /// The syntax node + /// The current semantic model + /// + public static ISymbol GetEnclosingSymbol(this SyntaxNode syntaxNode, SemanticModel semanticModel) + { + var position = syntaxNode.SpanStart; + return semanticModel.GetEnclosingSymbol(position); + } + + /// + /// Returns the semantic symbol of the provided syntax node + /// + /// The syntax node + /// The syntax semantic model + /// The symbol of the provided syntax node + public static TSymbolType GetSymbolAs(this SyntaxNode syntaxNode, SemanticModel model) where TSymbolType : class, ISymbol + { + return model.GetSymbolInfo(syntaxNode).Symbol as TSymbolType; + } + + /// + /// Returns the semantic symbol of the provided syntax node + /// + /// The syntax node + /// The syntax analysis context + /// The symbol of the provided syntax node + public static TSymbolType GetSymbolAs(this SyntaxNode syntaxNode, SyntaxNodeAnalysisContext context) where TSymbolType : class, ISymbol + { + return context.SemanticModel.GetSymbolInfo(syntaxNode).Symbol as TSymbolType; + } + + /// + /// Returns the semantic declared symbol of the provided syntax node as the provided symbol type + /// + /// The syntax node + /// The syntax analysis context + /// The symbol of the provided syntax node + public static TSymbolType GetDeclaredSymbolAs(this SyntaxNode syntaxNode, SyntaxNodeAnalysisContext context) where TSymbolType : class, ISymbol + { + return context.SemanticModel.GetDeclaredSymbol(syntaxNode) as TSymbolType; + } + + /// + /// Returns the semantic declared symbol of the provided syntax node as the provided symbol type + /// + /// The syntax node + /// The syntax analysis context + /// The symbol of the provided syntax node + public static TSymbolType GetDeclaredSymbolAs(this SyntaxNode syntaxNode, SemanticModel model) where TSymbolType : class, ISymbol + { + return model.GetDeclaredSymbol(syntaxNode) as TSymbolType; + } + + /// + /// Returns the semantic symbol of the provided syntax node, or the declared symbol if the previous cast was invalid + /// + /// The syntax node + /// The syntax analysis context + /// The symbol or declared symbol of the provided syntax node + public static TSymbolType GetSymbolOrDeclaredAs(this SyntaxNode syntaxNode, SyntaxNodeAnalysisContext context) where TSymbolType : class, ISymbol + { + return syntaxNode.GetSymbolAs(context) ?? syntaxNode.GetDeclaredSymbolAs(context); + } + + /// + /// Returns the semantic symbol of the provided syntax node, or the declared symbol if the previous cast was invalid + /// + /// The syntax node + /// The syntax semantic model + /// The symbol or declared symbol of the provided syntax node + public static TSymbolType GetSymbolOrDeclaredAs(this SyntaxNode syntaxNode, SemanticModel model) where TSymbolType : class, ISymbol + { + return syntaxNode.GetSymbolAs(model) ?? syntaxNode.GetDeclaredSymbolAs(model); + } + + /// + /// Finds first ancestor node such that predicate is met, unless terminateAt is met first. Returns null if terminateAt is true or if no ancestor meets predicate. + /// + /// The child node to start from. + /// The condition to return an ancestor. + /// If this is true for any ancestor, the search will be terminated. + /// The ancestor node that meets the predicate condition, or null if terminateAt is satisfied first or if no ancestor is found. + public static SyntaxNode GetFirstAncestorWhere(this SyntaxNode node, Func predicate, + Func terminateAt = null) + { + terminateAt = terminateAt ?? (_ => false); + + return node.Ancestors() + .TakeWhile(n => !terminateAt(n)) + .Where(predicate) + .FirstOrDefault(); + } + + /// + /// Finds first ancestor node of type T, unless terminateAt is satisfied first. Returns null if terminateAt is true or if no ancestor is of type T. + /// + /// The SyntaxNode type of interest. + /// The child node to start from. + /// If this is true for any ancestor, the search will be terminated. + /// The first ancestor node of type T, or null if terminateAt is satisfied first or if no ancestor of type T is found. + public static T GetFirstAncestorOfType(this SyntaxNode node, Func terminateAt = null) + where T : SyntaxNode + { + return GetFirstAncestorWhere(node, n => n is T, terminateAt) as T; + } + + /// + /// Get ancestor of a particular type which could 'refer to' node. This will return null if it encounters a 'boundary' (eg a StatementSyntax not of the + /// type of interest, a lambda expression, a ConditionalStatement that the node is on the left-hand side of, etc.), or if no ancestor of type T is found. + /// + /// The SyntaxNode type of interest. + /// The child node to start from. + /// The first ancestor node of type T, or null if a boundary node is encountered first or if no ancestor of type T is found. + public static T GetReferringAncestorOfType(this SyntaxNode node) + where T : SyntaxNode + { + return node.GetFirstAncestorOfType(terminateAt: n => !(n is T) && n.IsExtendedSyntaxOfType(ExtendedSyntaxType.ReferenceBoundary)); + } + + /// + /// Returns true if a node is the condition in a conditional expression. + /// + /// + /// + private static bool IsNodeConditionInConditionalExpression(this SyntaxNode node) + { + return node != null && (node.Parent as ConditionalExpressionSyntax)?.Condition == node; + } + + /// + /// Returns the the type symbol that this syntax node provides, if it has one (i.e InvocationSyntax -> invocation return type) + /// + /// The syntax node + /// The syntax analysis context + /// If true, the converted type (implicit conversion) is returned + /// The type symbol that the syntax node represents + public static ITypeSymbol GetAsTypeSymbol(this SyntaxNode syntaxNode, SyntaxNodeAnalysisContext context, bool useConvertedType = false) + { + var symbolTypeInfo = context.SemanticModel.GetTypeInfo(syntaxNode); + var type = useConvertedType ? symbolTypeInfo.ConvertedType : symbolTypeInfo.Type; + + return type.IsOfType(context) ? null : type; + } + + + /// + /// Indicates if the current syntax node is of the trageted syntax type + /// + /// + /// + /// + public static bool IsSyntaxOfType(this SyntaxNode current) where TSymbolType : SyntaxNode + { + return current is TSymbolType; + } + + /// + /// Returns the syntax node safe-casted into a certain syntax type + /// + /// The syntax type the node should be cast to + /// The syntax node to convert + /// + public static TSymbolType GetAsSyntaxOfType(this SyntaxNode current) where TSymbolType : SyntaxNode + { + return current as TSymbolType; + } + + public static SyntaxSymbolPairing LinkNodeToSymbol( + this TSyntax syntaxNode, + Func syntaxToSymbol, + SyntaxNodeAnalysisContext? context = null) + where TSyntax : SyntaxNode where TSymbol : ISymbol + { + return syntaxNode.LinkNodeToSymbol(node => node, syntaxToSymbol, context); + } + + public static SyntaxSymbolPairing LinkNodeToSymbol( + this TSourceSyntax syntaxNode, + Func syntaxTransform, + Func syntaxToSymbol, + SyntaxNodeAnalysisContext? context = null) + where TSourceSyntax : SyntaxNode + where TResultSyntax : SyntaxNode + where TSymbol : ISymbol + { + return new SyntaxSymbolPairing( + syntaxNode, + node => syntaxToSymbol(syntaxTransform(node)), + node => context.HasValue ? node.GetAsTypeSymbol(context.Value) : null + ); + } + + /// + /// Links each syntax node to a specified semantic representation of that node. + /// + /// The nodes to map to symbols + /// Describes the transition from syntax to symbol applied to a node + /// to obtain the desired semantic representation of that node + /// [Optionnal] The analysis context. Must be provided if the + /// needs to be computed + /// A self-contained pairing between the given syntax node and its equivalent semantic representation + public static IEnumerable> LinkNodesToSymbols( + this IEnumerable syntaxNodes, + Func syntaxToSymbol, + SyntaxNodeAnalysisContext? context = null) + where TSyntax : SyntaxNode where TSymbol : ISymbol + { + return syntaxNodes.Select(node => node.LinkNodeToSymbol(syntaxToSymbol, context)); + } + + /// + /// Indicates if this node is directly or conditionally returned in the context of its declaration + /// + /// The node to check + /// Is the node is an active member of a return statement + public static bool IsReturned(this SyntaxNode node) + { + if (node.Parent.IsSyntaxOfType()) + { + return true; + } + + var ancestorsUntilReturn = node.Ancestors() + .TakeWhile(ancestor => !ancestor.IsSyntaxOfType() && IsConditionalOrCoalesce(node)); + + var returnStatement = ancestorsUntilReturn.LastOrDefault()?.Parent?.GetAsSyntaxOfType(); + return returnStatement != null && returnStatement.Expression.GetAsSyntaxOfType()?.Condition != node; + } + + private static bool IsConditionalOrCoalesce(SyntaxNode node) + { + return node.IsSyntaxOfType() || node.IsKind(SyntaxKind.CoalesceExpression); + } + + /// + /// Returns the nearest ancestor of type IfStatementSyntax where the syntax node is declared + /// + /// The provided syntax node + /// The nearest ancestor of type IfStatementSyntax where the syntax node is declared + public static IfStatementSyntax GetDeclaringIfStatement(this SyntaxNode syntaxNode) + { + return syntaxNode.FirstAncestorOrSelf(); + } + + /// + /// Return the nearest ancestor of any of the four loop type (for, while, do-while, foreach) where the syntax node is declared + /// + /// The provided syntax node + /// The nearest ancestor of any of the four loop type (for, while, do-while, foreach) where the syntax node is declared + public static StatementSyntax GetDeclaringLoopStatement(this SyntaxNode syntaxNode) + { + return syntaxNode.FirstAncestorOrSelf() ?? syntaxNode.FirstAncestorOrSelf() ?? + (StatementSyntax)syntaxNode.FirstAncestorOrSelf() ?? syntaxNode.FirstAncestorOrSelf(); + } + + /// + /// Checks if the given node is a certain type of syntax. This type is actually one of the pre-defined check declared in ExtendedSyntaxType + /// + /// The current node + /// The target extended syntax type to check the current node against + /// True if the node matches the provided extended type + public static bool IsExtendedSyntaxOfType(this SyntaxNode node, ExtendedSyntaxType extendedSyntaxType) + { + return extendedSyntaxType.CheckIfExtendedType(node); + } + + /// + /// Get the first ancestor which is a member declaration syntax + /// + /// The current node + /// If true, the current node will be considered when checking for MemberDeclarationSyntax ancestors + /// The surrounding member declaration syntax + public static MemberDeclarationSyntax GetSurroundingMemberDeclarationSyntax(this SyntaxNode node, bool includeSelf = false) + { + + return GetSurroundingMemberDeclarationSyntax(node, includeSelf, false); + } + + /// + /// Get the first ancestor which is a member declaration syntax of the provided kind (class, method, namespace, etc) + /// + /// The current node + /// If true, the current node will be considered when checking for MemberDeclarationSyntax ancestors + /// If true, will grab the last surrounding declaration syntax of the given type. Useful to ignore of nested classes or namespaces + /// The surrounding member declaration syntax + public static MemberDeclarationSyntax GetSurroundingMemberDeclarationSyntax( + this SyntaxNode node, + bool includeSelf = false, + bool takeLast = false) + where TMemberDeclarationType : MemberDeclarationSyntax + { + var ancestors = includeSelf ? node.AncestorsAndSelf() : node.Ancestors(); + var target = takeLast + ? ancestors.LastOrDefault(ancestor => ancestor.IsSyntaxOfType()) + : ancestors.FirstOrDefault(ancestor => ancestor.IsSyntaxOfType()); + + return target as TMemberDeclarationType; + } + + /// + /// Checks if the current syntax node matches any of the given extended syntax type definitions + /// + /// The current node + /// The extended syntax types to match the current node agaisnt + /// True if the current node is of any of of the given extended types + public static bool IsOneOfThoseExtendedSyntaxTypes(this SyntaxNode node, params ExtendedSyntaxType[] extendedSyntaxTypes) + { + return extendedSyntaxTypes.Any(t => t.CheckIfExtendedType(node)); + } + + /// + /// Gets info about cyclomatic complexity, counting the number of predicates within the scope of rootNode and within each nested function + /// (methods and anonymous functions). + /// + /// The SyntaxNode to measure cyclomatic complexity within + /// A sequence of RegionInfo objects, each containing the region-defining node (either rootNode or a function-defining node) + /// and cyclomatic complexity values for the region. There will always be at least one RegionInfo returned for the rootNode, + /// plus one for each nested function. + public static IEnumerable GetCyclomaticComplexityInfo(this SyntaxNode rootNode, SemanticModel model) + { + var walker = new CyclomaticComplexityWalker(rootNode, model); + walker.Visit(rootNode); + return walker.Results; + } + + /// + /// Descends the hierarchy of 's descendants depth-first, looking for nodes that match . + /// If an encountered node matches , it is returned, and its own descendants are ignored. + /// If an encountered node matches , it and its descendants are ignored. + /// If is true, the skip predicate takes precedence over the keep predicate. + /// + /// The root syntax node to start the analysis at + /// The predicate used to indicate if a node should be retained or not. + /// The predicate used to indicate if a node (and its descendant) should be skipped or not. + /// If true, even a node that matches the keep predicate will not be retained if it also matches the skip predicate + /// All the first occurences of the targeted nodes for each branch of the syntax tree under the given root + public static IEnumerable GetAllFirstMatchingSubTreeRoots( + this SyntaxNode root, + Func keepPredicate, + Func skipPredicate = null, + bool prioritizeSkip = DefaultPrioritizeSkip) + { + // Iterative depth first search of the tree + var nodes = new Stack(root.ChildNodes()); + while (nodes.Any()) + { + var current = nodes.Pop(); + var skipCurrent = skipPredicate?.Invoke(current) ?? false; + var keepCurrent = keepPredicate(current); + + if (prioritizeSkip && skipCurrent) + { + continue; + } + + if (keepCurrent) + { + yield return current; + } + else if (!skipCurrent) + { + foreach (var child in current.ChildNodes()) + { + nodes.Push(child); + } + } + } + } + + /// + /// Descends the hierarchy of 's descendants depth-first, looking for nodes that match . + /// If an encountered node matches , it is returned, and its own descendants are ignored. + /// If an encountered node matches , it and its descendants are ignored. + /// If is true, the skip predicate takes precedence over the keep predicate. + /// If no value is given for the , the predicate is assumed to be always 'true", and so any subtree root matching the + /// given type will be returned (while its descendants are ignored) + /// + /// The root syntax node to start the analysis at + /// The predicate used to indicate if a node should be retained or not. + /// The predicate used to indicate if a node (and its descendant) should be skipped or not. + /// If true, even a node that matches the keep predicate will not be retained if it also matches the skip predicate + /// All the first occurences of the targeted nodes for each branch of the syntax tree under the given root + public static IEnumerable GetAllFirstMatchingSubTreeRootsOfType( + this SyntaxNode root, + Func keepPredicate = null, + Func skipPredicate = null, + bool prioritizeSkip = DefaultPrioritizeSkip) + where TNodeType : SyntaxNode + { + // We combine the 'keep' predicate with the type-matching predicate here + Func combinedPredicate = node => node is TNodeType && (keepPredicate?.Invoke(node) ?? true); + return root.GetAllFirstMatchingSubTreeRoots(node => combinedPredicate(node), skipPredicate, prioritizeSkip).Cast(); + } + /// + /// Returns true if the node appears to be in generated code. + /// + /// + /// + public static bool IsInGeneratedCode(this SyntaxNode node) + { + var fileName = Path.GetFileName(node.SyntaxTree.FilePath); + return IsFileNameForGeneratedCode(fileName); + } + + /// + /// Returns true if file name indicates that the code is generated. + /// https://github.com/dotnet/roslyn/blob/master/src/Workspaces/Core/Portable/GeneratedCodeRecognition/GeneratedCodeRecognitionServiceFactory.cs + /// + /// + /// + private static bool IsFileNameForGeneratedCode(string fileName) + { + if (fileName.StartsWith("TemporaryGeneratedFile_", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + string extension = Path.GetExtension(fileName); + if (extension != string.Empty) + { + fileName = Path.GetFileNameWithoutExtension(fileName); + + if (fileName.EndsWith("AssemblyInfo", StringComparison.OrdinalIgnoreCase) || + fileName.EndsWith(".designer", StringComparison.OrdinalIgnoreCase) || + fileName.EndsWith(".generated", StringComparison.OrdinalIgnoreCase) || + fileName.EndsWith(".g", StringComparison.OrdinalIgnoreCase) || + fileName.EndsWith(".g.i", StringComparison.OrdinalIgnoreCase) || + fileName.EndsWith(".AssemblyAttributes", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + + return false; + } + } +} diff --git a/src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/TypeParameterSymbolExtensions.cs b/src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/TypeParameterSymbolExtensions.cs new file mode 100644 index 0000000..4b01763 --- /dev/null +++ b/src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/TypeParameterSymbolExtensions.cs @@ -0,0 +1,104 @@ +// ****************************************************************** +// Copyright � 2015-2018 nventive inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ****************************************************************** +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.CodeAnalysis +{ + public static class TypeParameterSymbolExtensions + { + /// Uses reflection to obtain the EffectiveBaseClassNoUseSiteDiagnostics property and its value. + /// http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis.CSharp/Symbols/TypeParameterSymbol.cs#275 + private static MethodInfo GetReflectedEffectiveBaseClassMethodInfo(ITypeParameterSymbol typeSymbol) + { + return typeSymbol.GetType().GetRuntimeProperties().FirstOrDefault(methodInfo => methodInfo.Name == "EffectiveBaseClassNoUseSiteDiagnostics").GetMethod; ; + } + + /// Uses reflection to obtain the EffectiveInterfacesNoUseSiteDiagnostics property and its value. + /// http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis.CSharp/Symbols/TypeParameterSymbol.cs#300 + private static MethodInfo GetReflectedEffectiveInterfaceMethodInfo(ITypeParameterSymbol typeSymbol) + { + return typeSymbol.GetType().GetRuntimeProperties().FirstOrDefault(methodInfo => methodInfo.Name == "EffectiveInterfacesNoUseSiteDiagnostics").GetMethod; + } + + /// + /// Returns true if two ITypeParameterSymbols (symbols corresponding to a type parameter, eg 'T' in SomeMethod() { T t = ... }) appear to be equivalent, + /// meaning that they appear to have matching constraints. + /// + /// Note: this method is currently not watertight, due to difficult cases like self-referential constraints (eg 'where T : IComparable') + /// + /// Symbol to compare + /// Symbol to compare + /// True if the type parameters are equivalent + public static bool HasEquivalentConstraintsTo(this ITypeParameterSymbol current, ITypeParameterSymbol other) + { + if (current == null || other == null) + { + return false; + } + if (current.HasReferenceTypeConstraint != other.HasReferenceTypeConstraint + || current.HasValueTypeConstraint != other.HasValueTypeConstraint + || current.HasConstructorConstraint != other.HasConstructorConstraint) + { + return false; + } + return current.ConstraintTypes.AreTypeSetsEquivalent(other.ConstraintTypes); + } + + /// + /// Provides all the resolved/effetive interface constraints of the given type parameter symbol. + /// + /// + /// public Method where T : U where U : IEnumerable, V where V : IComparable + /// // U will have the following effective interface constraints: IEnumerable, Icomparable + /// + /// + /// + /// The type parameter symbol to resolve obtain the effective interface constraints from + /// All the resolved/effective interfaces that constrain the given type parameter symbol + public static IEnumerable GetAllEffectiveInterfaceConstraints(this ITypeParameterSymbol current) + { + return ((IEnumerable)GetReflectedEffectiveInterfaceMethodInfo(current).Invoke(current, null)).Cast(); + } + + /// + /// Attempts to resolve the constraints on the given type parameter symbol and obtain a concrete named type. + /// If no such constraint can be resolved into a named type, null is returned + /// + /// The type parameter symbol to resolve as a constrained type + /// The effective/constrained named type that has been resolved from the given type parameter symbol's constraint + public static INamedTypeSymbol TryGetAsConstrainedType(this ITypeParameterSymbol current) + { + var constrainedBaseType = (INamedTypeSymbol)GetReflectedEffectiveBaseClassMethodInfo(current).Invoke(current, null); + + // If the attempt to get the current type parameter symbol as a restrained type gives us a type symbol representing 'object' + // or 'ValueType', then this type parameter is unconstrained + return constrainedBaseType.SpecialType == SpecialType.System_Object || constrainedBaseType.SpecialType == SpecialType.System_ValueType + ? null + : constrainedBaseType; + } + } +} diff --git a/src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/TypeSymbolExtensions.cs b/src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/TypeSymbolExtensions.cs new file mode 100644 index 0000000..dc62a50 --- /dev/null +++ b/src/Uno.CodeGen.RoslynHelpers/Microsoft/CodeAnalysis/TypeSymbolExtensions.cs @@ -0,0 +1,567 @@ +// ****************************************************************** +// Copyright � 2015-2018 nventive inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ****************************************************************** +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.CodeAnalysis +{ + public static class TypeSymbolExtensions + { + + private const bool DoDefaultCompareUsingSubstitutedType = true; + + /// + /// Returns true is the underlying type is an interface + /// + /// The type symbol + /// True if the type is an interface + public static bool IsInterface(this ITypeSymbol symbol) + { + return symbol.TypeKind == TypeKind.Interface; + } + + /// + /// Returns all the interfaces this type inherits from, including the type itself if it is an interface + /// + /// The type symbol + /// All the interfaces this type inherits from, including itself + public static IList GetAllInterfacesIncludingThis(this ITypeSymbol type) + { + var allInterfaces = type.AllInterfaces; + var namedType = type as INamedTypeSymbol; + if (namedType != null && namedType.TypeKind == TypeKind.Interface && !allInterfaces.Contains(namedType)) + { + var result = new List(allInterfaces.Length + 1); + result.Add(namedType); + result.AddRange(allInterfaces); + return result; + } + + return allInterfaces; + } + + private static INamedTypeSymbol GetTypeSymbolFromMetadataName(string otherTypeFullName, SyntaxNodeAnalysisContext context) + { + return context.SemanticModel.Compilation.GetTypeByMetadataName(otherTypeFullName); + } + + /// + /// Compares two type symbols for equality + /// + /// The current type symbol + /// Another type sybol + /// If false, the comparison will use the original definitions of both symbols (in case one or both are generic types) + /// If the symbols are equal + public static bool EqualsType(this ITypeSymbol current, ITypeSymbol other, bool compareUsingSubstitutedType = DoDefaultCompareUsingSubstitutedType) + { + var currentTypeSymbol = compareUsingSubstitutedType ? current : current?.OriginalDefinition; + var otherTypeSymbol = compareUsingSubstitutedType ? other : other?.OriginalDefinition; + + return currentTypeSymbol != null && currentTypeSymbol.OriginalDefinition.Equals(otherTypeSymbol); + } + + /// + /// If both current and other are ITypeParameterSymbols, checks if their constraints are equivalent. Otherwise, returns the result of EqualsType. + /// + /// + /// + /// + public static bool IsEquivalentToType(this ITypeSymbol current, ITypeSymbol other) + { + if (current is ITypeParameterSymbol && other is ITypeParameterSymbol) + { + return (current as ITypeParameterSymbol).HasEquivalentConstraintsTo(other as ITypeParameterSymbol); + } + + if (current is INamedTypeSymbol && other is INamedTypeSymbol) + { + return (current as INamedTypeSymbol).IsEquivalentToType(other as INamedTypeSymbol); + } + + return current.EqualsType(other, compareUsingSubstitutedType: true); + } + + /// + /// Checks if the underlying type of the current type symbol derives from the type with the provided name + /// + /// The current type symbol + /// The full name for the System.Type instance the current type symbol will be checked against for inheritance/implementation + /// The analysis context + /// If the underlying type of the current type symbol implements or inherits the target type + public static bool DerivesFromType(this ITypeSymbol symbol, string otherTypeFullName, SyntaxNodeAnalysisContext context) + { + var otherType = GetTypeSymbolFromMetadataName(otherTypeFullName, context); + return DerivesFromType(symbol, otherType); + } + + /// + /// Checks if the underlying type of the current type symbol derives from the type with the provided name + /// + /// The current type symbol + /// The full name for the System.Type instance the current type symbol will be checked against for inheritance/implementation + /// The analysis context + /// If the underlying type of the current type symbol implements or inherits the target type + public static bool DerivesFromType(this ITypeSymbol symbol, ITypeSymbol otherType) + { + var baseTypes = GetBaseTypesAndThis(symbol); + var implementedInterfaces = GetAllInterfacesIncludingThis(symbol); + + return baseTypes.Any(baseType => baseType.Equals(otherType) || + implementedInterfaces.Any(baseInterfaceType => baseInterfaceType.Equals(otherType))); + } + + /// + /// Checks if the underlying type of the current type symbol derives from the provided type + /// + /// The current type symbol + /// The System.Type instance that the type symbol will be checked against for inheritance/implementation + /// The analysis context + /// If the underlying type of the current type symbol implements or inherits the target type + public static bool DerivesFromType(this ITypeSymbol symbol, Type otherType, SyntaxNodeAnalysisContext context) + { + return DerivesFromType(symbol, otherType?.FullName, context); + } + + /// + /// Checks if the underlying type of the current type symbol derives from the provided type + /// + /// The current type symbol + /// The analysis context + /// The type names from which the symbol could inherit + /// If the underlying type of the current type symbol implements or inherits the target type + public static bool DerivesFromAnyOfTheseTypes(this ITypeSymbol symbol, SyntaxNodeAnalysisContext context, params string[] typeNames) + { + return typeNames.Any(typeName => DerivesFromType(symbol, typeName, context)); + } + + /// + /// Checks if the underlying type of the current type symbol derives from the generic argument type + /// + /// The current type symbol + /// The analysis context + /// If the underlying type of the current type symbol implements or inherits the target type + public static bool DerivesFromType(this ITypeSymbol symbol, SyntaxNodeAnalysisContext context) + { + return DerivesFromType(symbol, typeof(TSymbolType), context); + } + + /// + /// Checks if the underlying type of the current type symbol is the same as the type with the provided name + /// + /// The current type symbol + /// The full name for the System.Type instance the current type symbol will be checked against for equality + /// The analysis context + /// Determines if the comparison wil use the original definitions of both symbols (in case one or both are generic types) + /// If the underlying type of the current type symbol is equal to the target type + public static bool IsOfType(this ITypeSymbol symbol, string otherTypeFullName, SyntaxNodeAnalysisContext context, bool compareUsingOriginalType = DoDefaultCompareUsingSubstitutedType) + { + var otherType = GetTypeSymbolFromMetadataName(otherTypeFullName, context); + return EqualsType(symbol, otherType, compareUsingOriginalType); + } + + /// + /// Checks if the underlying type of the current type symbol is the same as the type with the provided type + /// + /// The current type symbol + /// The System.Type instance that the provided type symbol will be checked against for equality + /// The analysis context + /// Determines if the comparison wil use the original definitions of both symbols (in case one or both are generic types) + /// If the underlying type of the current type symbol is equal to the target type + public static bool IsOfType(this ITypeSymbol symbol, Type otherType, SyntaxNodeAnalysisContext context, bool compareUsingOriginalType = DoDefaultCompareUsingSubstitutedType) + { + return IsOfType(symbol, otherType?.FullName, context, compareUsingOriginalType); + } + + /// + /// Checks if the underlying type of the current type symbol is the same as the type with the provided generic type + /// + /// The current type symbol + /// The analysis context + /// Determines if the comparison wil use the original definitions of both symbols (in case one or both are generic types) + /// If the underlying type of the current type symbol is equal to the target type + public static bool IsOfType(this ITypeSymbol symbol, SyntaxNodeAnalysisContext context, bool compareUsingOriginalType = DoDefaultCompareUsingSubstitutedType) + { + return IsOfType(symbol, typeof(TSymbolType), context, compareUsingOriginalType); + } + + /// + /// Checks if one of the provided types matches the underlying type of the current type symbol + /// + /// The current type symbol + /// The analysis context + /// Determines if the comparison wil use the original definitions of both symbols (in case one or both are generic types) + /// The full names for the System.Type instances that the provided type symbol will be checked against for equality + /// If the underlying type of the current type symbol is equal to one of the target types + public static bool IsOneOfTheseTypes(this ITypeSymbol symbol, SyntaxNodeAnalysisContext context, bool compareUsingOriginalType, params string[] otherTypeNames) + { + var otherTypes = otherTypeNames.Select(typeName => GetTypeSymbolFromMetadataName(typeName, context)); + return otherTypes.Any(type => EqualsType(symbol, type, compareUsingOriginalType)); + } + + /// + /// Checks if one of the provided types matches the underlying type of the current type symbol. + /// Uses the default comparison strategy, defined in + /// + /// The current type symbol + /// The full names for the System.Type instances that the provided type symbol will be checked against for equality + /// The analysis context + /// If the underlying type of the current type symbol is equal to one of the target types + public static bool IsOneOfTheseTypes(this ITypeSymbol symbol, SyntaxNodeAnalysisContext context, params string[] otherTypeNames) + { + return IsOneOfTheseTypes(symbol, context, true, otherTypeNames); + } + + /// + /// Checks if one of the provided types matches the underlying type of the current type symbol + /// + /// The current type symbol + /// Determines if the comparison wil use the original definitions of both symbols (in case one or both are generic types) + /// The System.Type instances the current type symbol will be check against for equality + /// The analysis context + /// If the underlying type of the current type symbol is equal to one of the target types + public static bool IsOneOfTheseTypes(this ITypeSymbol symbol, SyntaxNodeAnalysisContext context, bool compareUsingOriginalType, params Type[] otherTypes) + { + return IsOneOfTheseTypes(symbol, context, compareUsingOriginalType, otherTypes.Select(t => t.FullName).ToArray()); + } + + /// + /// Checks if one of the provided types matches the underlying type of the current type symbol. + /// Uses the default comparison strategy, defined in + /// + /// The current type symbol + /// The System.Type instances the current type symbol will be check against for equality + /// The analysis context + /// If the underlying type of the current type symbol is equal to one of the target types + public static bool IsOneOfTheseTypes(this ITypeSymbol symbol, SyntaxNodeAnalysisContext context, params Type[] otherTypes) + { + return IsOneOfTheseTypes(symbol, context, true, otherTypes); + } + + public static bool IsAnonymousType(this INamedTypeSymbol symbol) + { + return symbol?.IsAnonymousType == true; + } + + /// + /// True if type symbol represents void + /// + /// + /// + public static bool IsVoid(this ITypeSymbol symbol) + { + return symbol.SpecialType == SpecialType.System_Void; + } + + /// + /// True if type symbol is a primitive, DateTime, or DateTimeOffset + /// + /// + /// + /// + public static bool IsSimpleType(this ITypeSymbol symbol, SyntaxNodeAnalysisContext context) + { + return symbol.IsOfType(context) + || symbol.IsOfType(context) + || symbol.IsOfType(context) + || symbol.IsOfType(context) + || symbol.IsOfType(context) + || symbol.IsOfType(context) + || symbol.IsOfType(context) + || symbol.IsOfType(context) + || symbol.IsOfType(context) + || symbol.IsOfType(context) + || symbol.IsOfType(context) + || symbol.IsOfType(context) + || symbol.IsOfType(context); + } + + /// + /// Return all the symbols for the base types present in the current type symbol's underlying type inheritance + /// hierarchy, including the type from the symbol itself + /// + /// The type symbol to analyze + /// The symbols for all the base type for the current type symbol's underlying type, including the current stype + public static IEnumerable GetBaseTypesAndThis(this ITypeSymbol type) + { + var current = type; + while (current != null) + { + yield return current; + current = current.BaseType; + } + } + + /// + /// Return all the symbols for the base types present in the current type symbol's underlying type inheritance + /// hierarchy + /// + /// The type symbol to analyze + /// The symbols for all the base type for the current type symbol's underlying type + public static IEnumerable GetBaseTypes(this ITypeSymbol type) + { + var current = type.BaseType; + while (current != null) + { + yield return current; + current = current.BaseType; + } + } + + /// + /// Return the symbols representing all the classes in which the current type symbol's underlying type is contained, + /// including the class of the current symbol's underlying type + /// hierarchy + /// + /// The type symbol to analyze + /// The symbols for all the classes in which the current type symbol's underlying type is contained, including the current type + public static IEnumerable GetContainingTypesAndThis(this ITypeSymbol type) + { + var current = type; + while (current != null) + { + yield return current; + current = current.ContainingType; + } + } + + /// + /// Return the symbols representing all the classes in which the current type symbol's underlying type is contained + /// hierarchy + /// + /// The type symbol to analyze + /// The symbols for all the classes in which the current type symbol's underlying type is containede + public static IEnumerable GetContainingTypes(this ITypeSymbol type) + { + var current = type.ContainingType; + while (current != null) + { + yield return current; + current = current.ContainingType; + } + } + + /// + /// Return all the attributes applied to the current type, include the ones inherited from inheritance ancestors + /// + /// The type symbol to analyze + /// All the attributes applied to the type, either directly or through inheritance ancestors that have those attributes + public static IEnumerable GetAllAppliedAttributes(this ITypeSymbol type) + { + return type + .GetBaseTypesAndThis() + .SelectMany(t => t.GetAttributes()); + } + + /// + /// Returns an enumeration of the methods that are accessible from within a type, + /// including protected and private methods. + /// + /// The type to explore + /// The analysis context + /// If true, the returned methods will included the accessible (public and protected) methods this type inherits from + /// If true, this will include the methods marked as obsolete + /// Only targets methods with this specific name (optionnal) + /// The methods that are available from within the provided type (includes inherited methods if is set to true) + public static IEnumerable GetAllAccessibleMethodsFromWithinType( + this ITypeSymbol type, + SyntaxNodeAnalysisContext context, + bool visitHierarchy = true, + bool includeObsoleteMethods = false, + string methodName = null) + { + return GetAllMethodsWithinType(type, context, visitHierarchy, includeObsoleteMethods, methodName) + .Where(x => x.DeclaredAccessibility == Accessibility.Public || x.DeclaredAccessibility == Accessibility.ProtectedOrFriend); + + } + + /// + /// Returns an enumeration of the methods that are publicly accessible for a given type + /// + /// The type to explore + /// The analysis context + /// If true, the returned methods will included the publicly accessible methods this type inherits from + /// If true, this will include the methods marked as obsolete + /// Only targets methods with this specific name (optionnal) + /// The methods that are publicly accessible for a given type (includes inherited methods if is set to true) + public static IEnumerable GetAllPubliclyAccessibleMethodsFromType( + this ITypeSymbol type, + SyntaxNodeAnalysisContext context, + bool visitHierarchy = false, + bool includeObsoleteMethods = false, + string methodName = null) + { + return GetAllMethodsWithinType(type, context, visitHierarchy, includeObsoleteMethods, methodName) + .Where(m => m.DeclaredAccessibility == Accessibility.Public); + } + + /// + /// Returns am enmumeration of methods contained within a type + /// + /// The type to explore + /// The analysis context + /// If true, the returned methods will included the methods this type inherits from + /// If true, this will include the methods marked as obsolete + /// Only targets methods with this specific name (optionnal) + /// The methods from a given type (includes inherited methods if is set to true) + private static IEnumerable GetAllMethodsWithinType( + ITypeSymbol currentType, + SyntaxNodeAnalysisContext context, + bool visitHierarchy, + bool includeObsoleteMethods, + string methodName) + { + var obsoleteAttribute = context.SemanticModel.Compilation.GetTypeByMetadataName("System.ObsoleteAttribute"); + + while (currentType != null) + { + var members = methodName != null ? currentType.GetMembers(methodName) : currentType.GetMembers(); + var methods = members + .OfType() + .Where(x => !x.IsConstructorOrDestructor()) + .Where(x => !x.IsAbstract) + .Where(x => includeObsoleteMethods || !x.HasAttributes(obsoleteAttribute)); + + foreach (var method in methods) + { + yield return method; + } + + if (!visitHierarchy) + { + break; + } + + currentType = currentType.BaseType; + } + } + + /// + /// Returns true if two sets of types are equivalent, ignoring order. + /// + /// + /// + /// + public static bool AreTypeSetsEquivalent(this IEnumerable current, IEnumerable other) + { + var otherList = other.ToList(); + foreach (var typeInCurrent in current) + { + int equivalentInOther = otherList.FindIndex(typeInOther => typeInCurrent.IsEquivalentToType(typeInOther)); + if (equivalentInOther == -1) + { + return false; + } + else + { + otherList.RemoveAt(equivalentInOther); + } + } + //If we found a type in other for every type in current, and there are no remaining types in other, then the sets are an exact match + return otherList.Count == 0; + } + + /// + /// Returns true if typeSymbol is a type parameter (eg 'TValue') or a generic type with only type parameters within its type arguments (eg Dictionary or Dictionary>, but not Dictionary or Dictionary>), false otherwise + /// + /// + /// + public static bool IsTypeParameterOrGenericWithTypeParameterArguments(this ITypeSymbol typeSymbol) + { + if (typeSymbol is ITypeParameterSymbol) + { + return true; + } + var asNamedType = typeSymbol as INamedTypeSymbol; + if (asNamedType?.IsGenericType ?? false) + { + return asNamedType.TypeArguments.All(typeArg => typeArg.IsTypeParameterOrGenericWithTypeParameterArguments()); + } + return false; + } + + /// + /// Returns the given type as its most constrained/effective version according to its type and, possibly, its type constraints. + /// If no constrained version of the type is found, the type itself is returned. + /// In the case of an array type, the method can also optionally provide the most constrained version of the array's underlying type + /// + /// The type symbol which the method will attempt to resolve as a constrained/effective type + /// If true, the logic will apply on the underlying type of the array (i.e 'A' is the underlying array type of 'A[]') in the case the provided type is an . + /// If false, the method will simply return the array type in the case where in the case the provided type is an + /// If true, the given symbol, under its original or potentially reduced form, will be processed in order + /// to obtain a constrained type in the case where the symbol in question is a + /// The most constrained/effective version of the given symbol, or the symbol itself if no such constrained/effective type was found + public static ITypeSymbol GetUnderlyingTypeOrSelf(this ITypeSymbol typeSymbol, bool getReducedArrayType = true, bool tryResolvingGenericConstraint = true) + { + // Array type + var typeSymbolAsArrayType = typeSymbol as IArrayTypeSymbol; + if (typeSymbolAsArrayType != null) + { + if (getReducedArrayType) + { + typeSymbol = typeSymbolAsArrayType.ElementType; + } + else + { + return typeSymbolAsArrayType; + } + } + + // Named type + if (typeSymbol is INamedTypeSymbol) + { + return typeSymbol; + } + + // Type parameter + var typeAsTypeParameterSymbol = typeSymbol as ITypeParameterSymbol; + if (tryResolvingGenericConstraint && typeAsTypeParameterSymbol != null) + { + var typeAsConstrained = typeAsTypeParameterSymbol.TryGetAsConstrainedType(); + return typeAsConstrained ?? (ITypeSymbol)typeAsTypeParameterSymbol; + } + + return typeSymbol; + } + + + /// + /// Return a more display friendly name for some of the named types with abbreviated or otherwise vague names + /// + /// The named type symbol to get the name from + /// The display friendly version of the current type symbol if it exists, or simply its regular name if it does not + public static string GetDisplayFriendlyName(this ITypeSymbol current) + { + switch (current.SpecialType) + { + case SpecialType.System_Int16: + case SpecialType.System_Int32: + case SpecialType.System_Int64: + return "Integer"; + case SpecialType.System_UInt16: + case SpecialType.System_UInt32: + case SpecialType.System_UInt64: + return "UnsignedInteger"; + default: + return current.Name; + } + } + } +} diff --git a/src/Uno.CodeGen.RoslynHelpers/Uno.CodeGen.RoslynHelpers.projitems b/src/Uno.CodeGen.RoslynHelpers/Uno.CodeGen.RoslynHelpers.projitems new file mode 100644 index 0000000..5cb140d --- /dev/null +++ b/src/Uno.CodeGen.RoslynHelpers/Uno.CodeGen.RoslynHelpers.projitems @@ -0,0 +1,26 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + f099b362-19d8-450b-b9b2-dca3cdfcaab5 + + + Uno.CodeGen.RoslynHelpers + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Uno.CodeGen.RoslynHelpers/Uno.CodeGen.RoslynHelpers.shproj b/src/Uno.CodeGen.RoslynHelpers/Uno.CodeGen.RoslynHelpers.shproj new file mode 100644 index 0000000..6f85af7 --- /dev/null +++ b/src/Uno.CodeGen.RoslynHelpers/Uno.CodeGen.RoslynHelpers.shproj @@ -0,0 +1,13 @@ + + + + f099b362-19d8-450b-b9b2-dca3cdfcaab5 + 14.0 + + + + + + + + diff --git a/src/Uno.CodeGen.Tests.ExternalClasses/Uno.CodeGen.Tests.ExternalClasses.csproj b/src/Uno.CodeGen.Tests.ExternalClasses/Uno.CodeGen.Tests.ExternalClasses.csproj index 2250f27..b6c9711 100644 --- a/src/Uno.CodeGen.Tests.ExternalClasses/Uno.CodeGen.Tests.ExternalClasses.csproj +++ b/src/Uno.CodeGen.Tests.ExternalClasses/Uno.CodeGen.Tests.ExternalClasses.csproj @@ -12,12 +12,12 @@ - - + + all runtime; build; native; contentfiles; analyzers - + diff --git a/src/Uno.CodeGen.Tests.JsonDisabled/Uno.CodeGen.Tests.JsonDisabled.csproj b/src/Uno.CodeGen.Tests.JsonDisabled/Uno.CodeGen.Tests.JsonDisabled.csproj index 99ce869..23c8144 100644 --- a/src/Uno.CodeGen.Tests.JsonDisabled/Uno.CodeGen.Tests.JsonDisabled.csproj +++ b/src/Uno.CodeGen.Tests.JsonDisabled/Uno.CodeGen.Tests.JsonDisabled.csproj @@ -12,9 +12,9 @@ - + - + diff --git a/src/Uno.CodeGen.Tests.MinimalDeps/Uno.CodeGen.Tests.MinimalDeps.csproj b/src/Uno.CodeGen.Tests.MinimalDeps/Uno.CodeGen.Tests.MinimalDeps.csproj index 1c412d8..5b80658 100644 --- a/src/Uno.CodeGen.Tests.MinimalDeps/Uno.CodeGen.Tests.MinimalDeps.csproj +++ b/src/Uno.CodeGen.Tests.MinimalDeps/Uno.CodeGen.Tests.MinimalDeps.csproj @@ -20,7 +20,7 @@ --> - + diff --git a/src/Uno.CodeGen.Tests/Uno.CodeGen.Tests.csproj b/src/Uno.CodeGen.Tests/Uno.CodeGen.Tests.csproj index 21731f8..8fea753 100644 --- a/src/Uno.CodeGen.Tests/Uno.CodeGen.Tests.csproj +++ b/src/Uno.CodeGen.Tests/Uno.CodeGen.Tests.csproj @@ -1,52 +1,55 @@  - - net461 - false - 1701;1702;1705;NU1701 - Uno.CodeGen.Tests.ruleset - - - - - - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers - - - NU1701 - - - - - - - - - - - - - - - - - - - - + + net461 + false + 1701;1702;1705;NU1701 + Uno.CodeGen.Tests.ruleset + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers + + + NU1701 + + + + + + + + + + + + + + + + + + + + diff --git a/src/Uno.CodeGen.sln b/src/Uno.CodeGen.sln index 35be8d4..4b3cd53 100644 --- a/src/Uno.CodeGen.sln +++ b/src/Uno.CodeGen.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27130.2024 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31320.298 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.CodeGen", "Uno.CodeGen\Uno.CodeGen.csproj", "{7A05DD54-F3F1-4A48-97A5-1A5F45D9F315}" EndProject @@ -35,7 +35,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.CodeGen.Tests.MinimalDe EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.CodeGen.Tests.JsonDisabled", "Uno.CodeGen.Tests.JsonDisabled\Uno.CodeGen.Tests.JsonDisabled.csproj", "{8A1F7BE0-46F6-455B-8720-5B0698843733}" EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Uno.CodeGen.RoslynHelpers", "Uno.CodeGen.RoslynHelpers\Uno.CodeGen.RoslynHelpers.shproj", "{F099B362-19D8-450B-B9B2-DCA3CDFCAAB5}" +EndProject Global + GlobalSection(SharedMSBuildProjectFiles) = preSolution + Uno.CodeGen.RoslynHelpers\Uno.CodeGen.RoslynHelpers.projitems*{3f7d2a75-2fbe-4b2c-ab93-1fbf7effe3c9}*SharedItemsImports = 5 + Uno.CodeGen.RoslynHelpers\Uno.CodeGen.RoslynHelpers.projitems*{f099b362-19d8-450b-b9b2-dca3cdfcaab5}*SharedItemsImports = 13 + EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU diff --git a/src/Uno.CodeGen/Uno.CodeGen.csproj b/src/Uno.CodeGen/Uno.CodeGen.csproj index 6df42b0..b1f41e1 100644 --- a/src/Uno.CodeGen/Uno.CodeGen.csproj +++ b/src/Uno.CodeGen/Uno.CodeGen.csproj @@ -19,18 +19,20 @@ - + - + - - + + compile; build; native; contentfiles; analyzers; buildtransitive + + all runtime; build; native; contentfiles; analyzers - + NU1701 diff --git a/src/Uno.Equality/Uno.Equality.csproj b/src/Uno.Equality/Uno.Equality.csproj index 09384e5..d0d73b9 100644 --- a/src/Uno.Equality/Uno.Equality.csproj +++ b/src/Uno.Equality/Uno.Equality.csproj @@ -1,34 +1,34 @@ - - net461;netstandard1.3;netstandard2.0 - Equality Declarations - true - True - - full - True - nventive - nventive + + net461;netstandard1.3;netstandard2.0 + Equality Declarations + true + True + + full + True + nventive + nventive This package provides attributes for Equality source code generation. This package is part of the Uno.CodeGen to generate equality members in your project. - Uno.Equality - bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml - Copyright (C) 2015-2018 nventive inc. - all rights reserved + Uno.Equality + bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml + Copyright (C) 2015-2018 nventive inc. - all rights reserved https://github.com/unoplatform/Uno.CodeGen https://github.com/unoplatform/Uno.CodeGen uno.png - - - - - - - all - runtime; build; native; contentfiles; analyzers - + + + + + + + all + runtime; build; native; contentfiles; analyzers + - - + + diff --git a/src/Uno.Immutables/Uno.Immutables.csproj b/src/Uno.Immutables/Uno.Immutables.csproj index 5a3701b..8be9bd3 100644 --- a/src/Uno.Immutables/Uno.Immutables.csproj +++ b/src/Uno.Immutables/Uno.Immutables.csproj @@ -1,39 +1,39 @@ - - net461;netstandard1.3;netstandard2.0 - Immutable Declarations - true - True - - full - True - nventive - nventive + + net461;netstandard1.3;netstandard2.0 + Immutable Declarations + true + True + + full + True + nventive + nventive This package provides attributes for immutable entities source code generation. This package is part of the Uno.CodeGen to generate immutable entities in your project. - Uno - bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml + Uno + bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml https://github.com/unoplatform/Uno.CodeGen https://github.com/unoplatform/Uno.CodeGen - Copyright (C) 2015-2018 nventive inc. - all rights reserved + Copyright (C) 2015-2018 nventive inc. - all rights reserved uno.png - - - - - - - - all - runtime; build; native; contentfiles; analyzers - + + + + + + + + all + runtime; build; native; contentfiles; analyzers + - + - - - + + + diff --git a/src/Uno.Injectable/Uno.Injectable.csproj b/src/Uno.Injectable/Uno.Injectable.csproj index 656a875..05afc77 100644 --- a/src/Uno.Injectable/Uno.Injectable.csproj +++ b/src/Uno.Injectable/Uno.Injectable.csproj @@ -1,34 +1,34 @@ - - net461;netstandard1.3;netstandard2.0 - Injectable Declarations - true - True - - full - True - nventive - nventive + + net461;netstandard1.3;netstandard2.0 + Injectable Declarations + true + True + + full + True + nventive + nventive This package provides attributes for injectable entities source code generation. This package is part of the Uno.CodeGen to generate injectable entities in your project. - Uno - bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml + Uno + bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml https://github.com/unoplatform/Uno.CodeGen https://github.com/unoplatform/Uno.CodeGen - Copyright (C) 2015-2018 nventive inc. - all rights reserved + Copyright (C) 2015-2018 nventive inc. - all rights reserved uno.png - - - - - - - all - runtime; build; native; contentfiles; analyzers - + + + + + + + all + runtime; build; native; contentfiles; analyzers + - +