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 override void VisitValueExpression( XElement element, XAttribute attribute, MSBuildElementSyntax resolvedElement, MSBuildAttributeSyntax resolvedAttribute, ITypedSymbol valueDescriptor, MSBuildValueKind inferredKind, ExpressionNode node) { var nodeAtOffset = node.Find(offset); switch (nodeAtOffset) { case ExpressionItemName ei: rr.ReferenceKind = MSBuildReferenceKind.Item; rr.ReferenceOffset = ei.Offset; rr.ReferenceLength = ei.Name.Length; rr.Reference = ei.Name; break; case ExpressionPropertyName propName: rr.ReferenceKind = MSBuildReferenceKind.Property; rr.ReferenceOffset = propName.Offset; rr.Reference = propName.Name; rr.ReferenceLength = propName.Length; break; case ExpressionMetadata em: if (em.ItemName == null || offset >= em.MetadataNameOffset) { rr.ReferenceKind = MSBuildReferenceKind.Metadata; rr.ReferenceOffset = em.MetadataNameOffset; rr.Reference = (em.GetItemName(), em.MetadataName); rr.ReferenceLength = em.MetadataName.Length; } else { rr.ReferenceKind = MSBuildReferenceKind.Item; rr.ReferenceOffset = em.ItemNameOffset; rr.Reference = em.ItemName; rr.ReferenceLength = em.ItemName.Length; } break; case ExpressionFunctionName name: rr.ReferenceOffset = name.Offset; rr.ReferenceLength = name.Name.Length; switch (name.Parent) { case ExpressionItemNode _: rr.ReferenceKind = MSBuildReferenceKind.ItemFunction; rr.Reference = name.Name; break; case ExpressionPropertyFunctionInvocation prop: { if (prop.Target is ExpressionClassReference classRef) { rr.ReferenceKind = MSBuildReferenceKind.StaticPropertyFunction; rr.Reference = (classRef.Name, name.Name); } else if (prop.Target is ExpressionPropertyNode propNode) { var type = functionTypeProvider?.ResolveType(propNode) ?? MSBuildValueKind.Unknown; rr.ReferenceKind = MSBuildReferenceKind.PropertyFunction; rr.Reference = (type, name.Name); } break; } case ExpressionConditionFunction _: rr.ReferenceKind = MSBuildReferenceKind.ConditionFunction; rr.Reference = name.Name; break; } break; case ExpressionClassReference cr: if (!string.IsNullOrEmpty(cr.Name)) { if (cr.Parent is ExpressionArgumentList) { rr.ReferenceKind = MSBuildReferenceKind.Enum; } else if (cr.Parent is ExpressionPropertyFunctionInvocation) { rr.ReferenceKind = MSBuildReferenceKind.ClassName; } else { break; } rr.ReferenceOffset = cr.Offset; rr.Reference = cr.Name; rr.ReferenceLength = cr.Length; } break; case ExpressionText lit: inferredKind = inferredKind.GetScalarType(); if (lit.IsPure) { VisitPureLiteral(element, valueDescriptor, inferredKind, lit); if (inferredKind == MSBuildValueKind.TaskOutputParameterName) { rr.ReferenceKind = MSBuildReferenceKind.TaskParameter; rr.ReferenceOffset = lit.Offset; rr.ReferenceLength = lit.Value.Length; rr.Reference = (element.ParentElement.Name.Name, lit.Value); break; } } switch (inferredKind) { case MSBuildValueKind.File: case MSBuildValueKind.FileOrFolder: case MSBuildValueKind.ProjectFile: case MSBuildValueKind.TaskAssemblyFile: var pathNode = lit.Parent as ConcatExpression ?? (ExpressionNode)lit; var path = MSBuildNavigation.GetPathFromNode(pathNode, (MSBuildRootDocument)Document); if (path != null) { rr.ReferenceKind = MSBuildReferenceKind.FileOrFolder; rr.ReferenceOffset = path.Offset; rr.ReferenceLength = path.Length; rr.Reference = path.Paths; } break; } break; } }