private DirectiveTriviaSyntax ParseElifDirective(SyntaxToken hash, SyntaxToken keyword, bool isActive, bool endIsActive) { var expr = this.ParseExpression(); var eod = this.ParseEndOfDirective(ignoreErrors: false); if (_context.HasPreviousIfOrElif()) { var isTrue = this.EvaluateBool(expr); var branchTaken = endIsActive && isTrue && !_context.PreviousBranchTaken(); return(SyntaxFactory.ElifDirectiveTrivia(hash, keyword, expr, eod, endIsActive, branchTaken, isTrue)); } else { eod = eod.TokenWithLeadingTrivia(SyntaxList.Concat(SyntaxFactory.DisabledText(expr.ToFullString()), eod.GetLeadingTrivia())); if (_context.HasUnfinishedRegion()) { return(this.AddError(SyntaxFactory.BadDirectiveTrivia(hash, keyword, eod, isActive), ErrorCode.ERR_EndRegionDirectiveExpected)); } else if (_context.HasUnfinishedIf()) { return(this.AddError(SyntaxFactory.BadDirectiveTrivia(hash, keyword, eod, isActive), ErrorCode.ERR_EndifDirectiveExpected)); } else { return(this.AddError(SyntaxFactory.BadDirectiveTrivia(hash, keyword, eod, isActive), ErrorCode.ERR_UnexpectedDirective)); } } }
/// <summary> /// Converts skippedSyntax node into tokens and adds these as trivia on the target token. /// Also adds the first error (in depth-first preorder) found in the skipped syntax tree to the target token. /// </summary> internal SyntaxToken AddSkippedSyntax(SyntaxToken target, CSharpSyntaxNode skippedSyntax, bool trailing) { var builder = new SyntaxListBuilder(4); // the error in we'll attach to the node SyntaxDiagnosticInfo diagnostic = null; // the position of the error within the skipedSyntax node full tree int diagnosticOffset = 0; int currentOffset = 0; foreach (var node in skippedSyntax.EnumerateNodes()) { SyntaxToken token = node as SyntaxToken; if (token != null) { builder.Add(token.GetLeadingTrivia()); if (token.Width > 0) { // separate trivia from the tokens SyntaxToken tk = token.WithLeadingTrivia(null).WithTrailingTrivia(null); // adjust relative offsets of diagnostics attached to the token: int leadingWidth = token.GetLeadingTriviaWidth(); if (leadingWidth > 0) { var tokenDiagnostics = tk.GetDiagnostics(); for (int i = 0; i < tokenDiagnostics.Length; i++) { var d = (SyntaxDiagnosticInfo)tokenDiagnostics[i]; tokenDiagnostics[i] = new SyntaxDiagnosticInfo(d.Offset - leadingWidth, d.Width, (ErrorCode)d.Code, d.Arguments); } } builder.Add(SyntaxFactory.SkippedTokensTrivia(tk)); } else { // do not create zero-width structured trivia, GetStructure doesn't work well for them var existing = (SyntaxDiagnosticInfo)token.GetDiagnostics().FirstOrDefault(); if (existing != null) { diagnostic = existing; diagnosticOffset = currentOffset; } } builder.Add(token.GetTrailingTrivia()); currentOffset += token.FullWidth; } else if (node.ContainsDiagnostics && diagnostic == null) { // only propagate the first error to reduce noise: var existing = (SyntaxDiagnosticInfo)node.GetDiagnostics().FirstOrDefault(); if (existing != null) { diagnostic = existing; diagnosticOffset = currentOffset; } } } int triviaWidth = currentOffset; var trivia = builder.ToListNode(); // total width of everything preceding the added trivia int triviaOffset; if (trailing) { var trailingTrivia = target.GetTrailingTrivia(); triviaOffset = target.FullWidth; //added trivia is full width (before addition) target = target.WithTrailingTrivia(SyntaxList.Concat(trailingTrivia, trivia)); } else { // Since we're adding triviaWidth before the token, we have to add that much to // the offset of each of its diagnostics. if (triviaWidth > 0) { var targetDiagnostics = target.GetDiagnostics(); for (int i = 0; i < targetDiagnostics.Length; i++) { var d = (SyntaxDiagnosticInfo)targetDiagnostics[i]; targetDiagnostics[i] = new SyntaxDiagnosticInfo(d.Offset + triviaWidth, d.Width, (ErrorCode)d.Code, d.Arguments); } } var leadingTrivia = target.GetLeadingTrivia(); target = target.WithLeadingTrivia(SyntaxList.Concat(trivia, leadingTrivia)); triviaOffset = 0; //added trivia is first, so offset is zero } if (diagnostic != null) { int newOffset = triviaOffset + diagnosticOffset + diagnostic.Offset; target = WithAdditionalDiagnostics(target, new SyntaxDiagnosticInfo(newOffset, diagnostic.Width, (ErrorCode)diagnostic.Code, diagnostic.Arguments) ); } return(target); }