Skip to content

Commit

Permalink
Authoring bug fixes and xaml type mapping (#666)
Browse files Browse the repository at this point in the history
* Add support for attributes on synthesized interface members.

* Add support for XAML type mappings.

* Allow inheriting class member attributes from interfaces.
  • Loading branch information
manodasanW committed Jan 15, 2021
1 parent 86895f6 commit fb0e7ad
Show file tree
Hide file tree
Showing 8 changed files with 615 additions and 132 deletions.
39 changes: 38 additions & 1 deletion src/Authoring/WinRT.SourceGenerator/DiagnosticHelpers.cs
Expand Up @@ -3,6 +3,7 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Runtime.CompilerServices;
using WinRT.SourceGenerator;
Expand Down Expand Up @@ -167,6 +168,12 @@ private bool MatchesAnyAttribute(string attrName, SyntaxList<AttributeListSyntax
return false;
}

private bool MatchesAnyAttribute(string attrName, ImmutableArray<AttributeData> attributes)
{
string attrClassName = attrName + "Attribute";
return attributes.Any((attr) => attr.AttributeClass.Name == attrClassName);
}

/// <summary>
/// Checks to see if an array parameter has been marked with both Write and Read attributes
/// Does extra work, by catching `ref` params, done here since this code can be used by class or interface related methods</summary>
Expand Down Expand Up @@ -241,10 +248,40 @@ private void ParameterHasAttributeErrors(MethodDeclarationSyntax method)
private bool ParamHasReadOnlyAttribute(ParameterSyntax param) { return ReadOnlyArrayAttributeNames.Where(str => ParamHasAttribute(param, str)).Any(); }
private bool ParamHasWriteOnlyAttribute(ParameterSyntax param) { return WriteOnlyArrayAttributeNames.Where(str => ParamHasAttribute(param, str)).Any(); }

private ISymbol GetInterfaceMemberFromClassMember(ISymbol classMember)
{
var parent = classMember.ContainingType;
foreach (var @interface in parent.AllInterfaces)
{
foreach (var interfaceMember in @interface.GetMembers())
{
if (SymbolEqualityComparer.Default.Equals(parent.FindImplementationForInterfaceMember(interfaceMember), classMember))
{
return interfaceMember;
}
}
}

return null;
}

/// <summary>Check for qualified and unqualified [DefaultOverload] attribute on the parameter<</summary>
/// <param name="method"></param>
/// <returns>True if any attribute is the DefaultOverload attribute</returns>
private bool HasDefaultOverloadAttribute(MethodDeclarationSyntax method) { return OverloadAttributeNames.Where(str => MatchesAnyAttribute(str, method.AttributeLists)).Any(); }
private bool HasDefaultOverloadAttribute(MethodDeclarationSyntax method)
{
if(OverloadAttributeNames.Where(str => MatchesAnyAttribute(str, method.AttributeLists)).Any())
{
return true;
}

var interfaceMember = GetInterfaceMemberFromClassMember(GetModel(method.SyntaxTree).GetDeclaredSymbol(method));
if (interfaceMember == null)
{
return false;
}
return OverloadAttributeNames.Where(str => MatchesAnyAttribute(str, interfaceMember.GetAttributes())).Any();
}

/// <summary>
/// Keeps track of repeated declarations of a method (overloads) and raises diagnostics according to the rule that exactly one overload should be attributed the default</summary>
Expand Down
16 changes: 15 additions & 1 deletion src/Authoring/WinRT.SourceGenerator/Helper.cs
@@ -1,4 +1,5 @@
using System;
using Microsoft.CodeAnalysis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
Expand Down Expand Up @@ -31,5 +32,18 @@ public static Guid EncodeGuid(byte[] data)
}
return new Guid(data.Take(16).ToArray());
}
}

class AttributeDataComparer : IEqualityComparer<AttributeData>
{
public bool Equals(AttributeData x, AttributeData y)
{
return x.ToString() == y.ToString();
}

public int GetHashCode(AttributeData obj)
{
return obj.ToString().GetHashCode();
}
}
}
434 changes: 314 additions & 120 deletions src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs

Large diffs are not rendered by default.

Expand Up @@ -6,6 +6,10 @@
name="AuthoringTest.BasicClass"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="AuthoringTest.CustomCommand"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="AuthoringTest.CustomDictionary"
threadingModel="both"
Expand All @@ -18,14 +22,22 @@
name="AuthoringTest.CustomVector"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="AuthoringTest.CustomVector2"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="AuthoringTest.CustomVectorView"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="AuthoringTest.CustomWWW"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="AuthoringTest.CustomXamlServiceProvider"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="AuthoringTest.DisposableClass"
threadingModel="both"
Expand Down
5 changes: 5 additions & 0 deletions src/Tests/AuthoringConsumptionTest/pch.h
Expand Up @@ -15,6 +15,11 @@
#pragma pop_macro("X64")
#pragma pop_macro("X86")

#include <winrt/Microsoft.UI.Xaml.h>
#include <winrt/Microsoft.UI.Xaml.Input.h>
#include <winrt/Microsoft.UI.Xaml.Interop.h>
#include <winrt/Windows.UI.Xaml.Interop.h>

#include <winrt/AuthoringTest.h>

#include "gtest/gtest.h"
52 changes: 52 additions & 0 deletions src/Tests/AuthoringConsumptionTest/test.cpp
Expand Up @@ -390,4 +390,56 @@ TEST(AuthoringTest, DISABLED_CustomVectorImplementations)

vector.Clear();
EXPECT_EQ(vector.Size(), 0);
}

TEST(AuthoringTest, Overloads)
{
TestClass testClass;
EXPECT_EQ(testClass.Get(2), 2);
EXPECT_EQ(testClass.Get(L"CsWinRT"), L"CsWinRT");
EXPECT_EQ(testClass.GetNumStr(4.1), L"4.1");
EXPECT_EQ(testClass.GetNumStr(4), L"4");

IDouble doubleInterface = testClass;
EXPECT_EQ(doubleInterface.GetNumStr(2.2), L"2.2");
EXPECT_EQ(doubleInterface.GetNumStr(8), L"8");
}

TEST(AuthoringTest, XamlMappings)
{
CustomVector2 vector;
EXPECT_EQ(vector.Size(), 0);
vector.Append(DisposableClass());
vector.Append(DisposableClass());
vector.Append(TestClass());
EXPECT_EQ(vector.Size(), 3);

auto first = vector.First();
EXPECT_TRUE(first.HasCurrent());
EXPECT_FALSE(first.Current().as<DisposableClass>().IsDisposed());
first.Current().as<DisposableClass>().Close();
EXPECT_TRUE(first.Current().as<DisposableClass>().IsDisposed());
EXPECT_FALSE(vector.GetAt(1).as<DisposableClass>().IsDisposed());
for (auto obj : vector.GetView())
{
}

vector.RemoveAt(0);
EXPECT_EQ(vector.Size(), 2);
vector.Clear();
EXPECT_EQ(vector.Size(), 0);

CustomXamlServiceProvider serviceProvider;
EXPECT_EQ(serviceProvider.GetService(winrt::xaml_typename<CustomVector2>()).as<IStringable>().ToString(), L"CustomVector2");

bool eventTriggered = false;
CustomCommand command;
EXPECT_FALSE(command.CanExecute(nullptr));
auto token = command.CanExecuteChanged(auto_revoke, [&eventTriggered](IInspectable sender, IInspectable args)
{
eventTriggered = true;
});
command.SetCanExecute(true);
EXPECT_TRUE(eventTriggered);
EXPECT_TRUE(command.CanExecute(nullptr));
}

0 comments on commit fb0e7ad

Please sign in to comment.