// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
///
/// This class stores several source parsing related options and offers access to their values.
///
public sealed class CSharpParseOptions : ParseOptions, IEquatable
{
///
/// The default parse options.
///
public static CSharpParseOptions Default { get; } = new CSharpParseOptions();
private ImmutableDictionary _features;
///
/// Gets the effective language version.
///
public LanguageVersion LanguageVersion { get; private set; }
///
/// Gets the specified language version.
///
public LanguageVersion SpecifiedLanguageVersion { get; private set; }
internal ImmutableArray PreprocessorSymbols { get; private set; }
///
/// Gets the names of defined preprocessor symbols.
///
public override IEnumerable PreprocessorSymbolNames
{
get { return PreprocessorSymbols; }
}
public CSharpParseOptions(
LanguageVersion languageVersion = LanguageVersion.Default,
DocumentationMode documentationMode = DocumentationMode.Parse,
SourceCodeKind kind = SourceCodeKind.Regular,
IEnumerable preprocessorSymbols = null)
: this(languageVersion, documentationMode, kind, preprocessorSymbols.ToImmutableArrayOrEmpty())
{
// 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("preprocessorSymbols");
}
}
}
}
internal CSharpParseOptions(
LanguageVersion languageVersion,
DocumentationMode documentationMode,
SourceCodeKind kind,
IEnumerable preprocessorSymbols,
ImmutableDictionary features)
: this(languageVersion, documentationMode, kind, preprocessorSymbols)
{
if (features == null)
{
throw new ArgumentNullException(nameof(features));
}
_features = features;
}
private CSharpParseOptions(CSharpParseOptions other) : this(
languageVersion: other.SpecifiedLanguageVersion,
documentationMode: other.DocumentationMode,
kind: other.Kind,
preprocessorSymbols: other.PreprocessorSymbols,
features: other.Features.ToImmutableDictionary())
{
}
// No validation
internal CSharpParseOptions(
LanguageVersion languageVersion,
DocumentationMode documentationMode,
SourceCodeKind kind,
ImmutableArray preprocessorSymbols)
: base(kind, documentationMode)
{
Debug.Assert(!preprocessorSymbols.IsDefault);
this.SpecifiedLanguageVersion = languageVersion;
this.LanguageVersion = languageVersion.MapSpecifiedToEffectiveVersion();
this.PreprocessorSymbols = preprocessorSymbols;
_features = ImmutableDictionary.Empty;
}
public new CSharpParseOptions WithKind(SourceCodeKind kind)
{
if (kind == this.Kind)
{
return this;
}
if (!kind.IsValid())
{
throw new ArgumentOutOfRangeException(nameof(kind));
}
return new CSharpParseOptions(this) { Kind = kind };
}
public CSharpParseOptions WithLanguageVersion(LanguageVersion version)
{
if (version == this.SpecifiedLanguageVersion)
{
return this;
}
var effectiveLanguageVersion = version.MapSpecifiedToEffectiveVersion();
if (!effectiveLanguageVersion.IsValid())
{
throw new ArgumentOutOfRangeException(nameof(version));
}
return new CSharpParseOptions(this) { SpecifiedLanguageVersion = version, LanguageVersion = effectiveLanguageVersion };
}
public CSharpParseOptions WithPreprocessorSymbols(IEnumerable preprocessorSymbols)
{
return WithPreprocessorSymbols(preprocessorSymbols.AsImmutableOrNull());
}
public CSharpParseOptions WithPreprocessorSymbols(params string[] preprocessorSymbols)
{
return WithPreprocessorSymbols(ImmutableArray.Create(preprocessorSymbols));
}
public CSharpParseOptions WithPreprocessorSymbols(ImmutableArray symbols)
{
if (symbols.IsDefault)
{
symbols = ImmutableArray.Empty;
}
if (symbols.Equals(this.PreprocessorSymbols))
{
return this;
}
return new CSharpParseOptions(this) { PreprocessorSymbols = symbols };
}
public new CSharpParseOptions WithDocumentationMode(DocumentationMode documentationMode)
{
if (documentationMode == this.DocumentationMode)
{
return this;
}
if (!documentationMode.IsValid())
{
throw new ArgumentOutOfRangeException(nameof(documentationMode));
}
return new CSharpParseOptions(this) { DocumentationMode = documentationMode };
}
public override ParseOptions CommonWithKind(SourceCodeKind kind)
{
return WithKind(kind);
}
protected override ParseOptions CommonWithDocumentationMode(DocumentationMode documentationMode)
{
return WithDocumentationMode(documentationMode);
}
protected override ParseOptions CommonWithFeatures(IEnumerable> features)
{
return WithFeatures(features);
}
///
/// Enable some experimental language features for testing.
///
public new CSharpParseOptions WithFeatures(IEnumerable> features)
{
if (features == null)
{
throw new ArgumentNullException(nameof(features));
}
return new CSharpParseOptions(this) { _features = features.ToImmutableDictionary(StringComparer.OrdinalIgnoreCase) };
}
public override IReadOnlyDictionary Features
{
get
{
return _features;
}
}
internal bool IsFeatureEnabled(MessageID feature)
{
string featureFlag = feature.RequiredFeature();
if (featureFlag != null)
{
return Features.ContainsKey(featureFlag);
}
LanguageVersion availableVersion = LanguageVersion;
LanguageVersion requiredVersion = feature.RequiredVersion();
return availableVersion >= requiredVersion;
}
public override bool Equals(object obj)
{
return this.Equals(obj as CSharpParseOptions);
}
public bool Equals(CSharpParseOptions other)
{
if (object.ReferenceEquals(this, other))
{
return true;
}
if (!base.EqualsHelper(other))
{
return false;
}
return this.SpecifiedLanguageVersion == other.SpecifiedLanguageVersion;
}
public override int GetHashCode()
{
return
Hash.Combine(base.GetHashCodeHelper(),
Hash.Combine((int)this.SpecifiedLanguageVersion, 0));
}
}
}