protected override void VisitValue( XElement element, XAttribute attribute, MSBuildElementSyntax resolvedElement, MSBuildAttributeSyntax resolvedAttribute, ValueInfo info, string value, int offset) { if (!IsTargetsFile && !IsPropsFile) { if (info.DefaultValue != null && string.Equals(info.DefaultValue, value)) { Document.Diagnostics.Add(CoreDiagnostics.HasDefaultValue, new TextSpan(offset, value.Length), DescriptionFormatter.GetKindNoun(info), info.Name, info.DefaultValue); } } //NOTE: doing this here means we can't check for deprecated constructs that don't have values, but there aren't any yet CheckDeprecated(info, (INamedXObject)attribute ?? element); // 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); }
public static IEnumerable <BaseInfo> GetCompletionInfos( MSBuildResolveResult rr, TriggerState trigger, MSBuildValueKind kind, ExpressionNode triggerExpression, int triggerLength, MSBuildRootDocument doc) { switch (trigger) { case TriggerState.Value: return(MSBuildCompletionExtensions.GetValueCompletions(kind, doc, rr)); case TriggerState.Item: return(doc.GetItems()); case TriggerState.Metadata: return(doc.GetMetadata(null, true)); case TriggerState.Property: return(doc.GetProperties(true)); case TriggerState.MetadataOrItem: return(((IEnumerable <BaseInfo>)doc.GetItems()).Concat(doc.GetMetadata(null, true))); case TriggerState.DirectorySeparator: return(MSBuildCompletionExtensions.GetFilenameCompletions(kind, doc, triggerExpression, triggerLength));; case TriggerState.MethodName: return(FunctionCompletion.GetMethodNameCompletions(triggerExpression)); } throw new InvalidOperationException(); }
protected override void VisitValue( XElement element, XAttribute attribute, MSBuildElementSyntax resolvedElement, MSBuildAttributeSyntax resolvedAttribute, ITypedSymbol valueDescriptor, string value, int offset) { if (!IsTargetsFile && !IsPropsFile && valueDescriptor is IHasDefaultValue hasDefault) { if (hasDefault.DefaultValue != null && string.Equals(hasDefault.DefaultValue, value, StringComparison.OrdinalIgnoreCase)) { Document.Diagnostics.Add( CoreDiagnostics.HasDefaultValue, attribute?.Span ?? element.OuterSpan, ImmutableDictionary <string, object> .Empty.Add("Info", valueDescriptor), DescriptionFormatter.GetKindNoun(valueDescriptor), valueDescriptor.Name, hasDefault.DefaultValue); } } if (valueDescriptor is IDeprecatable deprecatable) { CheckDeprecated(deprecatable, (INamedXObject)attribute ?? element); } // 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(valueDescriptor); var options = kind.GetExpressionOptions() | ExpressionOptions.ItemsMetadataAndLists; var node = ExpressionParser.Parse(value, options, offset); VisitValueExpression(element, attribute, resolvedElement, resolvedAttribute, valueDescriptor, kind, node); }
public static IEnumerable <ISymbol> GetComparandCompletions(MSBuildRootDocument doc, IReadOnlyList <ExpressionNode> variables) { var names = new HashSet <string> (); foreach (var variable in variables) { VariableInfo info; switch (variable) { case ExpressionProperty ep: if (ep.IsSimpleProperty) { info = doc.GetProperty(ep.Name, true) ?? new PropertyInfo(ep.Name, null, false); break; } continue; case ExpressionMetadata em: info = doc.GetMetadata(em.ItemName, em.MetadataName, true) ?? new MetadataInfo(em.MetadataName, null, false); break; default: continue; } if (info == null) { continue; } IEnumerable <ISymbol> cinfos; if (info.CustomType != null && info.CustomType.Values.Count > 0) { cinfos = info.CustomType.Values; } else { var kind = info.InferValueKindIfUnknown(); cinfos = MSBuildCompletionExtensions.GetValueCompletions(kind, doc); } if (cinfos != null) { foreach (var ci in cinfos) { if (names.Add(ci.Name)) { yield return(ci); } } } } }
public static MSBuildNavigationResult GetPathFromNode(ExpressionNode node, MSBuildRootDocument document) { try { var path = MSBuildCompletionExtensions.EvaluateExpressionAsPaths(node, document).FirstOrDefault(); if (path != null && File.Exists(path)) { return(new MSBuildNavigationResult( new [] { path }, node.Offset, node.Length )); } } catch (Exception ex) { Core.LoggingService.LogError($"Error checking path for file '{node}'", ex); } return(null); }
public static IEnumerable <ISymbol> GetCompletionInfos( MSBuildResolveResult rr, TriggerState trigger, MSBuildValueKind kind, ExpressionNode triggerExpression, int triggerLength, MSBuildRootDocument doc, IFunctionTypeProvider functionTypeProvider) { switch (trigger) { case TriggerState.Value: return(MSBuildCompletionExtensions.GetValueCompletions(kind, doc, rr, triggerExpression)); case TriggerState.ItemName: return(doc.GetItems()); case TriggerState.MetadataName: return(doc.GetMetadata(null, true)); case TriggerState.PropertyName: return(doc.GetProperties(true)); case TriggerState.MetadataOrItemName: return(((IEnumerable <ISymbol>)doc.GetItems()).Concat(doc.GetMetadata(null, true))); case TriggerState.DirectorySeparator: return(MSBuildCompletionExtensions.GetFilenameCompletions(kind, doc, triggerExpression, triggerLength, rr)); case TriggerState.PropertyFunctionName: return(functionTypeProvider.GetPropertyFunctionNameCompletions(triggerExpression)); case TriggerState.ItemFunctionName: return(functionTypeProvider.GetItemFunctionNameCompletions()); case TriggerState.PropertyFunctionClassName: return(functionTypeProvider.GetClassNameCompletions()); case TriggerState.None: break; case TriggerState.BareFunctionArgumentValue: //FIXME: enum completion etc return(MSBuildValueKind.Bool.GetSimpleValues(true)); case TriggerState.ConditionFunctionName: return(Builtins.ConditionFunctions.Values); } throw new InvalidOperationException($"Unhandled trigger type {trigger}"); }
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); }
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 virtual void VisitValue( XElement element, XAttribute attribute, MSBuildElementSyntax resolvedElement, MSBuildAttributeSyntax resolvedAttribute, ITypedSymbol valueDescriptor, string value, int offset) { var kind = MSBuildCompletionExtensions.InferValueKindIfUnknown(valueDescriptor); if (!kind.AllowExpressions()) { VisitValueExpression( element, attribute, resolvedElement, resolvedAttribute, valueDescriptor, kind, new ExpressionText(offset, value, true)); return; } var expression = valueDescriptor?.ValueKind == MSBuildValueKind.Condition ? ExpressionParser.ParseCondition(value, offset) : ExpressionParser.Parse(value, kind.GetExpressionOptions(), offset); VisitValueExpression( element, attribute, resolvedElement, resolvedAttribute, valueDescriptor, kind, expression); }
Task <ICompletionDataList> HandleExpressionCompletion(MSBuildResolveResult rr, CancellationToken token) { var doc = GetDocument(); if (!ExpressionCompletion.IsPossibleExpressionCompletionContext(Tracker.Engine)) { return(null); } string expression = GetAttributeOrElementTextToCaret(); var triggerState = ExpressionCompletion.GetTriggerState( expression, rr.IsCondition(), out int triggerLength, out ExpressionNode triggerExpression, out IReadOnlyList <ExpressionNode> comparandVariables ); if (triggerState == ExpressionCompletion.TriggerState.None) { return(null); } var info = rr.GetElementOrAttributeValueInfo(doc); if (info == null) { return(null); } var kind = MSBuildCompletionExtensions.InferValueKindIfUnknown(info); if (!ExpressionCompletion.ValidateListPermitted(ref triggerState, kind)) { return(null); } bool allowExpressions = kind.AllowExpressions(); kind = kind.GetScalarType(); if (kind == MSBuildValueKind.Data || kind == MSBuildValueKind.Nothing) { return(null); } var list = new CompletionDataList { TriggerWordLength = triggerLength, AutoSelect = false }; if (comparandVariables != null && triggerState == ExpressionCompletion.TriggerState.Value) { foreach (var ci in ExpressionCompletion.GetComparandCompletions(doc, comparandVariables)) { list.Add(new MSBuildCompletionData(ci, doc, rr, XmlCompletionData.DataType.XmlAttributeValue)); } } if (triggerState == ExpressionCompletion.TriggerState.Value) { switch (kind) { case MSBuildValueKind.NuGetID: return(GetPackageNameCompletions(doc, Editor.CaretOffset - triggerLength, triggerLength)); case MSBuildValueKind.NuGetVersion: return(GetPackageVersionCompletions(doc, rr, Editor.CaretOffset - triggerLength, triggerLength)); case MSBuildValueKind.Sdk: case MSBuildValueKind.SdkWithVersion: return(GetSdkCompletions(triggerLength, token)); case MSBuildValueKind.Guid: list.Add(new GenerateGuidCompletionData()); break; case MSBuildValueKind.Lcid: foreach (var culture in System.Globalization.CultureInfo.GetCultures(System.Globalization.CultureTypes.AllCultures)) { string name = culture.Name; string id = culture.LCID.ToString(); string display = culture.DisplayName; //insert multiple versions for matching on both the name and the number list.Add(new CompletionData(id, null, display)); list.Add(new CompletionData(display, null, id, id)); } break; } } //TODO: better metadata support IEnumerable <BaseInfo> cinfos; if (info.Values != null && info.Values.Count > 0 && triggerState == ExpressionCompletion.TriggerState.Value) { cinfos = info.Values; } else { cinfos = ExpressionCompletion.GetCompletionInfos(rr, triggerState, kind, triggerExpression, triggerLength, doc); } if (cinfos != null) { foreach (var ci in cinfos) { list.Add(new MSBuildCompletionData(ci, doc, rr, XmlCompletionData.DataType.XmlAttributeValue)); } } if (allowExpressions && triggerState == ExpressionCompletion.TriggerState.Value) { list.Add(new CompletionDataWithSkipCharAndRetrigger("$(", "md-variable", "Property value reference", "$(|)", ')')); list.Add(new CompletionDataWithSkipCharAndRetrigger("@(", "md-variable", "Item list reference", "@(|)", ')')); } if (list.Count > 0) { return(Task.FromResult <ICompletionDataList> (list)); } return(null); }
async Task <CompletionContext> GetExpressionCompletionsAsync(ValueInfo info, ExpressionCompletion.TriggerState triggerState, ExpressionCompletion.ListKind listKind, int triggerLength, ExpressionNode triggerExpression, IReadOnlyList <ExpressionNode> comparandVariables, MSBuildResolveResult rr, SnapshotPoint triggerLocation, MSBuildRootDocument doc, CancellationToken token) { var kind = MSBuildCompletionExtensions.InferValueKindIfUnknown(info); if (!ExpressionCompletion.ValidateListPermitted(listKind, kind)) { return(CompletionContext.Empty); } bool allowExpressions = kind.AllowExpressions(); kind = kind.GetScalarType(); if (kind == MSBuildValueKind.Data || kind == MSBuildValueKind.Nothing) { return(CompletionContext.Empty); } bool isValue = triggerState == ExpressionCompletion.TriggerState.Value || triggerState == ExpressionCompletion.TriggerState.PropertyOrValue || triggerState == ExpressionCompletion.TriggerState.ItemOrValue || triggerState == ExpressionCompletion.TriggerState.MetadataOrValue; var items = new List <CompletionItem> (); if (comparandVariables != null && isValue) { foreach (var ci in ExpressionCompletion.GetComparandCompletions(doc, comparandVariables)) { items.Add(CreateCompletionItem(ci, doc, rr)); } } if (isValue) { switch (kind) { case MSBuildValueKind.NuGetID: return(await GetPackageNameCompletions(doc, triggerLocation.Position - triggerLength, triggerLength)); case MSBuildValueKind.NuGetVersion: return(await GetPackageVersionCompletions(doc, rr)); case MSBuildValueKind.Sdk: case MSBuildValueKind.SdkWithVersion: return(await GetSdkCompletions(doc, token)); case MSBuildValueKind.Guid: items.Add(CreateSpecialItem("New GUID", "Inserts a new GUID", KnownImages.Add, MSBuildSpecialCommitKind.NewGuid)); break; case MSBuildValueKind.Lcid: items.AddRange(GetLcidCompletions()); break; } } //TODO: better metadata support IEnumerable <BaseInfo> cinfos; if (info.Values != null && info.Values.Count > 0 && isValue) { cinfos = info.Values; } else { //FIXME: can we avoid awaiting this unless we actually need to resolve a function? need to propagate async downwards await provider.FunctionTypeProvider.EnsureInitialized(token); cinfos = ExpressionCompletion.GetCompletionInfos(rr, triggerState, kind, triggerExpression, triggerLength, doc, provider.FunctionTypeProvider); } if (cinfos != null) { foreach (var ci in cinfos) { items.Add(CreateCompletionItem(ci, doc, rr)); } } if ((allowExpressions && isValue) || triggerState == TriggerState.BareFunctionArgumentValue) { items.Add(CreateSpecialItem("$(", "Property reference", KnownImages.MSBuildProperty, MSBuildSpecialCommitKind.PropertyReference)); } if (allowExpressions && isValue) { items.Add(CreateSpecialItem("@(", "Item reference", KnownImages.MSBuildItem, MSBuildSpecialCommitKind.ItemReference)); //FIXME metadata } if (items.Count > 0) { return(CreateCompletionContext(items)); } return(CompletionContext.Empty); }