Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
[X] throw if x:Key isn't a string literal
Browse files Browse the repository at this point in the history
as reported in #12425
  • Loading branch information
StephaneDelcroix committed Oct 9, 2020
1 parent 7d73de8 commit c9d9aab
Show file tree
Hide file tree
Showing 20 changed files with 155 additions and 136 deletions.
1 change: 1 addition & 0 deletions Xamarin.Forms.Build.Tasks/BuildException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class BuildExceptionCode
public static BuildExceptionCode ResourceMissing = new BuildExceptionCode("XFC0124", nameof(ResourceMissing), "");
public static BuildExceptionCode ResourceDictDuplicateKey = new BuildExceptionCode("XFC0125", nameof(ResourceDictDuplicateKey), "");
public static BuildExceptionCode ResourceDictMissingKey = new BuildExceptionCode("XFC0126", nameof(ResourceDictMissingKey), "");
public static BuildExceptionCode XKeyNotLiteral = new BuildExceptionCode("XFC0127", nameof(XKeyNotLiteral), "");

public string Code { get; private set; }
public string ErrorMessageKey { get; private set; }
Expand Down
150 changes: 19 additions & 131 deletions Xamarin.Forms.Build.Tasks/ErrorMessages.Designer.cs

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions Xamarin.Forms.Build.Tasks/ErrorMessages.resx
Original file line number Diff line number Diff line change
Expand Up @@ -244,5 +244,9 @@
</data>
<data name="XStaticSyntax" xml:space="preserve">
<value>Syntax for x:Static is "[Member=][prefix:]typeName.staticMemberName".</value>
</data>
<data name="XKeyNotLiteral" xml:space="preserve">
<value>x:Key expects a string literal.</value>
</data>

</root>
6 changes: 4 additions & 2 deletions Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1429,7 +1429,8 @@ static bool CanAddToResourceDictionary(VariableDefinition parent, TypeReference

if (node.Properties.ContainsKey(XmlName.xKey))
{
var key = (node.Properties[XmlName.xKey] as ValueNode).Value as string;
var valueNode = node.Properties[XmlName.xKey] as ValueNode ?? throw new BuildException(XKeyNotLiteral, lineInfo, null);
var key = (valueNode).Value as string;
if (!resourceNamesInUse.TryGetValue(parent, out var names))
resourceNamesInUse[parent] = (names = new List<string>());
if (names.Contains(key))
Expand Down Expand Up @@ -1482,7 +1483,8 @@ static IEnumerable<Instruction> AddToResourceDictionary(VariableDefinition paren
if (node.Properties.ContainsKey(XmlName.xKey))
{
var names = resourceNamesInUse[parent];
var key = (node.Properties[XmlName.xKey] as ValueNode).Value as string;
var valueNode = node.Properties[XmlName.xKey] as ValueNode ?? throw new BuildException(XKeyNotLiteral, lineInfo, null);
var key = (valueNode).Value as string;
names.Add(key);

// IL_0014: ldstr "key"
Expand Down
5 changes: 5 additions & 0 deletions Xamarin.Forms.Build.Tasks/xlf/ErrorMessages.cs.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">x:DataType očekává řetězcový literál, značku {{x:Type}} nebo {{x:Nul}l}.</target>
<note />
</trans-unit>
<trans-unit id="XKeyNotLiteral">
<source>x:Key expects a string literal.</source>
<target state="new">x:Key expects a string literal.</target>
<note />
</trans-unit>
<trans-unit id="XStaticResolution">
<source>x:Static: unable to find a public -- or accessible internal -- static field, static property, const or enum value named "{0}" in "{1}".</source>
<target state="translated">x:Static: nejde najít veřejné nebo přístupné interní statické pole, statickou vlastnost, konstantu nebo hodnotu výčtu s názvem {0} v typu {1}.</target>
Expand Down
5 changes: 5 additions & 0 deletions Xamarin.Forms.Build.Tasks/xlf/ErrorMessages.de.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">x:DataType erwartet ein Zeichenfolgenliteral, ein {{x:Type}}-Markup oder {{x:Nul}l}.</target>
<note />
</trans-unit>
<trans-unit id="XKeyNotLiteral">
<source>x:Key expects a string literal.</source>
<target state="new">x:Key expects a string literal.</target>
<note />
</trans-unit>
<trans-unit id="XStaticResolution">
<source>x:Static: unable to find a public -- or accessible internal -- static field, static property, const or enum value named "{0}" in "{1}".</source>
<target state="translated">x:Static: Ein öffentliches – oder zugängliches internes – statisches Feld, eine statische Eigenschaft oder ein const- oder enum-Wert mit dem Namen "{0}" wurde in "{1}" nicht gefunden.</target>
Expand Down
5 changes: 5 additions & 0 deletions Xamarin.Forms.Build.Tasks/xlf/ErrorMessages.es.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">x:DataType espera un literal de cadena, una marca {{x:Type}} o {{x:Nul}l}.</target>
<note />
</trans-unit>
<trans-unit id="XKeyNotLiteral">
<source>x:Key expects a string literal.</source>
<target state="new">x:Key expects a string literal.</target>
<note />
</trans-unit>
<trans-unit id="XStaticResolution">
<source>x:Static: unable to find a public -- or accessible internal -- static field, static property, const or enum value named "{0}" in "{1}".</source>
<target state="translated">x:Static: no puede encontrar un campo estático público (o interno accesible), una propiedad estática o un valor constante o de enumeración llamados "{0}" en "{1}".</target>
Expand Down
5 changes: 5 additions & 0 deletions Xamarin.Forms.Build.Tasks/xlf/ErrorMessages.fr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">x:DataType attend un littéral de chaîne, une balise {{x:Type}} ou {{x:Nul}l}.</target>
<note />
</trans-unit>
<trans-unit id="XKeyNotLiteral">
<source>x:Key expects a string literal.</source>
<target state="new">x:Key expects a string literal.</target>
<note />
</trans-unit>
<trans-unit id="XStaticResolution">
<source>x:Static: unable to find a public -- or accessible internal -- static field, static property, const or enum value named "{0}" in "{1}".</source>
<target state="translated">x:Static : impossible de localiser un champ statique public (ou interne et accessible), une propriété statique, une valeur const ou une valeur enum portant le nom "{0}" dans "{1}".</target>
Expand Down
5 changes: 5 additions & 0 deletions Xamarin.Forms.Build.Tasks/xlf/ErrorMessages.it.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">Con x:DataType è previsto un valore letterale stringa, un markup {{x:Type}} oppure {{x:Nul}l}.</target>
<note />
</trans-unit>
<trans-unit id="XKeyNotLiteral">
<source>x:Key expects a string literal.</source>
<target state="new">x:Key expects a string literal.</target>
<note />
</trans-unit>
<trans-unit id="XStaticResolution">
<source>x:Static: unable to find a public -- or accessible internal -- static field, static property, const or enum value named "{0}" in "{1}".</source>
<target state="translated">x:Static: non è possibile trovare un valore di campo statico pubblico o interno accessibile, di proprietà statica, di costante o di enumerazione denominato "{0}" in "{1}".</target>
Expand Down
5 changes: 5 additions & 0 deletions Xamarin.Forms.Build.Tasks/xlf/ErrorMessages.ja.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">x:DataType には、文字列リテラル、{{x:Type}} マークアップ、または {{x:Nul}l} を指定する必要があります。</target>
<note />
</trans-unit>
<trans-unit id="XKeyNotLiteral">
<source>x:Key expects a string literal.</source>
<target state="new">x:Key expects a string literal.</target>
<note />
</trans-unit>
<trans-unit id="XStaticResolution">
<source>x:Static: unable to find a public -- or accessible internal -- static field, static property, const or enum value named "{0}" in "{1}".</source>
<target state="translated">x:Static: "{1}" に、"{0}" という名前のパブリックな (またはアクセス可能な内部の) 静的フィールド、静的プロパティ、const、または列挙値が見つかりません。</target>
Expand Down
5 changes: 5 additions & 0 deletions Xamarin.Forms.Build.Tasks/xlf/ErrorMessages.ko.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">x:DataType에는 {{x:Type}} 태그 또는 {{x:Nul}l} 문자열 리터럴이 필요합니다.</target>
<note />
</trans-unit>
<trans-unit id="XKeyNotLiteral">
<source>x:Key expects a string literal.</source>
<target state="new">x:Key expects a string literal.</target>
<note />
</trans-unit>
<trans-unit id="XStaticResolution">
<source>x:Static: unable to find a public -- or accessible internal -- static field, static property, const or enum value named "{0}" in "{1}".</source>
<target state="translated">x:Static: "{1}"에서 이름이 "{0}"인 public 또는 액세스 가능한 내부 정적 필드, 정적 속성, 상수 또는 열거형 값을 찾을 수 없습니다.</target>
Expand Down
5 changes: 5 additions & 0 deletions Xamarin.Forms.Build.Tasks/xlf/ErrorMessages.pl.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">Argument x:DataType oczekuje literału ciągu, znacznika {{x:Type}} lub {{x:Nul}l}.</target>
<note />
</trans-unit>
<trans-unit id="XKeyNotLiteral">
<source>x:Key expects a string literal.</source>
<target state="new">x:Key expects a string literal.</target>
<note />
</trans-unit>
<trans-unit id="XStaticResolution">
<source>x:Static: unable to find a public -- or accessible internal -- static field, static property, const or enum value named "{0}" in "{1}".</source>
<target state="translated">x:Static: nie można odnaleźć publicznego — lub dostępnego wewnętrznie — pola statycznego, właściwości statycznej, stałej lub wartości wyliczenia o nazwie „{0}” w typie „{1}”.</target>
Expand Down
5 changes: 5 additions & 0 deletions Xamarin.Forms.Build.Tasks/xlf/ErrorMessages.pt-BR.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">O x:DataType espera um literal de cadeia de caracteres, uma marcação {{x:Type}} ou um {{x:Nul}l}.</target>
<note />
</trans-unit>
<trans-unit id="XKeyNotLiteral">
<source>x:Key expects a string literal.</source>
<target state="new">x:Key expects a string literal.</target>
<note />
</trans-unit>
<trans-unit id="XStaticResolution">
<source>x:Static: unable to find a public -- or accessible internal -- static field, static property, const or enum value named "{0}" in "{1}".</source>
<target state="translated">O x:Static: não pôde encontrar um campo estático, uma propriedade estática, um valor const ou enumerado público (ou interno acessível) denominado "{0}" em "{1}".</target>
Expand Down
5 changes: 5 additions & 0 deletions Xamarin.Forms.Build.Tasks/xlf/ErrorMessages.ru.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">x:DataType ожидает строковый литерал, разметку {{x:Type}} или {{x:Nul}l}.</target>
<note />
</trans-unit>
<trans-unit id="XKeyNotLiteral">
<source>x:Key expects a string literal.</source>
<target state="new">x:Key expects a string literal.</target>
<note />
</trans-unit>
<trans-unit id="XStaticResolution">
<source>x:Static: unable to find a public -- or accessible internal -- static field, static property, const or enum value named "{0}" in "{1}".</source>
<target state="translated">x:Static: не удается найти статическое поле, статическое свойство, константу или значение перечисления с именем "{0}" в "{1}", которые являлись бы открытыми или были бы доступны внутренне.</target>
Expand Down
5 changes: 5 additions & 0 deletions Xamarin.Forms.Build.Tasks/xlf/ErrorMessages.tr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">x:DataType için bir dize sabit değeri, {{x:Type}} işaretlemesi veya {{x:Nul}l} bekleniyor.</target>
<note />
</trans-unit>
<trans-unit id="XKeyNotLiteral">
<source>x:Key expects a string literal.</source>
<target state="new">x:Key expects a string literal.</target>
<note />
</trans-unit>
<trans-unit id="XStaticResolution">
<source>x:Static: unable to find a public -- or accessible internal -- static field, static property, const or enum value named "{0}" in "{1}".</source>
<target state="translated">x:Static: "{1}" içinde "{0}" adlı genel -- veya erişilebilir, dahili -- statik alan, statik özellik, sabit veya sabit listesi değeri bulunamıyor.</target>
Expand Down
5 changes: 5 additions & 0 deletions Xamarin.Forms.Build.Tasks/xlf/ErrorMessages.zh-Hans.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">x:DataType 需要字符串文本、{{x:Type}} 标记或 {{x:Nul}l}。</target>
<note />
</trans-unit>
<trans-unit id="XKeyNotLiteral">
<source>x:Key expects a string literal.</source>
<target state="new">x:Key expects a string literal.</target>
<note />
</trans-unit>
<trans-unit id="XStaticResolution">
<source>x:Static: unable to find a public -- or accessible internal -- static field, static property, const or enum value named "{0}" in "{1}".</source>
<target state="translated">x:Static: 在“{1}”中找不到公共(或可访问的内部)静态字段、静态属性、常量或枚举值“{0}”。</target>
Expand Down
5 changes: 5 additions & 0 deletions Xamarin.Forms.Build.Tasks/xlf/ErrorMessages.zh-Hant.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<target state="translated">x:DataType 需要字串常值、{{x:Type}} 標記或 {{x:Nul}l}。</target>
<note />
</trans-unit>
<trans-unit id="XKeyNotLiteral">
<source>x:Key expects a string literal.</source>
<target state="new">x:Key expects a string literal.</target>
<note />
</trans-unit>
<trans-unit id="XStaticResolution">
<source>x:Static: unable to find a public -- or accessible internal -- static field, static property, const or enum value named "{0}" in "{1}".</source>
<target state="translated">x:Static: 在 "{1}" 中找不到名為 "{0}" 的公用 (或可存取內部) 靜態欄位、靜態屬性、常數或列舉值。</target>
Expand Down
8 changes: 8 additions & 0 deletions Xamarin.Forms.Xaml.UnitTests/xKeyLiteral.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Xamarin.Forms.Xaml.UnitTests.xKeyLiteral">
<ContentPage.Resources>
<ResourceDictionary>
<Color x:Key="{x:Type Grid}">#96d1ff</Color>
</ResourceDictionary>
</ContentPage.Resources>
</ContentPage>
38 changes: 38 additions & 0 deletions Xamarin.Forms.Xaml.UnitTests/xKeyLiteral.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using NUnit.Framework;
using Xamarin.Forms;
using Xamarin.Forms.Build.Tasks;
using Xamarin.Forms.Core.UnitTests;

namespace Xamarin.Forms.Xaml.UnitTests
{
[XamlCompilation(XamlCompilationOptions.Skip)]
public partial class xKeyLiteral : ContentPage
{
public xKeyLiteral() => InitializeComponent();
public xKeyLiteral(bool useCompiledXaml)
{
//this stub will be replaced at compile time
}

[TestFixture]
class Tests
{
[SetUp] public void Setup() => Device.PlatformServices = new MockPlatformServices();
[TearDown] public void TearDown() => Device.PlatformServices = null;

[Test]
//this requirement might change, see https://github.com/xamarin/Xamarin.Forms/issues/12425
public void xKeyRequireStringLiteral([Values(false, true)] bool useCompiledXaml)
{
if (useCompiledXaml)
Assert.Throws<BuildException>(() => MockCompiler.Compile(typeof(xKeyLiteral)));
else
Assert.Throws<XamlParseException>(() => new xKeyLiteral());
}
}
}
}
19 changes: 16 additions & 3 deletions Xamarin.Forms.Xaml/ApplyPropertiesVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,14 @@ public void Visit(ElementNode node, INode parentNode)
ProvideValue(ref value, node, source, XmlName.Empty);
string contentProperty;
Exception xpe = null;
var xKey = node.Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)node.Properties[XmlName.xKey]).Value as string : null;

string xKey = null;
if (xpe == null && node.Properties.ContainsKey(XmlName.xKey))
{
if ((node.Properties[XmlName.xKey] is ValueNode valueNode))
xKey = valueNode.Value as string;
xpe = new XamlParseException("x:Key expects a string literal.", node as IXmlLineInfo);
}

//ResourceDictionary
if (xpe == null && TryAddToResourceDictionary(source as ResourceDictionary, value, xKey, node, out xpe))
Expand Down Expand Up @@ -168,10 +175,16 @@ public void Visit(ElementNode node, INode parentNode)
if (Skips.Contains(parentList.XmlName))
return;
Exception xpe = null;
var xKey = node.Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)node.Properties[XmlName.xKey]).Value as string : null;
string xKey = null;
if (xpe == null && node.Properties.ContainsKey(XmlName.xKey))
{
if ((node.Properties[XmlName.xKey] is ValueNode valueNode))
xKey = valueNode.Value as string;
xpe = new XamlParseException("x:Key expects a string literal.", node as IXmlLineInfo);
}

var collection = GetPropertyValue(source, parentList.XmlName, Context.RootElement, parentList, out _, out _) as IEnumerable;
if (collection == null)
if (xpe == null && collection == null)
xpe = new XamlParseException($"Property {parentList.XmlName.LocalName} is null or is not IEnumerable", node);

if (xpe == null && TryAddToResourceDictionary(collection as ResourceDictionary, value, xKey, node, out xpe))
Expand Down

0 comments on commit c9d9aab

Please sign in to comment.