Пример #1
0
        /// <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 |foo|
        /// #error  |foo|
        /// #error |foo |
        /// #error |foo baz|
        /// #error |//foo|
        /// #error |/*foo*/|
        /// #error |/*foo|
        /// </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;

                eod = this.AddError(eod, triviaOffset, triviaWidth, isError ? ErrorCode.ERR_ErrorDirective : ErrorCode.WRN_WarningDirective, triviaBuilder.ToString());
            }

            if (isError)
            {
                return(SyntaxFactory.ErrorDirectiveTrivia(hash, keyword, eod, isActive));
            }
            else
            {
                return(SyntaxFactory.WarningDirectiveTrivia(hash, keyword, eod, isActive));
            }
        }
Пример #2
0
        /// <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));
            }
        }