private static void Compact([NotNull] ExternalAnnotationsMap externalAnnotations) { foreach (string key in externalAnnotations.Keys.ToList()) { MemberNullabilityInfo annotation = externalAnnotations[key]; if (!HasNullabilityDefined(annotation)) { externalAnnotations.Remove(key); } } }
private static bool HasNullabilityDefined([NotNull] MemberNullabilityInfo info) { return(info.HasNullabilityDefined || info.ParametersNullability.Count > 0); }
public void ProcessDocument([NotNull] TextReader reader, [NotNull] ExternalAnnotationsMap result) { Guard.NotNull(reader, nameof(reader)); Guard.NotNull(result, nameof(result)); XElement assemblyElement = XDocument.Load(reader).Element("assembly"); if (assemblyElement != null) { // Known limitation: we are not entirely correct here, by ignoring assembly info. // You'll run into this, for example, with the next block of code: // // public class MyEnumerator : IEnumerator // { // public bool MoveNext() { throw new System.NotImplementedException(); } // // public void Reset() { } // // [CanBeNull] // public object Current { get; } // } // // When you set project properties to target .NET Framework v4.5, Resharper is fine with // the [CanBeNull]. But if you switch to target .NET Framework v2, then Resharper grays // out the [CanBeNull], with hover message "Base declaration has the same annotation". // This is because the external annotation file "2.0.0.0.Interfaces.Nullness.Gen.xml" // contains the following snapshot: // // <?xml version="1.0" encoding="utf-8"?> // <assembly name="mscorlib, Version=2.0.0.0"> // <member name="P:System.Collections.IEnumerator.Current"> // <attribute ctor="M:JetBrains.Annotations.CanBeNullAttribute.#ctor" /> // </member> // </assembly> // // But when targeting the .NET Framework v4.5, mscorlib v4.0.0.0 is used, so this snapshot // does not apply. To support this, we need to add assembly info to our data structure // for each symbol. That makes the dataset grow a lot, taking longer to load/save. foreach (XElement memberElement in assemblyElement.Elements("member")) { string memberType = "?"; string memberName = memberElement.Attribute("name").Value; if (memberName.Length > 2 && memberName[1] == ':') { memberType = memberName[0].ToString(); memberName = memberName.Substring(2); } MemberNullabilityInfo memberInfo = result.ContainsKey(memberName) ? result[memberName] : new MemberNullabilityInfo(memberType); foreach (XElement childElement in memberElement.Elements()) { if (childElement.Name == "parameter") { string parameterName = childElement.Attribute("name").Value; foreach (XElement attributeElement in childElement.Elements("attribute")) { if (ElementHasNullabilityDefinition(attributeElement)) { memberInfo.ParametersNullability[parameterName] = true; } } } if (childElement.Name == "attribute") { if (ElementHasNullabilityDefinition(childElement)) { memberInfo.HasNullabilityDefined = true; } } } result[memberName] = memberInfo; } } }