/// <summary> /// An error/warning directive tells the compiler to indicate a syntactic error/warning /// at the current location. /// /// Format: #error Error message string /// Resulting message: from the first non-whitespace character after the directive /// keyword until the end of the directive (aka EOD) at the line break or EOF. /// Resulting span: [first non-whitespace char, EOD) /// /// Examples (pipes indicate span): /// #error |goo| /// #error |goo| /// #error |goo | /// #error |goo baz| /// #error |//goo| /// #error |/*goo*/| /// #error |/*goo| /// </summary> /// <param name="hash">The '#' token.</param> /// <param name="keyword">The 'error' or 'warning' token.</param> /// <param name="isActive">True if the error/warning should be recorded.</param> /// <returns>An ErrorDirective or WarningDirective node.</returns> private DirectiveTriviaSyntax ParseErrorOrWarningDirective(SyntaxToken hash, SyntaxToken keyword, bool isActive) { var eod = this.ParseEndOfDirectiveWithOptionalPreprocessingMessage(); bool isError = keyword.Kind == SyntaxKind.ErrorKeyword; if (isActive) { var triviaBuilder = new System.IO.StringWriter(System.Globalization.CultureInfo.InvariantCulture); int triviaWidth = 0; // whitespace and single line comments are trailing trivia on the keyword, the rest // of the error message is leading trivia on the eod. // bool skipping = true; foreach (var t in keyword.TrailingTrivia) { if (skipping) { if (t.Kind == SyntaxKind.WhitespaceTrivia) { continue; } skipping = false; } t.WriteTo(triviaBuilder, leading: true, trailing: true); triviaWidth += t.FullWidth; } foreach (var node in eod.LeadingTrivia) { node.WriteTo(triviaBuilder, leading: true, trailing: true); triviaWidth += node.FullWidth; } //relative to leading trivia of eod //could be negative if part of the error text comes from the trailing trivia of the keyword token int triviaOffset = eod.GetLeadingTriviaWidth() - triviaWidth; string errorText = triviaBuilder.ToString(); eod = this.AddError(eod, triviaOffset, triviaWidth, isError ? ErrorCode.ERR_ErrorDirective : ErrorCode.WRN_WarningDirective, errorText); if (isError) { if (errorText.Equals("version", StringComparison.Ordinal)) { Assembly assembly = typeof(CSharpCompiler).GetTypeInfo().Assembly; string version = CommonCompiler.GetAssemblyFileVersion(assembly); eod = this.AddError(eod, triviaOffset, triviaWidth, ErrorCode.ERR_CompilerAndLanguageVersion, version, this.Options.SpecifiedLanguageVersion.ToDisplayString()); } else { const string versionMarker = "version:"; if (errorText.StartsWith(versionMarker, StringComparison.Ordinal) && LanguageVersionFacts.TryParse(errorText.Substring(versionMarker.Length), out var languageVersion)) { ErrorCode error = this.Options.LanguageVersion.GetErrorCode(); eod = this.AddError(eod, triviaOffset, triviaWidth, error, "version", new CSharpRequiredLanguageVersion(languageVersion)); } } } } if (isError) { return(SyntaxFactory.ErrorDirectiveTrivia(hash, keyword, eod, isActive)); } else { return(SyntaxFactory.WarningDirectiveTrivia(hash, keyword, eod, isActive)); } }