Пример #1
0
        public CSharpParseOptions(
            LanguageVersion languageVersion     = LanguageVersion.CSharp6,
            DocumentationMode documentationMode = DocumentationMode.Parse,
            SourceCodeKind kind = SourceCodeKind.Regular,
            ImmutableArray <string> preprocessorSymbols = default(ImmutableArray <string>))
            : this(languageVersion, documentationMode, kind, preprocessorSymbols.NullToEmpty(), privateCtor : true)
        {
            if (!languageVersion.IsValid())
            {
                throw new ArgumentOutOfRangeException("languageVersion");
            }

            if (!kind.IsValid())
            {
                throw new ArgumentOutOfRangeException("kind");
            }

            if (!preprocessorSymbols.IsDefaultOrEmpty)
            {
                foreach (var preprocessorSymbol in preprocessorSymbols)
                {
                    if (!SyntaxKindFacts.IsValidIdentifier(preprocessorSymbol))
                    {
                        throw new ArgumentException("preprocessorSymbols");
                    }
                }
            }
        }
Пример #2
0
        internal void ValidateOptions(
            ArrayBuilder <Diagnostic> builder,
            CommonMessageProvider messageProvider
            )
        {
            // Validate SpecifiedKind not Kind, to catch deprecated specified kinds:
            if (!SpecifiedKind.IsValid())
            {
                builder.Add(
                    messageProvider.CreateDiagnostic(
                        messageProvider.ERR_BadSourceCodeKind,
                        Location.None,
                        SpecifiedKind.ToString()
                        )
                    );
            }

            if (!DocumentationMode.IsValid())
            {
                builder.Add(
                    messageProvider.CreateDiagnostic(
                        messageProvider.ERR_BadDocumentationMode,
                        Location.None,
                        DocumentationMode.ToString()
                        )
                    );
            }
        }
Пример #3
0
        protected void ReadParseOptionsFrom(
            ObjectReader reader,
            out SourceCodeKind kind,
            out DocumentationMode documentationMode,
            out IEnumerable <KeyValuePair <string, string> > features,
            CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            kind = (SourceCodeKind)reader.ReadInt32();
            documentationMode = (DocumentationMode)reader.ReadInt32();

            // REVIEW: I don't think there is a guarantee on ordering of elements in the immutable dictionary.
            //         unfortunately, we need to sort them to make it deterministic
            //         not sure why ParseOptions uses SequencialEqual to check options equality
            //         when ordering can change result of it even if contents are same.
            var count = reader.ReadInt32();
            List <KeyValuePair <string, string> > featuresList = null;

            if (count > 0)
            {
                featuresList = new List <KeyValuePair <string, string> >(count);

                for (var i = 0; i < count; i++)
                {
                    var key   = reader.ReadString();
                    var value = reader.ReadString();

                    featuresList.Add(KeyValuePair.Create(key, value));
                }
            }

            features = featuresList ?? SpecializedCollections.EmptyEnumerable <KeyValuePair <string, string> >();
        }
Пример #4
0
        public CSharpParseOptions(
            LanguageVersion languageVersion     = LanguageVersion.CSharp6,
            DocumentationMode documentationMode = DocumentationMode.Parse,
            SourceCodeKind kind = SourceCodeKind.Regular,
            IEnumerable <string> preprocessorSymbols = null)
            : this(languageVersion, documentationMode, kind, preprocessorSymbols.ToImmutableArrayOrEmpty())
        {
            if (!languageVersion.IsValid())
            {
                throw new ArgumentOutOfRangeException(nameof(languageVersion));
            }

            if (!kind.IsValid())
            {
                throw new ArgumentOutOfRangeException(nameof(kind));
            }

            if (preprocessorSymbols != null)
            {
                foreach (var preprocessorSymbol in preprocessorSymbols)
                {
                    if (!SyntaxFacts.IsValidIdentifier(preprocessorSymbol))
                    {
                        throw new ArgumentException("preprocessorSymbols");
                    }
                }
            }
        }
Пример #5
0
 internal void ValidateOptions(ArrayBuilder <Diagnostic> builder, CommonMessageProvider messageProvider)
 {
     if (!DocumentationMode.IsValid())
     {
         builder.Add(messageProvider.CreateDiagnostic(messageProvider.ERR_BadDocumentationMode, Location.None, DocumentationMode.ToString()));
     }
 }
Пример #6
0
        public CSharpParseOptions(
            LanguageVersion languageVersion     = LanguageVersion.Default,
            DocumentationMode documentationMode = DocumentationMode.Parse,
            SourceCodeKind kind = SourceCodeKind.Regular,
            IEnumerable <string> preprocessorSymbols = null)
            : this(languageVersion,
                   documentationMode,
                   kind,
                   preprocessorSymbols.ToImmutableArrayOrEmpty(),
                   ImmutableDictionary <string, string> .Empty)
        {
            // We test the mapped value, LanguageVersion, rather than the parameter, languageVersion,
            // which has not had "Latest" mapped to the latest version yet.
            if (!LanguageVersion.IsValid())
            {
                throw new ArgumentOutOfRangeException(nameof(languageVersion));
            }

            if (!kind.IsValid())
            {
                throw new ArgumentOutOfRangeException(nameof(kind));
            }

            if (preprocessorSymbols != null)
            {
                foreach (var preprocessorSymbol in preprocessorSymbols)
                {
                    if (!SyntaxFacts.IsValidIdentifier(preprocessorSymbol))
                    {
                        throw new ArgumentException(nameof(preprocessorSymbol));
                    }
                }
            }
        }
Пример #7
0
        // NOTE: warnaserror[+|-], warnaserror[+|-]:<warn list>, unsafe[+|-], warn:<n>, nowarn:<warn list>

        public CSharpParseOptions(
            LanguageVersion languageVersion     = LanguageVersion.CSharp6,
            DocumentationMode documentationMode = DocumentationMode.Parse,
            SourceCodeKind kind = SourceCodeKind.Regular,
            params string[] preprocessorSymbols)
            : this(languageVersion, documentationMode, kind, preprocessorSymbols.AsImmutableOrEmpty())
        {
        }
Пример #8
0
        protected ParseOptions(SerializationInfo info, StreamingContext context)
        {
            //public readonly SourceCodeKind Kind;
            this.Kind = (SourceCodeKind)info.GetValue("Kind", typeof(SourceCodeKind));

            //public readonly DocumentationMode DocumentationMode;
            this.DocumentationMode = (DocumentationMode)info.GetValue("DocumentationMode", typeof(DocumentationMode));
        }
 private EvaluatedProjectState(
     string name,
     string assemblyName,
     string language,
     ReferenceAssemblies referenceAssemblies,
     OutputKind outputKind,
     DocumentationMode documentationMode,
     ImmutableArray <(string filename, SourceText content)> sources,
Пример #10
0
 internal MetaParseOptions(
     MetaLanguageVersion languageVersion,
     DocumentationMode documentationMode,
     SourceCodeKind kind,
     ImmutableArray <string> preprocessorSymbols,
     IReadOnlyDictionary <string, string> features)
     : base(languageVersion, documentationMode, kind, preprocessorSymbols, features)
 {
 }
Пример #11
0
        public async Task TestEnabledDocumentationModesAsync(DocumentationMode documentationMode)
        {
            var testCode = @"public class Foo
{
}
";

            this.documentationMode = documentationMode;
            await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
        }
Пример #12
0
        public async Task TestEnabledDocumentationModesAsync(DocumentationMode documentationMode)
        {
            var testCode = @"public class Foo
{
}
";

            this.documentationMode = documentationMode;
            await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
        }
Пример #13
0
 internal PhpParseOptions(
     DocumentationMode documentationMode,
     SourceCodeKind kind,
     Version languageVersion,
     bool shortOpenTags,
     ImmutableDictionary <string, string> features)
     : this(documentationMode, kind, languageVersion, shortOpenTags)
 {
     _features = features ?? throw new ArgumentNullException(nameof(features));
 }
Пример #14
0
 public PhpParseOptions(
     DocumentationMode documentationMode = DocumentationMode.Parse,
     SourceCodeKind kind = SourceCodeKind.Regular)
     : base(kind, documentationMode)
 {
     if (!kind.IsValid())
     {
         throw new ArgumentOutOfRangeException(nameof(kind));
     }
 }
Пример #15
0
        internal ParseOptions(DocumentationMode documentationMode)
        {
            DocumentationMode = documentationMode;

            _lazyErrors = new Lazy <ImmutableArray <Diagnostic> >(() =>
            {
                var builder = ArrayBuilder <Diagnostic> .GetInstance();
                ValidateOptions(builder);
                return(builder.ToImmutableAndFree());
            });
        }
Пример #16
0
 // No validation
 internal CSharpParseOptions(
     LanguageVersion languageVersion,
     DocumentationMode documentationMode,
     SourceCodeKind kind,
     ImmutableArray <string> preprocessorSymbols)
     : base(kind, documentationMode)
 {
     Debug.Assert(!preprocessorSymbols.IsDefault);
     this.LanguageVersion     = languageVersion;
     this.PreprocessorSymbols = preprocessorSymbols;
 }
Пример #17
0
 public new MetaParseOptions WithDocumentationMode(DocumentationMode documentationMode)
 {
     if (documentationMode == this.DocumentationMode)
     {
         return(this);
     }
     return(new MetaParseOptions(this)
     {
         DocumentationMode = documentationMode
     });
 }
Пример #18
0
 public CSharpParseOptions(
     LanguageVersion languageVersion     = LanguageVersion.Default,
     DocumentationMode documentationMode = DocumentationMode.Parse,
     SourceCodeKind kind = SourceCodeKind.Regular,
     IEnumerable <string> preprocessorSymbols = null)
     : this(languageVersion,
            documentationMode,
            kind,
            preprocessorSymbols.ToImmutableArrayOrEmpty(),
            ImmutableDictionary <string, string> .Empty)
 {
 }
Пример #19
0
        public async Task TestDisabledDocumentationModesAsync(DocumentationMode documentationMode)
        {
            var testCode = @"public class Foo
{
}
";

            DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(null, 0, 0);

            this.documentationMode = documentationMode;
            await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
        }
Пример #20
0
        private ParseOptions GetParseOptions(DocumentationMode documentationMode, [NotNull] string languageName)
        {
#pragma warning disable AV2310 // Code blocks should not contain inline comments
            // Bug workaround: Setting DocumentationMode to a non-default value resets Features.
#pragma warning restore AV2310 // Code blocks should not contain inline comments

            ParseOptions optionsWithLostFeatures = languageName == LanguageNames.VisualBasic
                ? (ParseOptions)DefaultBasicParseOptions.WithDocumentationMode(documentationMode)
                : DefaultCSharpParseOptions.WithDocumentationMode(documentationMode);

            return(optionsWithLostFeatures.WithFeatures(OperationFeature));
        }
Пример #21
0
        private ParseOptions GetParseOptions(DocumentationMode documentationMode, [NotNull] string languageName,
                                             OperationFeature operationFeature)
        {
            // Bug workaround: Setting DocumentationMode to a non-default value resets Features.
            ParseOptions optionsWithLostFeatures = languageName == LanguageNames.VisualBasic
                ? (ParseOptions)DefaultBasicParseOptions.WithDocumentationMode(documentationMode)
                : DefaultCSharpParseOptions.WithDocumentationMode(documentationMode);

            return(operationFeature == OperationFeature.Enabled
                ? optionsWithLostFeatures.WithFeatures(OperationFeatureFlag)
                : optionsWithLostFeatures);
        }
Пример #22
0
 // No validation
 internal CSharpParseOptions(
     LanguageVersion languageVersion,
     DocumentationMode documentationMode,
     SourceCodeKind kind,
     ImmutableArray <string> preprocessorSymbols,
     bool privateCtor)             //dummy param to distinguish from public ctor
     : base(kind, documentationMode)
 {
     Debug.Assert(!preprocessorSymbols.IsDefault);
     this.LanguageVersion     = languageVersion;
     this.PreprocessorSymbols = preprocessorSymbols;
 }
Пример #23
0
        public async Task TestDisabledDocumentationModesAsync(DocumentationMode documentationMode)
        {
            var testCode = @"public class Foo
{
}
";

            DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(null, 0, 0);

            this.documentationMode = documentationMode;
            await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
        }
Пример #24
0
 // No validation
 internal CSharpParseOptions(
     LanguageVersion languageVersion,
     DocumentationMode documentationMode,
     SourceCodeKind kind,
     ImmutableArray <string> preprocessorSymbols)
     : base(kind, documentationMode)
 {
     Debug.Assert(!preprocessorSymbols.IsDefault);
     this.SpecifiedLanguageVersion = languageVersion;
     this.LanguageVersion          = languageVersion.MapSpecifiedToEffectiveVersion();
     this.PreprocessorSymbols      = preprocessorSymbols;
     _features = ImmutableDictionary <string, string> .Empty;
 }
Пример #25
0
        public async Task TestDisabledDocumentationModesAsync(DocumentationMode documentationMode)
        {
            var testCode = @"public class Foo
{
}
";

            // This diagnostic is reported without a location
            DiagnosticResult expected = this.CSharpDiagnostic();

            this.documentationMode = documentationMode;
            await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
        }
Пример #26
0
        internal PhpParseOptions(
            DocumentationMode documentationMode,
            SourceCodeKind kind,
            ImmutableDictionary <string, string> features)
            : this(documentationMode, kind)
        {
            if (features == null)
            {
                throw new ArgumentNullException(nameof(features));
            }

            _features = features;
        }
Пример #27
0
 internal CSharpParseOptions(
     LanguageVersion languageVersion,
     DocumentationMode documentationMode,
     SourceCodeKind kind,
     IEnumerable <string> preprocessorSymbols,
     IReadOnlyDictionary <string, string> features)
     : base(kind, documentationMode)
 {
     this.SpecifiedLanguageVersion = languageVersion;
     this.LanguageVersion          = languageVersion.MapSpecifiedToEffectiveVersion();
     this.PreprocessorSymbols      = preprocessorSymbols.ToImmutableArrayOrEmpty();
     _features = features?.ToImmutableDictionary() ?? ImmutableDictionary <string, string> .Empty;
 }
Пример #28
0
        public async Task TestDisabledDocumentationModesAsync(DocumentationMode documentationMode)
        {
            var testCode = @"public class Foo
{
}
";

            // This diagnostic is reported without a location
            DiagnosticResult expected = this.CSharpDiagnostic();

            this.documentationMode = documentationMode;
            await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
        }
Пример #29
0
        internal ParseOptions(SourceCodeKind kind, DocumentationMode documentationMode)
        {
            this.SpecifiedKind     = kind;
            this.Kind              = kind.MapSpecifiedToEffectiveKind();
            this.DocumentationMode = documentationMode;

            _lazyErrors = new Lazy <ImmutableArray <Diagnostic> >(() =>
            {
                var builder = ArrayBuilder <Diagnostic> .GetInstance();
                ValidateOptions(builder);
                return(builder.ToImmutableAndFree());
            });
        }
Пример #30
0
 protected LanguageParseOptions(
     LanguageVersion languageVersion,
     DocumentationMode documentationMode,
     SourceCodeKind kind,
     ImmutableArray <string> preprocessorSymbols,
     IReadOnlyDictionary <string, string> features)
     : base(kind, documentationMode)
 {
     this.SpecifiedLanguageVersion = languageVersion ?? LanguageVersion.Default;
     this.LanguageVersion          = languageVersion;
     this.PreprocessorSymbols      = preprocessorSymbols.ToImmutableArrayOrEmpty();
     _features = features?.ToImmutableDictionary() ?? ImmutableDictionary <string, string> .Empty;
 }
Пример #31
0
        internal CSharpParseOptions(
            LanguageVersion languageVersion,
            DocumentationMode documentationMode,
            SourceCodeKind kind,
            IEnumerable <string> preprocessorSymbols,
            ImmutableDictionary <string, string> features)
            : this(languageVersion, documentationMode, kind, preprocessorSymbols)
        {
            if (features == null)
            {
                throw new ArgumentNullException(nameof(features));
            }

            _features = features;
        }
#pragma warning disable AV1561 // Method or constructor contains more than three parameters
#pragma warning disable AV1500 // Member contains more than seven statements
        private AnalyzerTestContext([NotNull] string markupCode, [NotNull] string languageName, [NotNull] string fileName,
                                    [NotNull] string assemblyName, [NotNull][ItemNotNull] ImmutableHashSet <MetadataReference> references,
                                    DocumentationMode documentationMode, [CanBeNull] int?compilerWarningLevel, TestValidationMode validationMode,
                                    DiagnosticsCaptureMode diagnosticsCaptureMode)
        {
            MarkupCode             = markupCode;
            LanguageName           = languageName;
            FileName               = fileName;
            AssemblyName           = assemblyName;
            References             = references;
            DocumentationMode      = documentationMode;
            CompilerWarningLevel   = compilerWarningLevel;
            ValidationMode         = validationMode;
            DiagnosticsCaptureMode = diagnosticsCaptureMode;
        }
Пример #33
0
        public PhpParseOptions(
            DocumentationMode documentationMode = DocumentationMode.Parse,
            SourceCodeKind kind     = SourceCodeKind.Regular,
            Version languageVersion = null,
            bool shortOpenTags      = false)
            : base(kind, documentationMode)
        {
            if (!kind.IsValid())
            {
                throw new ArgumentOutOfRangeException(nameof(kind));
            }

            _languageVersion    = languageVersion;
            _allowShortOpenTags = shortOpenTags;
        }
Пример #34
0
		private static void GenerateTableOfContents(HtmlHelper htmlHelper, UrlHelper urlHelper, StringBuilder builder, IEnumerable<TableOfContents.TableOfContentsItem> items, string key, int level, string version, DocumentationMode mode)
		{
			foreach (var item in items)
			{
				var containsKey = level == 0 && item.IsFolder && ContainsKey(item, key, 3);

				var css = string.Empty;
				var isCurrent = string.Equals(key, item.Key, StringComparison.OrdinalIgnoreCase);
				if (isCurrent)
					css += "selected ";

				if (item.IsFolder)
				{
					css += "folder ";
					if (containsKey)
						css += "in ";
					else
						css += "out ";
				}

				builder.AppendLine(string.Format("<li class='list-group-item {0}'>", css));

				if (item.IsFolder)
					GenerateForFolder(htmlHelper, urlHelper, builder, item, key, level, containsKey, version, mode);
				else
					GenerateForArticle(htmlHelper, builder, item);

				builder.AppendLine("</li>");
			}
		}
Пример #35
0
        protected ParseOptions(SerializationInfo info, StreamingContext context)
        {
            //public readonly SourceCodeKind Kind;
            this.Kind = (SourceCodeKind)info.GetValue("Kind", typeof(SourceCodeKind));

            //public readonly DocumentationMode DocumentationMode;
            this.DocumentationMode = (DocumentationMode)info.GetValue("DocumentationMode", typeof(DocumentationMode));
        }
Пример #36
0
        public async Task TestDocumentationAsync()
        {
            var testCode = @"/// <summary>
/// Some text
/// </summary>
public class Bar
{
}
";
            await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);

            // Verify that this works if the project was configured to treat documentation comments as regular comments
            this.documentationMode = DocumentationMode.None;

            await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
        }
        /// <summary>
        /// Get all of the DocumentationCommentTriviaSyntax associated with any declaring syntax of the
        /// given symbol (except for partial methods, which only consider the part with the body).
        /// </summary>
        /// <returns>True if the nodes are all valid XML.</returns>
        private bool TryGetDocumentationCommentNodes(Symbol symbol, out DocumentationMode maxDocumentationMode, out ImmutableArray<DocumentationCommentTriviaSyntax> nodes)
        {
            maxDocumentationMode = DocumentationMode.None;
            nodes = default(ImmutableArray<DocumentationCommentTriviaSyntax>);

            ArrayBuilder<DocumentationCommentTriviaSyntax> builder = null;

            foreach (SyntaxReference reference in symbol.DeclaringSyntaxReferences)
            {
                DocumentationMode currDocumentationMode = reference.SyntaxTree.Options.DocumentationMode;
                maxDocumentationMode = currDocumentationMode > maxDocumentationMode ? currDocumentationMode : maxDocumentationMode;

                ImmutableArray<DocumentationCommentTriviaSyntax> triviaList = SourceDocumentationCommentUtils.GetDocumentationCommentTriviaFromSyntaxNode((CSharpSyntaxNode)reference.GetSyntax(), _diagnostics);
                foreach (var trivia in triviaList)
                {
                    if (ContainsXmlParseDiagnostic(trivia))
                    {
                        if (builder != null)
                        {
                            builder.Free();
                        }
                        return false;
                    }

                    if (builder == null)
                    {
                        builder = ArrayBuilder<DocumentationCommentTriviaSyntax>.GetInstance();
                    }
                    builder.Add(trivia);
                }
            }

            if (builder == null)
            {
                nodes = ImmutableArray<DocumentationCommentTriviaSyntax>.Empty;
            }
            else
            {
                builder.Sort(Comparer);
                nodes = builder.ToImmutableAndFree();
            }

            return true;
        }
Пример #38
0
		private static void GenerateForFolder(HtmlHelper htmlHelper, UrlHelper urlHelper, StringBuilder builder, TableOfContents.TableOfContentsItem item, string key, int level, bool containsKey, string version, DocumentationMode mode)
		{
			if (mode == DocumentationMode.Legacy)
				builder.AppendLine(string.Format("<a href='{0}'>", urlHelper.Action(MVC.Docs.ActionNames.Articles, MVC.Docs.Name, new { version = version, language = Language.Csharp, key = item.Key })));

			builder.AppendLine(string.Format("<span class='fa fa-folder {1}'></span><span>{0}</span>", item.Title, containsKey ? "text-danger" : string.Empty));

			if (mode == DocumentationMode.Legacy)
				builder.AppendLine("</a>");

			builder.AppendLine("<ul class='list-group'>");

			GenerateTableOfContents(htmlHelper, urlHelper, builder, item.Items, key, ++level, version, mode);

			builder.AppendLine("</ul>");
		}
Пример #39
0
 internal ParseOptions(SourceCodeKind kind, DocumentationMode documentationMode)
 {
     this.Kind = kind;
     this.DocumentationMode = documentationMode;
 }
Пример #40
0
 /// <summary>
 /// Creates a new options instance with the specified documentation mode.
 /// </summary>
 public ParseOptions WithDocumentationMode(DocumentationMode documentationMode)
 {
     return CommonWithDocumentationMode(documentationMode);
 }
Пример #41
0
 protected abstract ParseOptions CommonWithDocumentationMode(DocumentationMode documentationMode);
 private static CSharpParseOptions GetOptions(DocumentationMode mode)
 {
     return TestOptions.Regular.WithDocumentationMode(mode);
 }
        protected void ReadParseOptionsFrom(
            ObjectReader reader,
            out SourceCodeKind kind,
            out DocumentationMode documentationMode,
            out IEnumerable<KeyValuePair<string, string>> features,
            CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            kind = (SourceCodeKind)reader.ReadInt32();
            documentationMode = (DocumentationMode)reader.ReadInt32();

            // REVIEW: I don't think there is a guarantee on ordering of elements in the immutable dictionary.
            //         unfortunately, we need to sort them to make it deterministic
            //         not sure why ParseOptions uses SequencialEqual to check options equality
            //         when ordering can change result of it even if contents are same.
            var count = reader.ReadInt32();
            List<KeyValuePair<string, string>> featuresList = null;

            if (count > 0)
            {
                featuresList = new List<KeyValuePair<string, string>>(count);

                for (var i = 0; i < count; i++)
                {
                    var key = reader.ReadString();
                    var value = reader.ReadString();

                    featuresList.Add(KeyValuePair.Create(key, value));
                }
            }

            features = featuresList ?? SpecializedCollections.EmptyEnumerable<KeyValuePair<string, string>>();
        }