//note: the value is unescaped, so offsets within it are not valid void VisitPureLiteral(ValueInfo info, MSBuildValueKind kind, string value, int offset) { IReadOnlyList <ConstantInfo> knownVals = info.Values ?? kind.GetSimpleValues(false); if (knownVals != null && knownVals.Count != 0) { foreach (var kv in knownVals) { if (string.Equals(kv.Name, value, StringComparison.OrdinalIgnoreCase)) { return; } } AddErrorWithArgs(CoreDiagnostics.UnknownValue, DescriptionFormatter.GetKindNoun(info), info.Name, value); return; } switch (kind) { case MSBuildValueKind.Guid: case MSBuildValueKind.ProjectKindGuid: if (!Guid.TryParseExact(value, "B", out _)) { AddErrorWithArgs(CoreDiagnostics.InvalidGuid, value); } break; case MSBuildValueKind.Int: if (!long.TryParse(value, out _)) { AddErrorWithArgs(CoreDiagnostics.InvalidInteger, value); } break; case MSBuildValueKind.Bool: if (!bool.TryParse(value, out _)) { AddErrorWithArgs(CoreDiagnostics.InvalidBool, value); } break; case MSBuildValueKind.Url: if (!Uri.TryCreate(value, UriKind.Absolute, out _)) { AddErrorWithArgs(CoreDiagnostics.InvalidUrl, value); } break; case MSBuildValueKind.Version: if (!Version.TryParse(value, out _)) { AddErrorWithArgs(CoreDiagnostics.InvalidVersion, value); } break; /* * FIXME: these won't work as-is, as inference will add them to the schema * case MSBuildValueKind.TargetName: * if (Document.GetSchemas ().GetTarget (value) == null) { * AddErrorWithArgs (CoreDiagnostics.UndefinedTarget, value); * } * break; * case MSBuildValueKind.PropertyName: * if (Document.GetSchemas ().GetProperty (value) == null) { * AddErrorWithArgs (CoreDiagnostics.UnknownProperty, value); * } * break; * case MSBuildValueKind.ItemName: * if (Document.GetSchemas ().GetItem (value) == null) { * AddErrorWithArgs (CoreDiagnostics.UnknownProperty, value); * } * break; */ case MSBuildValueKind.Lcid: if (int.TryParse(value, out int lcid) && lcid > 0) { try { CultureInfo.GetCultureInfo(lcid); } catch (CultureNotFoundException) { AddErrorWithArgs(CoreDiagnostics.UnknownLcid, value); } } else { AddErrorWithArgs(CoreDiagnostics.InvalidLcid, value); } break; case MSBuildValueKind.TargetFramework: if (!FrameworkInfoProvider.Instance.IsFrameworkShortNameValid(value)) { AddErrorWithArgs(CoreDiagnostics.UnknownTargetFramework, value); } break; case MSBuildValueKind.TargetFrameworkIdentifier: if (!FrameworkInfoProvider.Instance.IsFrameworkIdentifierValid(value)) { AddErrorWithArgs(CoreDiagnostics.UnknownTargetFrameworkIdentifier, value); } break; case MSBuildValueKind.TargetFrameworkVersion: { if (!Version.TryParse(value.TrimStart('v', 'V'), out Version fxv)) { AddErrorWithArgs(CoreDiagnostics.InvalidVersion, value); break; } fxv = new Version(Math.Max(fxv.Major, 0), Math.Max(fxv.Minor, 0), Math.Max(fxv.Revision, 0), Math.Max(fxv.Build, 0)); if (Document is MSBuildRootDocument d && d.Frameworks.Count > 0) { bool foundMatch = false; foreach (var fx in d.Frameworks) { if (FrameworkInfoProvider.AreVersionsEquivalent(fx.Version, fxv) && FrameworkInfoProvider.Instance.IsFrameworkVersionValid(fx.Framework, fxv)) { foundMatch = true; } } if (!foundMatch) { AddErrorWithArgs(CoreDiagnostics.UnknownTargetFrameworkVersion, value, d.Frameworks[0].Framework); } } break; } case MSBuildValueKind.TargetFrameworkProfile: { if (Document is MSBuildRootDocument d && d.Frameworks.Count > 0) { bool foundMatch = false; foreach (var fx in d.Frameworks) { if (fx.Profile == value && FrameworkInfoProvider.Instance.IsFrameworkProfileValid(fx.Framework, fx.Version, value)) { foundMatch = true; } } if (!foundMatch) { AddErrorWithArgs(CoreDiagnostics.UnknownTargetFrameworkProfile, value, d.Frameworks[0].Framework, d.Frameworks[0].Version); } } break; } } void AddError(MSBuildDiagnosticDescriptor d) => Document.Diagnostics.Add(d, new TextSpan(offset, value.Length)); void AddErrorWithArgs(MSBuildDiagnosticDescriptor d, params object[] args) => Document.Diagnostics.Add(d, new TextSpan(offset, value.Length), args); }