protected override void VisitValueExpression( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute, ValueInfo info, MSBuildValueKind kind, ExpressionNode node) { //these are things like <Foo Include="@(Bar)" RemoveMetadata="SomeBarMetadata" /> if (kind.GetScalarType() == MSBuildValueKind.MetadataName) { var expr = GetIncludeExpression(element); if (expr != null && expr .WithAllDescendants() .OfType <ExpressionItemName> () .Any(n => IsItemNameMatch(n.ItemName)) ) { switch (node) { case ListExpression list: foreach (var c in list.Nodes) { if (c is ExpressionText l) { CheckMatch(l); break; } } break; case ExpressionText lit: CheckMatch(lit); break; } } void CheckMatch(ExpressionText t) { //FIXME: get rid of this trim if (t.IsPure && IsMatch(t.Value.Trim())) { Results.Add((t.Offset, t.Length, ReferenceUsage.Read)); } } return; } foreach (var n in node.WithAllDescendants()) { switch (n) { case ExpressionMetadata em: var iname = em.GetItemName(); if (iname != null && IsItemNameMatch(iname) && IsMatch(em.MetadataName)) { Results.Add((em.MetadataNameOffset, em.MetadataName.Length, ReferenceUsage.Read)); } break; } } }
protected override void VisitValueExpression( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute, ValueInfo info, MSBuildValueKind kind, ExpressionNode node) { if (kind.GetScalarType() != MSBuildValueKind.TargetName) { return; } switch (node) { case ExpressionList list: foreach (var c in list.Nodes) { if (c is ExpressionLiteral l) { CheckMatch(l); break; } } break; case ExpressionLiteral lit: CheckMatch(lit); break; } }
protected override void VisitValueExpression( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute, ValueInfo info, MSBuildValueKind kind, ExpressionNode node) { if (kind.GetScalarType() != MSBuildValueKind.TargetName) { return; } bool isDeclaration = !kind.AllowExpressions(); switch (node) { case ListExpression list: foreach (var c in list.Nodes) { if (c is ExpressionText l) { CheckMatch(l, isDeclaration); } } break; case ExpressionText lit: CheckMatch(lit, isDeclaration); break; } }
protected override void VisitResolvedAttribute( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute) { VisitAttributeValue(element, attribute, resolvedElement, resolvedAttribute); base.VisitResolvedAttribute(element, attribute, resolvedElement, resolvedAttribute); }
protected override void VisitValueExpression( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute, ValueInfo info, MSBuildValueKind kind, ExpressionNode node) { foreach (var n in node.WithAllDescendants()) { switch (n) { case ExpressionItemName ei: if (IsMatch(ei.Name)) { Results.Add((ei.Offset, ei.Name.Length, ReferenceUsage.Read)); } break; case ExpressionMetadata em: if (em.IsQualified && IsMatch(em.ItemName)) { Results.Add((em.ItemNameOffset, em.ItemName.Length, ReferenceUsage.Read)); } break; } } }
protected override void VisitValueExpression( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute, ValueInfo info, MSBuildValueKind kind, ExpressionNode node) { foreach (var n in node.WithAllDescendants()) { switch (n) { case ExpressionFunctionName func: if (func.Parent is ExpressionPropertyFunctionInvocation inv) { string baseName = StripGetPrefix(func.Name); if (IsMatch(baseName)) { //TODO: should we be fuzzy here and accept "unknown"? var resolvedKind = functionTypeProvider.ResolveType(inv); if (resolvedKind == MSBuildValueKind.Unknown) { resolvedKind = MSBuildValueKind.String; } if (resolvedKind == valueKind) { Results.Add((func.Offset, func.Length, ReferenceUsage.Read)); } } } break; } } }
protected virtual void VisitResolvedAttribute( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute) { if (attribute.Value != null) { VisitAttributeValue(element, attribute, resolvedElement, resolvedAttribute, attribute.Value, attribute.GetValueStartOffset(TextDocument)); } }
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 VisitResolvedAttribute( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute) { var start = ConvertLocation(attribute.Region.Begin); var end = ConvertLocation(attribute.Region.End); if (!IsIn(start, end - start)) { base.VisitResolvedAttribute(element, attribute, resolvedElement, resolvedAttribute); return; } rr.LanguageAttribute = resolvedAttribute = Document.GetSchemas().SpecializeAttribute(resolvedAttribute, element.Name.Name); bool inName = IsIn(start, attribute.Name.Name.Length); if (inName) { rr.ReferenceOffset = start; rr.ReferenceLength = attribute.Name.Name.Length; switch (resolvedAttribute.AbstractKind) { case MSBuildKind.Metadata: rr.ReferenceKind = MSBuildReferenceKind.Metadata; rr.Reference = (element.Name.Name, attribute.Name.Name); break; case MSBuildKind.Parameter: rr.ReferenceKind = MSBuildReferenceKind.TaskParameter; rr.Reference = (element.Name.Name, attribute.Name.Name); break; default: if (!resolvedAttribute.IsAbstract) { rr.ReferenceKind = MSBuildReferenceKind.Keyword; rr.Reference = resolvedAttribute; } break; } return; } base.VisitResolvedAttribute(element, attribute, resolvedElement, resolvedAttribute); }
protected override void VisitValueExpression( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute, ValueInfo info, MSBuildValueKind kind, ExpressionNode node) { foreach (var n in node.WithAllDescendants()) { switch (n) { case ExpressionFunctionName func: if (func.Parent is ExpressionItemFunctionInvocation inv && IsMatch(func.Name)) { Results.Add((func.Offset, func.Length, ReferenceUsage.Read)); } break; } } }
protected override void VisitValueExpression( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute, ValueInfo info, MSBuildValueKind kind, ExpressionNode node) { foreach (var n in node.WithAllDescendants()) { switch (n) { case ExpressionPropertyName ep: if (IsMatch(ep.Name)) { Results.Add((ep.Offset, ep.Length, ReferenceUsage.Read)); } break; } } }
protected override void VisitValueExpression( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute, ValueInfo info, MSBuildValueKind kind, ExpressionNode node) { foreach (var n in node.WithAllDescendants()) { switch (n) { case ExpressionClassReference classRef: if (IsMatch(classRef.Name) && classRef.Parent is ExpressionArgumentList) { Results.Add((classRef.Offset, classRef.Length, ReferenceUsage.Read)); } break; } } }
protected override void VisitResolvedAttribute( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute) { if (!attribute.Span.Contains(offset)) { return; } rr.LanguageAttribute = resolvedAttribute = Document.GetSchemas().SpecializeAttribute(resolvedAttribute, element.Name.Name); bool inName = attribute.NameSpan.Contains(offset); if (inName) { rr.ReferenceOffset = attribute.Span.Start; rr.ReferenceLength = attribute.Name.Name.Length; switch (resolvedAttribute.AbstractKind) { case MSBuildSyntaxKind.Metadata: rr.ReferenceKind = MSBuildReferenceKind.Metadata; rr.Reference = (element.Name.Name, attribute.Name.Name); break; case MSBuildSyntaxKind.Parameter: rr.ReferenceKind = MSBuildReferenceKind.TaskParameter; rr.Reference = (element.Name.Name, attribute.Name.Name); break; default: if (!resolvedAttribute.IsAbstract) { rr.ReferenceKind = MSBuildReferenceKind.Keyword; rr.Reference = resolvedAttribute; } break; } return; } base.VisitResolvedAttribute(element, attribute, resolvedElement, resolvedAttribute); }
protected override void VisitValueExpression( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute, ValueInfo info, MSBuildValueKind kind, ExpressionNode node) { foreach (var n in node.WithAllDescendants()) { switch (n) { case ExpressionMetadata em: var iname = em.GetItemName(); if (iname != null && IsItemNameMatch(iname) && IsMatch(em.MetadataName)) { Results.Add((em.MetadataNameOffset, em.MetadataName.Length, ReferenceUsage.Read)); } break; } } }
protected override void VisitValue( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute, ValueInfo info, string value, int offset) { if (info.DefaultValue != null && string.Equals(info.DefaultValue, value)) { AddWarning($"{info.GetTitleCaseKindName ()} has default value", offset, value.Length); } // we skip calling base, and instead parse the expression with more options enabled // so that we can warn if the user is doing something likely invalid var kind = MSBuildCompletionExtensions.InferValueKindIfUnknown(info); var options = kind.GetExpressionOptions() | ExpressionOptions.ItemsMetadataAndLists; var node = ExpressionParser.Parse(value, options, offset); VisitValueExpression(element, attribute, resolvedElement, resolvedAttribute, info, kind, node); }
void VisitAttributeValue( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute) { if (string.IsNullOrWhiteSpace(attribute.Value)) { return; } var info = Document.GetSchemas().GetAttributeInfo(resolvedAttribute, element.Name.Name, attribute.Name.Name); if (info == null) { return; } VisitValue( element, attribute, resolvedElement, resolvedAttribute, info, attribute.Value, attribute.ValueOffset); }
protected override void VisitResolvedAttribute( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute) { switch (resolvedElement.Kind) { case MSBuildKind.Import: if (attribute.NameEquals("Project", true)) { CaptureAnnotations(); } break; case MSBuildKind.Project: if (attribute.NameEquals("Sdk", true)) { CaptureAnnotations(); } break; } base.VisitResolvedAttribute(element, attribute, resolvedElement, resolvedAttribute); void CaptureAnnotations() { var annotations = Document.Annotations.GetMany <NavigationAnnotation> (attribute); if (annotations != null) { foreach (var group in annotations.GroupBy(a => a.Region.Begin)) { var first = group.First(); var beginOffset = ConvertLocation(first.Region.Begin); var endOffset = ConvertLocation(first.Region.End); Navigations.Add(new MSBuildNavigationResult( group.Select(a => a.Path).ToArray(), beginOffset, endOffset - beginOffset + 1 )); } } } }
protected virtual void VisitValue( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute, ValueInfo info, string value, int offset) { var kind = MSBuildCompletionExtensions.InferValueKindIfUnknown(info); if (!kind.AllowExpressions()) { VisitValueExpression( element, attribute, resolvedElement, resolvedAttribute, info, kind, new ExpressionText(offset, value, true)); return; } var expression = ExpressionParser.Parse(value, kind.GetExpressionOptions(), offset); VisitValueExpression( element, attribute, resolvedElement, resolvedAttribute, info, kind, expression); }
protected override void VisitResolvedAttribute( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute) { switch (resolvedElement.SyntaxKind) { case MSBuildSyntaxKind.Import: if (attribute.NameEquals("Project", true)) { CaptureAnnotations(); } break; case MSBuildSyntaxKind.Project: if (attribute.NameEquals("Sdk", true)) { CaptureAnnotations(); } break; } base.VisitResolvedAttribute(element, attribute, resolvedElement, resolvedAttribute); void CaptureAnnotations() { var annotations = Document.Annotations.GetMany <NavigationAnnotation> (attribute); if (annotations != null) { foreach (var group in annotations.GroupBy(a => a.Span.Start)) { var first = group.First(); Navigations.Add(new MSBuildNavigationResult( group.Select(a => a.Path).ToArray(), first.Span.Start, first.Span.Length )); } } } }
protected override void VisitValueExpression( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute, ValueInfo info, MSBuildValueKind kind, ExpressionNode node) { foreach (var n in node.WithAllDescendants()) { switch (n) { case ExpressionFunctionName func: if (func.Parent is ExpressionPropertyFunctionInvocation inv) { string baseName = MSBuildPropertyFunctionReferenceCollector.StripGetPrefix(func.Name); if (IsMatch(baseName) && inv.Target is ExpressionClassReference cn && cn.Name == className) { Results.Add((func.Offset, func.Length, ReferenceUsage.Read)); } } break; } } }
protected override void VisitValueExpression(XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute, ValueInfo info, MSBuildValueKind kind, ExpressionNode node) { switch (kind.GetScalarType()) { case MSBuildValueKind.TargetName: foreach (var n in node.WithAllDescendants()) { if (n is ExpressionText lit && lit.IsPure) { Navigations.Add(new MSBuildNavigationResult( MSBuildReferenceKind.Target, lit.Value, lit.Offset, lit.Length )); } } break; case MSBuildValueKind.File: case MSBuildValueKind.FileOrFolder: case MSBuildValueKind.ProjectFile: case MSBuildValueKind.TaskAssemblyFile: case MSBuildValueKind.Unknown: if (node is ExpressionList list) { foreach (var n in list.Nodes) { var p = GetPathFromNode(n, (MSBuildRootDocument)Document); if (p != null) { Navigations.Add(p); } } } var path = GetPathFromNode(node, (MSBuildRootDocument)Document); if (path != null) { Navigations.Add(path); } break; } }
protected virtual void VisitAttributeValue(XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute, string value, int offset) { }
protected override void VisitResolvedAttribute(XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute) { if (resolvedAttribute.AbstractKind == MSBuildSyntaxKind.Metadata && IsMatch(attribute.Name.Name) && IsItemNameMatch(element.Name.Name)) { Results.Add((attribute.Span.Start, attribute.Name.Name.Length, ReferenceUsage.Write)); } base.VisitResolvedAttribute(element, attribute, resolvedElement, resolvedAttribute); }
void ValidateAttribute(XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute) { if (string.IsNullOrWhiteSpace(attribute.Value)) { if (resolvedAttribute.Required) { AddError($"Required attribute has empty value", attribute.GetNameRegion()); } else { AddWarning($"Attribute has empty value", attribute.GetNameRegion()); } return; } }
protected override void VisitResolvedAttribute(XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute) { if (resolvedAttribute.AbstractKind == MSBuildKind.Metadata && IsMatch(attribute.Name.Name) && IsItemNameMatch(element.Name.Name)) { AddNameResult(attribute, ReferenceUsage.Write); } base.VisitResolvedAttribute(element, attribute, resolvedElement, resolvedAttribute); }
protected override void VisitResolvedAttribute(XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute) { if (resolvedAttribute.ValueKind == MSBuildValueKind.ItemName.Literal() && IsMatch(attribute.Value)) { AddValueResult(attribute, ReferenceUsage.Write); } base.VisitResolvedAttribute(element, attribute, resolvedElement, resolvedAttribute); }
protected override void VisitAttributeValue(XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute, string value, int offset) { var kind = resolvedAttribute.ValueKind; //FIXME ExtractConfigurations should directly handle extracting references if (kind == MSBuildValueKind.Condition) { ExtractConfigurations(value, offset); } if (resolvedElement.Kind == MSBuildKind.Item && element.NameEquals("ProjectConfiguration", true)) { if (attribute.NameEquals("Configuration", true)) { kind = MSBuildValueKind.Configuration; } else if (attribute.NameEquals("Platform", true)) { kind = MSBuildValueKind.Platform; } } ExtractReferences(kind, value, offset); }
protected override void VisitResolvedAttribute(XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute) { if (resolvedAttribute.IsAbstract) { switch (resolvedElement.Kind) { case MSBuildKind.Item: CollectMetadata(element.Name.Name, attribute.Name.Name); break; case MSBuildKind.Task: CollectTaskParameter(element.Name.Name, attribute.Name.Name, false); break; } } if (resolvedElement.Kind == MSBuildKind.Output && resolvedAttribute.Name == "TaskParameter") { CollectTaskParameter(element.ParentElement().Name.Name, attribute.Value, true); } base.VisitResolvedAttribute(element, attribute, resolvedElement, resolvedAttribute); }
protected virtual void VisitValueExpression( XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute, ValueInfo info, MSBuildValueKind kind, ExpressionNode node) { }
protected override void VisitResolvedAttribute(XElement element, XAttribute attribute, MSBuildLanguageElement resolvedElement, MSBuildLanguageAttribute resolvedAttribute) { if (resolvedAttribute.ValueKind == MSBuildValueKind.PropertyName.Literal() && IsMatch(attribute.Value)) { Results.Add((attribute.Span.Start, attribute.Name.Name.Length, ReferenceUsage.Write)); } base.VisitResolvedAttribute(element, attribute, resolvedElement, resolvedAttribute); }