Fixed problem with inheritance from external assembly
This commit is contained in:
Родитель
c2e1ced64a
Коммит
e8e153880d
|
@ -0,0 +1,9 @@
|
|||
namespace Uno.CodeGen.Tests.ExternalClass
|
||||
{
|
||||
[GeneratedImmutable]
|
||||
public abstract partial class AbstractExternalClass
|
||||
{
|
||||
[EqualityHash]
|
||||
public string Id { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
namespace Uno.CodeGen.Tests.ExternalClass
|
||||
{
|
||||
[GeneratedImmutable]
|
||||
public abstract partial class AbstractExternalGenericClass<T>
|
||||
{
|
||||
[EqualityHash]
|
||||
public T Id { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
namespace Uno.CodeGen.Tests.ExternalClass
|
||||
{
|
||||
[GeneratedImmutable]
|
||||
public partial class ConcreteExternalClass
|
||||
{
|
||||
[EqualityHash]
|
||||
public string Id { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net46;netstandard2.0;netstandard1.6</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<SourceGenerator Include="..\Uno.CodeGen\bin\$(Configuration)\net46\Uno.CodeGen.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\Uno.CodeGen\build\Uno.CodeGen.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="4.4.1" />
|
||||
<PackageReference Include="Uno.SourceGenerationTasks" Version="1.20.0-dev.17" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Uno.Equality\Uno.Equality.csproj" />
|
||||
<ProjectReference Include="..\Uno.Immutables\Uno.Immutables.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -18,6 +18,7 @@ using System.Collections.Generic;
|
|||
using System.Collections.Immutable;
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Uno.Equality;
|
||||
|
||||
namespace Uno.CodeGen.Tests
|
||||
{
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
// ******************************************************************
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Uno.Equality;
|
||||
|
||||
namespace Uno.CodeGen.Tests
|
||||
{
|
||||
|
@ -39,6 +40,7 @@ namespace Uno.CodeGen.Tests
|
|||
e1.Equals(e2).Should().BeFalse();
|
||||
e1.KeyEquals(e2).Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void KeyEquality_WhenUsingEqualityMode()
|
||||
{
|
||||
|
@ -58,6 +60,25 @@ namespace Uno.CodeGen.Tests
|
|||
e1.KeyEquals(e2).Should().BeFalse();
|
||||
e1.IdField.KeyEquals(e2.IdField).Should().BeTrue();
|
||||
}
|
||||
|
||||
//[TestMethod]
|
||||
//public void KeyEquality_WhenUsingKeyEqualityMode_OnAbstractClass()
|
||||
//{
|
||||
// var e1 = new KeyEqualityConcreteWrapper.Builder
|
||||
// {
|
||||
// IdField = new KeyEqualityId.Builder { Id = "a", Name = "n" },
|
||||
// NonKeyField = "nkf1"
|
||||
// }.ToImmutable();
|
||||
|
||||
// var e2 = new KeyEqualityWrapper.Builder
|
||||
// {
|
||||
// IdField = new KeyEqualityConcreteWrapper.Builder { Id = "a", Name = "n-bis" },
|
||||
// NonKeyField = "nkf2"
|
||||
// }.ToImmutable();
|
||||
|
||||
// e1.Equals(e2).Should().BeFalse();
|
||||
// e1.KeyEquals(e2).Should().BeTrue();
|
||||
//}
|
||||
}
|
||||
|
||||
[GeneratedImmutable]
|
||||
|
@ -86,4 +107,20 @@ namespace Uno.CodeGen.Tests
|
|||
|
||||
public string Name { get; }
|
||||
}
|
||||
|
||||
[GeneratedImmutable]
|
||||
public abstract partial class KeyEqualityAbstractWrapper<T>
|
||||
where T:IKeyEquatable<T>
|
||||
{
|
||||
[EqualityKey]
|
||||
public T IdField { get; }
|
||||
|
||||
public string NonKeyField { get; }
|
||||
}
|
||||
|
||||
[GeneratedImmutable]
|
||||
public abstract partial class KeyEqualityConcreteWrapper : KeyEqualityAbstractWrapper<KeyEqualityId>
|
||||
{
|
||||
public string NonKeyField2 { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
// ******************************************************************
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Uno.Equality;
|
||||
|
||||
namespace Uno.CodeGen.Tests
|
||||
{
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
// ******************************************************************
|
||||
// Copyright <20> 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 FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Uno.CodeGen.Tests.ExternalClass;
|
||||
using Uno.Equality;
|
||||
|
||||
namespace Uno.CodeGen.Tests
|
||||
{
|
||||
partial class Given_ImmutableEntity
|
||||
{
|
||||
[TestMethod]
|
||||
public void Immutable_When_Abstracted_Base_Class()
|
||||
{
|
||||
// var sut1 = InheritanceDerivedClass.Default.WithKeyValue(null);
|
||||
}
|
||||
}
|
||||
|
||||
//public interface IImmutable<out TBuilder>
|
||||
//{
|
||||
// TBuilder GetBuilder();
|
||||
//}
|
||||
|
||||
[GeneratedImmutable]
|
||||
public abstract partial class InheritanceAbstractBaseClass<T> // : IImmutable<InheritanceAbstractBaseClass<T>.Builder>
|
||||
where T : IKeyEquatable<T>
|
||||
{
|
||||
[EqualityKey]
|
||||
public T KeyValue { get; }
|
||||
|
||||
//public abstract TBuilder GetBuilder<TBuilder>() where TBuilder : Builder;
|
||||
|
||||
//Builder IImmutable<Builder>.GetBuilder()
|
||||
//{
|
||||
// throw new System.NotImplementedException();
|
||||
//}
|
||||
}
|
||||
|
||||
//[GeneratedImmutable]
|
||||
//public abstract partial class InheritanceAbstractBaseClass2<T> : InheritanceAbstractBaseClass<T>
|
||||
// where T : IKeyEquatable<T>
|
||||
//{
|
||||
// //Builder IImmutable<InheritanceAbstractBaseClass2<T>.Builder>.GetBuilder()
|
||||
// //{
|
||||
// // throw new System.NotImplementedException();
|
||||
// //}
|
||||
|
||||
//}
|
||||
|
||||
[GeneratedImmutable]
|
||||
public partial class InheritanceHashedClass
|
||||
{
|
||||
[EqualityKey]
|
||||
public string Id { get; }
|
||||
}
|
||||
|
||||
[GeneratedImmutable]
|
||||
public partial class InheritanceDerivedClass : InheritanceAbstractBaseClass<InheritanceHashedClass>
|
||||
{
|
||||
//public override TBuilder GetBuilder<TBuilder>() where TBuilder : Builder
|
||||
//{
|
||||
// throw new System.NotImplementedException();
|
||||
//}
|
||||
}
|
||||
|
||||
public partial class InheritanceDerivedClassFromExternal : AbstractExternalClass
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public partial class InheritanceDerivedClassFromExternalGeneric : AbstractExternalGenericClass<string>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -29,8 +29,13 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Uno.ClassLifecycle\Uno.ClassLifecycle.csproj" />
|
||||
<ProjectReference Include="..\Uno.CodeGen.Tests.ExternalClass\Uno.CodeGen.Tests.ExternalClass.csproj" />
|
||||
<ProjectReference Include="..\Uno.Equality\Uno.Equality.csproj" />
|
||||
<ProjectReference Include="..\Uno.Immutables\Uno.Immutables.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -26,6 +26,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.ClassLifecycle", "Uno.C
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.CodeGen.ClassLifecycle", "Uno.CodeGen.ClassLifecycle\Uno.CodeGen.ClassLifecycle.csproj", "{3F7D2A75-2FBE-4B2C-AB93-1FBF7EFFE3C9}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Uno.CodeGen.Tests.ExternalClass", "Uno.CodeGen.Tests.ExternalClass\Uno.CodeGen.Tests.ExternalClass.csproj", "{907C30BD-0984-4D75-8A43-107C98235F65}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -56,6 +58,10 @@ Global
|
|||
{3F7D2A75-2FBE-4B2C-AB93-1FBF7EFFE3C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3F7D2A75-2FBE-4B2C-AB93-1FBF7EFFE3C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3F7D2A75-2FBE-4B2C-AB93-1FBF7EFFE3C9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{907C30BD-0984-4D75-8A43-107C98235F65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{907C30BD-0984-4D75-8A43-107C98235F65}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{907C30BD-0984-4D75-8A43-107C98235F65}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{907C30BD-0984-4D75-8A43-107C98235F65}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Uno.SourceGeneration;
|
||||
|
||||
namespace Uno
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple generator outputing a list of all references used to compile the project.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Generates only one file containing only comments.
|
||||
/// </remarks>
|
||||
public class CompilationReferencesListingGenerator : SourceGenerator
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void Execute(SourceGeneratorContext context)
|
||||
{
|
||||
var output = new StringBuilder();
|
||||
|
||||
output.AppendLine("// This is the list of all external references used to compile this project:");
|
||||
|
||||
var lines = context
|
||||
.Compilation
|
||||
.References
|
||||
.OrderBy(r => r.Display, StringComparer.InvariantCultureIgnoreCase)
|
||||
.Select((r, i) => $"// #{i}: {r.Display}");
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
output.AppendLine(line);
|
||||
}
|
||||
|
||||
var filename = $"{nameof(CompilationReferencesListingGenerator)}.cs";
|
||||
context.AddCompilationUnit(filename, output.ToString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ using System.Threading;
|
|||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Uno.Equality;
|
||||
using Uno.Helpers;
|
||||
using Uno.RoslynHelpers;
|
||||
using Uno.SourceGeneration;
|
||||
|
@ -95,6 +96,7 @@ namespace Uno
|
|||
249449, // 22001st prime number
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Execute(SourceGeneratorContext context)
|
||||
{
|
||||
_context = context;
|
||||
|
|
|
@ -15,24 +15,28 @@
|
|||
//
|
||||
// ******************************************************************
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Uno.Helpers
|
||||
{
|
||||
public static class NamedTypeSymbolExtensions
|
||||
{
|
||||
public static SymbolNames GetSymbolNames(this INamedTypeSymbol typeSymbol)
|
||||
public static SymbolNames GetSymbolNames(this INamedTypeSymbol typeSymbol, INamedTypeSymbol typeToUseForSubstitutions = null)
|
||||
{
|
||||
var substitutions = typeToUseForSubstitutions.GetSubstitutionTypes();
|
||||
|
||||
var symbolName = typeSymbol.Name;
|
||||
if (typeSymbol.TypeArguments.Length == 0) // not a generic type
|
||||
{
|
||||
return new SymbolNames(typeSymbol, symbolName, "", symbolName, symbolName, symbolName, symbolName, "");
|
||||
}
|
||||
|
||||
var argumentNames = typeSymbol.GetTypeArgumentNames();
|
||||
var argumentNames = typeSymbol.GetTypeArgumentNames(substitutions);
|
||||
var genericArguments = string.Join(", ", argumentNames);
|
||||
|
||||
// symbolNameWithGenerics: MyType<T1, T2>
|
||||
|
@ -56,9 +60,43 @@ namespace Uno.Helpers
|
|||
return new SymbolNames(typeSymbol, symbolName, $"<{genericArguments}>", symbolNameWithGenerics, symbolForXml, symbolNameDefinition, symbolFilename, genericConstraints);
|
||||
}
|
||||
|
||||
public static string[] GetTypeArgumentNames(this ITypeSymbol typeSymbol)
|
||||
public static string[] GetTypeArgumentNames(
|
||||
this ITypeSymbol typeSymbol,
|
||||
(string argumentName, string type)[] substitutions)
|
||||
{
|
||||
return (typeSymbol as INamedTypeSymbol)?.TypeArguments.Select(ta => ta.ToString()).ToArray() ?? new string[0];
|
||||
if (typeSymbol is INamedTypeSymbol namedSymbol)
|
||||
{
|
||||
var dict = substitutions.ToDictionary(x => x.argumentName, x => x.type);
|
||||
|
||||
return namedSymbol.TypeArguments
|
||||
.Select(ta => ta.ToString())
|
||||
.Select(t=> dict.ContainsKey(t) ? dict[t] : t)
|
||||
.ToArray();
|
||||
}
|
||||
return new string[0];
|
||||
}
|
||||
|
||||
public static (string argumentName, string type)[] GetSubstitutionTypes(this INamedTypeSymbol type)
|
||||
{
|
||||
if (type == null || type.TypeArguments.Length == 0)
|
||||
{
|
||||
return new(string, string)[] { };
|
||||
}
|
||||
|
||||
var argumentParameters = type.TypeParameters;
|
||||
var argumentTypes = type.TypeArguments;
|
||||
|
||||
var result = new (string, string)[type.TypeArguments.Length];
|
||||
|
||||
for (var i = 0; i < argumentParameters.Length; i++)
|
||||
{
|
||||
var parameterType = argumentTypes[i] as INamedTypeSymbol;
|
||||
var parameterNames = parameterType.GetSymbolNames();
|
||||
|
||||
result[i]= (argumentParameters[i].Name, parameterNames.SymbolNameWithGenerics);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,6 +131,24 @@ namespace Uno.Helpers
|
|||
public string SymbolFilename { get; }
|
||||
public string GenericConstraints { get; }
|
||||
|
||||
public string GetContainingTypeFullName(INamedTypeSymbol typeForSubstitutions = null)
|
||||
{
|
||||
if (Symbol.ContainingType != null)
|
||||
{
|
||||
return Symbol
|
||||
.ContainingType
|
||||
.GetSymbolNames(typeForSubstitutions)
|
||||
.GetSymbolFullNameWithGenerics();
|
||||
}
|
||||
|
||||
return Symbol.ContainingNamespace.ToString();
|
||||
}
|
||||
|
||||
public string GetSymbolFullNameWithGenerics(INamedTypeSymbol typeForSubstitutions = null)
|
||||
{
|
||||
return $"{GetContainingTypeFullName(typeForSubstitutions)}.{SymbolNameWithGenerics}";
|
||||
}
|
||||
|
||||
public void Deconstruct(
|
||||
out string symbolName,
|
||||
out string genericArguments,
|
||||
|
|
|
@ -14,11 +14,17 @@
|
|||
// limitations under the License.
|
||||
//
|
||||
// ******************************************************************
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace Uno.Helpers
|
||||
{
|
||||
|
@ -325,5 +331,55 @@ namespace Uno.Helpers
|
|||
(keyType, valueType, isReadonlyDictionary) = ImmutableInterlocked.GetOrAdd(ref _isDictionary, type, GetIsACollection);
|
||||
return keyType != null;
|
||||
}
|
||||
|
||||
private static MethodInfo _isAutoPropertyGetter;
|
||||
|
||||
public static bool IsAutoProperty(this IPropertySymbol symbol)
|
||||
{
|
||||
if (symbol.IsWithEvents || symbol.IsIndexer || !symbol.IsReadOnly)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (!Equals(symbol.OriginalDefinition, symbol))
|
||||
{
|
||||
// In some cases we're dealing with a derived type of `WrappedPropertySymbol`.
|
||||
// This code needs to deal with the SourcePropertySymbol from Roslyn,
|
||||
// the type containing the `IsAutoProperty` internal member.
|
||||
symbol = symbol.OriginalDefinition;
|
||||
}
|
||||
|
||||
var type = symbol.GetType();
|
||||
switch (type.FullName)
|
||||
{
|
||||
case "Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE.PEPropertySymbol":
|
||||
return symbol.IsReadOnly; // It's from compiled code. We assume it's an auto-property when "read only"
|
||||
case "Microsoft.CodeAnalysis.CSharp.Symbols.SourcePropertySymbol":
|
||||
break; // ok
|
||||
default:
|
||||
throw new InvalidOperationException(
|
||||
"Unable to find the internal property `IsAutoProperty` on implementation of `IPropertySymbol`. " +
|
||||
"Should be on internal class `PropertySymbol`. Maybe you are using an incompatible version of Roslyn.");
|
||||
}
|
||||
|
||||
if (_isAutoPropertyGetter == null)
|
||||
{
|
||||
_isAutoPropertyGetter = type
|
||||
.GetProperty("IsAutoProperty", BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
.GetMethod;
|
||||
}
|
||||
|
||||
var isAuto = _isAutoPropertyGetter.Invoke(symbol, new object[] { });
|
||||
return (bool) isAuto;
|
||||
}
|
||||
|
||||
public static bool IsFromPartialDeclaration(this ISymbol symbol)
|
||||
{
|
||||
return symbol
|
||||
.DeclaringSyntaxReferences
|
||||
.Select(reference => reference.GetSyntax(CancellationToken.None))
|
||||
.OfType<ClassDeclarationSyntax>()
|
||||
.Any(node => node.Modifiers.Any(SyntaxKind.PartialKeyword));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|||
using Uno.Helpers;
|
||||
using Uno.RoslynHelpers;
|
||||
using Uno.SourceGeneration;
|
||||
using TypeSymbolExtensions = Uno.Helpers.TypeSymbolExtensions;
|
||||
|
||||
namespace Uno
|
||||
{
|
||||
|
@ -51,6 +52,7 @@ namespace Uno
|
|||
|
||||
private Regex[] _copyIgnoreAttributeRegexes;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Execute(SourceGeneratorContext context)
|
||||
{
|
||||
_context = context;
|
||||
|
@ -141,24 +143,28 @@ namespace Uno
|
|||
return shouldGenerateEquality ?? _generationOptions.generateEqualityByDefault;
|
||||
}
|
||||
|
||||
private (bool isBaseType, string baseType, string builderBaseType, bool isImmutablePresent) GetTypeInfo(
|
||||
private (bool isBaseTypePresent, string baseType, string builderBaseType, bool isImmutablePresent) GetTypeInfo(
|
||||
SourceGeneratorContext context,
|
||||
INamedTypeSymbol type, INamedTypeSymbol[] immutableEntitiesToGenerate)
|
||||
{
|
||||
// Check if [Immutable] is present on the non-generated partial
|
||||
var isImmutablePresent = type.FindAttributeFlattened(_immutableAttributeSymbol) != null;
|
||||
|
||||
var baseType = type.BaseType;
|
||||
if (baseType == null || baseType.Equals(_systemObject))
|
||||
{
|
||||
return (false, null, null, false); // no base type
|
||||
return (false, null, null, isImmutablePresent); // no base type
|
||||
}
|
||||
|
||||
// Check if [Immutable] is present on the non-generated partial
|
||||
var isImmutablePresent = baseType.FindAttributeFlattened(_immutableAttributeSymbol) != null;
|
||||
|
||||
// Is Builder already compiled ? (in another project/assembly)
|
||||
var builderAttribute = baseType.FindAttributeFlattened(_immutableBuilderAttributeSymbol);
|
||||
var builderAttribute = baseType.FindAttribute(_immutableBuilderAttributeSymbol);
|
||||
if (builderAttribute != null)
|
||||
{
|
||||
return (true, null, null, true); // no relevant basetype
|
||||
var baseTypeBuilder = builderAttribute.ConstructorArguments[0].Value as INamedTypeSymbol;
|
||||
var baseTypeNames = baseType.GetSymbolNames();
|
||||
var baseTypeBuilderNames = baseTypeBuilder.GetSymbolNames(baseType);
|
||||
|
||||
return (true, baseTypeNames.GetSymbolFullNameWithGenerics(baseType), baseTypeBuilderNames.GetSymbolFullNameWithGenerics(baseType), isImmutablePresent);
|
||||
}
|
||||
|
||||
var baseTypeDefinition = baseType.ConstructedFrom ?? baseType;
|
||||
|
@ -175,11 +181,11 @@ namespace Uno
|
|||
return (true, baseTypeName, builderBaseType, isImmutablePresent);
|
||||
}
|
||||
|
||||
return (true, null, null, false); // no relevant basetype
|
||||
return (false, null, null, isImmutablePresent); // no relevant basetype
|
||||
}
|
||||
|
||||
private void GenerateImmutable(INamedTypeSymbol typeSymbol,
|
||||
(bool isBaseType, string baseType, string builderBaseType, bool isImmutablePresent) baseTypeInfo,
|
||||
(bool isBaseTypePresent, string baseType, string builderBaseType, bool isImmutablePresent) baseTypeInfo,
|
||||
bool generateEquality)
|
||||
{
|
||||
var defaultMemberName = "Default";
|
||||
|
@ -193,22 +199,22 @@ namespace Uno
|
|||
|
||||
var typeProperties = typeSymbol.GetProperties().ToArray();
|
||||
|
||||
if (baseTypeInfo.isBaseType)
|
||||
if (baseTypeInfo.isBaseTypePresent)
|
||||
{
|
||||
var baseProperties = typeSymbol.BaseType.GetProperties()
|
||||
.Where(x => x.IsReadOnly && IsAutoProperty(x))
|
||||
.Where(x => x.IsReadOnly && x.IsAutoProperty())
|
||||
.Select(x => x.Name)
|
||||
.ToArray();
|
||||
|
||||
properties = typeProperties
|
||||
.Where(x => x.IsReadOnly && IsAutoProperty(x))
|
||||
.Where(x => x.IsReadOnly && x.IsAutoProperty())
|
||||
.Select(x => (x, baseProperties.Contains(x.Name))) // remove properties already present in base class
|
||||
.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
properties = typeProperties
|
||||
.Where(x => x.IsReadOnly && IsAutoProperty(x))
|
||||
.Where(x => x.IsReadOnly && x.IsAutoProperty())
|
||||
.Select(x => (x, false))
|
||||
.ToArray();
|
||||
}
|
||||
|
@ -220,14 +226,14 @@ namespace Uno
|
|||
|
||||
ValidateType(builder, typeSymbol, baseTypeInfo, symbolNames, typeProperties);
|
||||
|
||||
var newModifier = baseTypeInfo.isBaseType ? "new " : "";
|
||||
var newModifier = baseTypeInfo.isBaseTypePresent ? "new " : "";
|
||||
|
||||
builder.AppendLineInvariant("using System;");
|
||||
builder.AppendLine();
|
||||
builder.AppendLineInvariant("// <auto-generated>");
|
||||
builder.AppendLineInvariant("// *****************************************************************************************************************");
|
||||
builder.AppendLineInvariant("// This has been generated by Uno.CodeGen (ImmutableGenerator), available at https://github.com/nventive/Uno.CodeGen");
|
||||
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("// **********************************************************************************************************************");
|
||||
builder.AppendLineInvariant("// </auto-generated>");
|
||||
builder.AppendLine();
|
||||
|
||||
|
@ -236,11 +242,11 @@ namespace Uno
|
|||
string builderTypeNameAndBaseClass;
|
||||
if (typeSymbol.IsAbstract)
|
||||
{
|
||||
builderTypeNameAndBaseClass = baseTypeInfo.isBaseType ? $"Builder : {baseTypeInfo.builderBaseType}" : $"Builder";
|
||||
builderTypeNameAndBaseClass = baseTypeInfo.isBaseTypePresent ? $"Builder : {baseTypeInfo.builderBaseType}" : $"Builder";
|
||||
}
|
||||
else
|
||||
{
|
||||
builderTypeNameAndBaseClass = baseTypeInfo.isBaseType
|
||||
builderTypeNameAndBaseClass = baseTypeInfo.isBaseTypePresent
|
||||
? $"Builder : {baseTypeInfo.builderBaseType}, global::Uno.IImmutableBuilder<{symbolNameWithGenerics}>"
|
||||
: $"Builder : global::Uno.IImmutableBuilder<{symbolNameWithGenerics}>";
|
||||
}
|
||||
|
@ -277,8 +283,22 @@ namespace Uno
|
|||
builder.AppendLineInvariant($"/// </summary>");
|
||||
builder.AppendLineInvariant($"public static readonly {newModifier}{symbolNameWithGenerics} {defaultMemberName} = new {symbolNameWithGenerics}();");
|
||||
|
||||
//builder.AppendLine();
|
||||
|
||||
//builder.AppendLineInvariant($"/// <summary>");
|
||||
//builder.AppendLineInvariant($"/// {defaultMemberName} instance with only property initializer set.");
|
||||
//builder.AppendLineInvariant($"/// </summary>");
|
||||
//using (builder.BlockInvariant($"internal {newModifier}{symbolNameWithGenerics} {defaultMemberName}({symbolNameWithGenerics} original = default({symbolNameWithGenerics}));"))
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
|
||||
builder.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
var prop1Name = properties.Select(p => p.property.Name).FirstOrDefault() ?? symbolName + "Property";
|
||||
builder.AppendLineInvariant($"/// <summary>");
|
||||
|
@ -301,14 +321,14 @@ namespace Uno
|
|||
using (builder.BlockInvariant(
|
||||
$"{typeSymbol.GetAccessibilityAsCSharpCodeString()} {newModifier}partial class {builderTypeNameAndBaseClass}"))
|
||||
{
|
||||
if (!baseTypeInfo.isBaseType)
|
||||
if (!baseTypeInfo.isBaseTypePresent)
|
||||
{
|
||||
// _isDirty only on base builder (will be reused in derived builders)
|
||||
builder.AppendLineInvariant("// Dirty means there's a difference from `_original`.");
|
||||
builder.AppendLineInvariant("protected bool _isDirty = false;");
|
||||
builder.AppendLine();
|
||||
builder.AppendLineInvariant("// This is the original entity, if any (could be null))");
|
||||
builder.AppendLineInvariant("{0}", $"internal readonly {symbolNameWithGenerics} _original;");
|
||||
builder.AppendLineInvariant("{0}", $"protected internal readonly {symbolNameWithGenerics} _original;");
|
||||
builder.AppendLine();
|
||||
builder.AppendLineInvariant("// Cached version of generated entity (flushed when the builder is updated)");
|
||||
builder.AppendLineInvariant($"protected {symbolNameWithGenerics} _cachedResult = default({symbolNameWithGenerics});");
|
||||
|
@ -448,6 +468,13 @@ return ({symbolNameWithGenerics})(_cachedResult = _original);");
|
|||
|
||||
builder.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLineInvariant($"// Since {symbolNameWithGenerics} is abstract, there is no .ToImmutable():");
|
||||
builder.AppendLineInvariant($"// you should call it on a derived class, which should implement it.");
|
||||
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
if (properties.Any())
|
||||
{
|
||||
|
@ -578,7 +605,7 @@ public static implicit operator global::Uno.Option<{symbolNameWithGenerics}>(Bui
|
|||
builder.AppendLineInvariant("/// </remarks>");
|
||||
builder.AppendLineInvariant($"/// <param name=\"builder\">The builder for {symbolNameForXml}.</param>");
|
||||
|
||||
var baseConstructorChaining = baseTypeInfo.isBaseType
|
||||
var baseConstructorChaining = baseTypeInfo.isBaseTypePresent
|
||||
? " : base(builder)"
|
||||
: "";
|
||||
|
||||
|
@ -753,7 +780,7 @@ $@"public sealed class {symbolName}BuilderJsonConverterTo{symbolName}{genericArg
|
|||
(bool isBaseType, string baseType, string builderBaseType, bool isImmutablePresent) baseTypeInfo,
|
||||
SymbolNames symbolNames, IPropertySymbol[] typeProperties)
|
||||
{
|
||||
if (!IsFromPartialDeclaration(typeSymbol))
|
||||
if (!typeSymbol.IsFromPartialDeclaration())
|
||||
{
|
||||
builder.AppendLineInvariant(
|
||||
$"#warning {nameof(ImmutableGenerator)}: you should add the partial modifier to the class {symbolNames.SymbolNameWithGenerics}.");
|
||||
|
@ -892,55 +919,11 @@ $@"public sealed class {symbolName}BuilderJsonConverterTo{symbolName}{genericArg
|
|||
return string.Join("", Enumerate());
|
||||
}
|
||||
|
||||
private static MethodInfo _isAutoPropertyGetter;
|
||||
|
||||
private static bool IsAutoProperty(IPropertySymbol symbol)
|
||||
{
|
||||
if (symbol.IsWithEvents || symbol.IsIndexer || !symbol.IsReadOnly)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (!Equals(symbol.OriginalDefinition, symbol))
|
||||
{
|
||||
// In some cases we're dealing with a derived type of `WrappedPropertySymbol`.
|
||||
// This code needs to deal with the SourcePropertySymbol from Roslyn,
|
||||
// the type containing the `IsAutoProperty` internal member.
|
||||
symbol = symbol.OriginalDefinition;
|
||||
}
|
||||
|
||||
if (_isAutoPropertyGetter == null)
|
||||
{
|
||||
var type = symbol.GetType();
|
||||
var propertyInfo = type.GetProperty("IsAutoProperty", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (propertyInfo == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Unable to find the internal property `IsAutoProperty` on implementation of `IPropertySymbol`. " +
|
||||
"Should be on internal class `PropertySymbol`. Maybe you are using an incompatible version of Roslyn.");
|
||||
}
|
||||
|
||||
_isAutoPropertyGetter = propertyInfo?.GetMethod;
|
||||
}
|
||||
|
||||
var isAuto = _isAutoPropertyGetter.Invoke(symbol, new object[] { });
|
||||
return (bool) isAuto;
|
||||
}
|
||||
|
||||
private IEnumerable<(INamedTypeSymbol symbol, AttributeData attribute)> EnumerateImmutableGeneratedEntities()
|
||||
=> from type in _context.Compilation.SourceModule.GlobalNamespace.GetNamespaceTypes()
|
||||
let moduleAttribute = type.FindAttributeFlattened(_generatedImmutableAttributeSymbol)
|
||||
where moduleAttribute != null
|
||||
//where (bool) moduleAttribute.ConstructorArguments[0].Value
|
||||
select (type, moduleAttribute);
|
||||
|
||||
private static bool IsFromPartialDeclaration(ISymbol symbol)
|
||||
{
|
||||
return symbol
|
||||
.DeclaringSyntaxReferences
|
||||
.Select(reference => reference.GetSyntax(CancellationToken.None))
|
||||
.OfType<ClassDeclarationSyntax>()
|
||||
.Any(node => node.Modifiers.Any(SyntaxKind.PartialKeyword));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"profiles": {
|
||||
"Uno.CodeGen": {
|
||||
"commandName": "Executable",
|
||||
"executablePath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Professional\\MSBuild\\15.0\\Bin\\MSBuild.exe",
|
||||
"commandLineArgs": "..\\Uno.CodeGen.Tests\\Uno.CodeGen.Tests.csproj /p:Configuration=Debug"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,7 +37,6 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Uno.ClassLifecycle.Generator\Uno.CodeGen.ClassLifecycle.csproj" />
|
||||
<ProjectReference Include="..\Uno.Equality\Uno.Equality.csproj" />
|
||||
<ProjectReference Include="..\Uno.Immutables\Uno.Immutables.csproj" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
// limitations under the License.
|
||||
//
|
||||
// ******************************************************************
|
||||
namespace Uno
|
||||
namespace Uno.Equality
|
||||
{
|
||||
/// <summary>
|
||||
/// Use to qualify the collection mode in <see cref="EqualityComparerOptionsAttribute"/> attribute.
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
// ******************************************************************
|
||||
using System;
|
||||
|
||||
namespace Uno
|
||||
namespace Uno.Equality
|
||||
{
|
||||
/// <summary>
|
||||
/// Attribute to put on a collection field/property to specify the kind
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
//
|
||||
// ******************************************************************
|
||||
using System;
|
||||
using Uno.Equality;
|
||||
|
||||
namespace Uno
|
||||
{
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
// limitations under the License.
|
||||
//
|
||||
// ******************************************************************
|
||||
namespace Uno
|
||||
namespace Uno.Equality
|
||||
{
|
||||
/// <summary>
|
||||
/// Mode to use for <see cref="EqualityKeyAttribute"/>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
// ******************************************************************
|
||||
using System;
|
||||
|
||||
namespace Uno
|
||||
namespace Uno.Equality
|
||||
{
|
||||
/// <summary>
|
||||
/// Use to qualify the string mode in <see cref="EqualityComparerOptionsAttribute"/> attribute.
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<Company>nventive</Company>
|
||||
<Description>This package provides attributes for Equality source code generation.
|
||||
This package is part of the Uno.CodeGen to generate equality members in your project.</Description>
|
||||
<RootNamespace>Uno</RootNamespace>
|
||||
<RootNamespace>Uno.Equality</RootNamespace>
|
||||
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
|
||||
<Copyright>Copyright (C) 2015-2018 nventive inc. - all rights reserved</Copyright>
|
||||
<PackageProjectUrl>https://github.com/nventive/Uno.CodeGen</PackageProjectUrl>
|
||||
|
|
Загрузка…
Ссылка в новой задаче