protected override void VisitValueExpression( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute, ValueInfo info, MSBuildValueKind kind, ExpressionNode node) { bool allowExpressions = kind.AllowExpressions(); bool allowLists = kind.AllowListsOrCommaLists(); foreach (var n in node.WithAllDescendants()) { switch (n) { case ExpressionList list: if (!allowLists) { AddListWarning(list.Nodes [0].End, 1); } break; case ExpressionError err: var msg = err.Kind.GetMessage(info, out bool isWarning); AddError( isWarning? ErrorType.Warning : ErrorType.Error, msg, err.Offset, Math.Max(1, err.Length) ); break; case ExpressionMetadata meta: case ExpressionProperty prop: case ExpressionItem item: if (!allowExpressions) { AddExpressionWarning(node); } //TODO: can we validate property/metadata/items refs? //maybe warn if they're not used anywhere outside of this expression? break; case ExpressionText lit: VisitPureLiteral(info, kind, lit.GetUnescapedValue(), lit.Offset); break; } } string Name() => info.GetTitleCaseKindName(); void AddExpressionWarning(ExpressionNode n) => AddWarning($"{Name ()} does not expect expressions", n.Offset, n.Length); void AddListWarning(int start, int length) => AddWarning($"{Name ()} does not expect lists", start, length); }
protected override void VisitValueExpression( XElement element, XAttribute attribute, MSBuildElementSyntax resolvedElement, MSBuildAttributeSyntax resolvedAttribute, ValueInfo info, MSBuildValueKind kind, ExpressionNode node) { bool allowExpressions = kind.AllowExpressions(); bool allowLists = kind.AllowListsOrCommaLists(); if (node is ListExpression list) { if (!allowLists) { Document.Diagnostics.Add( CoreDiagnostics.UnexpectedList, new TextSpan(list.Nodes[0].End, list.End - list.Nodes[0].End), ImmutableDictionary <string, object> .Empty.Add("Name", info.Name), DescriptionFormatter.GetKindNoun(info), info.Name); } if (!allowExpressions) { var expr = list.Nodes.FirstOrDefault(n => !(n is ExpressionText)); if (expr != null) { AddExpressionWarning(expr); } } } else if (node is ExpressionText lit) { VisitPureLiteral(info, kind, lit.GetUnescapedValue(), lit.Offset); } else { if (!allowExpressions) { AddExpressionWarning(node); } } foreach (var n in node.WithAllDescendants()) { switch (n) { case ExpressionError err: var(desc, args) = CoreDiagnostics.GetExpressionError(err, info); Document.Diagnostics.Add(desc, new TextSpan(err.Offset, Math.Max(1, err.Length)), args); break; case ExpressionMetadata meta: case ExpressionProperty prop: case ExpressionItem item: //TODO: can we validate property/metadata/items refs? //maybe warn if they're not used anywhere outside of this expression? //TODO: deprecation squiggles in expressions break; } } void AddExpressionWarning(ExpressionNode n) => Document.Diagnostics.Add(CoreDiagnostics.UnexpectedExpression, new TextSpan(n.Offset, n.Length), DescriptionFormatter.GetKindNoun(info), info.Name); }
protected override void VisitValueExpression( XElement element, XAttribute attribute, MSBuildElementSyntax resolvedElement, MSBuildAttributeSyntax resolvedAttribute, ValueInfo info, MSBuildValueKind kind, ExpressionNode node) { bool allowExpressions = kind.AllowExpressions(); bool allowLists = kind.AllowListsOrCommaLists(); if (node is ListExpression list) { if (!allowLists) { Document.Diagnostics.Add( CoreDiagnostics.UnexpectedList, new TextSpan(list.Nodes[0].End, list.End - list.Nodes[0].End), ImmutableDictionary <string, object> .Empty.Add("Name", info.Name), DescriptionFormatter.GetKindNoun(info), info.Name); } if (!allowExpressions) { var expr = list.Nodes.FirstOrDefault(n => !(n is ExpressionText)); if (expr != null) { AddExpressionWarning(expr); } } } else if (node is ExpressionText lit) { VisitPureLiteral(info, kind, lit.GetUnescapedValue(), lit.Offset); } else { if (!allowExpressions) { AddExpressionWarning(node); } } foreach (var n in node.WithAllDescendants()) { switch (n) { case ExpressionError err: var(desc, args) = CoreDiagnostics.GetExpressionError(err, info); Document.Diagnostics.Add(desc, new TextSpan(err.Offset, Math.Max(1, err.Length)), args); break; case ExpressionMetadata meta: var metaItem = meta.GetItemName(); if (!string.IsNullOrEmpty(metaItem) && !IsMetadataUsed(metaItem, meta.MetadataName, ReferenceUsage.Write)) { Document.Diagnostics.Add( CoreDiagnostics.UnwrittenMetadata, meta.Span, ImmutableDictionary <string, object> .Empty .Add("ItemName", metaItem) .Add("Name", meta.MetadataName) .Add("Spans", new [] { new TextSpan(meta.MetadataNameOffset, meta.MetadataName.Length) }), metaItem, meta.MetadataName ); } break; case ExpressionPropertyName prop: if (!IsPropertyUsed(prop.Name, ReferenceUsage.Write)) { Document.Diagnostics.Add( CoreDiagnostics.UnwrittenProperty, prop.Span, ImmutableDictionary <string, object> .Empty .Add("Name", prop.Name) .Add("Spans", new[] { new TextSpan(prop.Offset, prop.Length) }), prop.Name ); } break; case ExpressionItemName item: if (!IsItemUsed(item.Name, ReferenceUsage.Write)) { Document.Diagnostics.Add( CoreDiagnostics.UnwrittenItem, item.Span, ImmutableDictionary <string, object> .Empty .Add("Name", item.Name) .Add("Spans", new[] { new TextSpan(item.Offset, item.Length) }), item.Name ); } //TODO: deprecation squiggles in expressions break; } } void AddExpressionWarning(ExpressionNode n) => Document.Diagnostics.Add(CoreDiagnostics.UnexpectedExpression, new TextSpan(n.Offset, n.Length), DescriptionFormatter.GetKindNoun(info), info.Name); }