@@ -303,7 +303,7 @@ private static int GetFullWidth(SyntaxListBuilder? builder)
303303 private SyntaxToken LexSyntaxToken ( )
304304 {
305305 _leadingTriviaCache . Clear ( ) ;
306- this . LexSyntaxTrivia ( afterFirstToken : TextWindow . Position > 0 , isTrailing : false , triviaList : ref _leadingTriviaCache ) ;
306+ this . LexSyntaxTrivia ( isFollowingToken : TextWindow . Position > 0 , isTrailing : false , triviaList : ref _leadingTriviaCache ) ;
307307 var leading = _leadingTriviaCache ;
308308
309309 var tokenInfo = default ( TokenInfo ) ;
@@ -313,7 +313,7 @@ private SyntaxToken LexSyntaxToken()
313313 var errors = this . GetErrors ( GetFullWidth ( leading ) ) ;
314314
315315 _trailingTriviaCache . Clear ( ) ;
316- this . LexSyntaxTrivia ( afterFirstToken : true , isTrailing : true , triviaList : ref _trailingTriviaCache ) ;
316+ this . LexSyntaxTrivia ( isFollowingToken : true , isTrailing : true , triviaList : ref _trailingTriviaCache ) ;
317317 var trailing = _trailingTriviaCache ;
318318
319319 return Create ( in tokenInfo , leading , trailing , errors ) ;
@@ -322,15 +322,15 @@ private SyntaxToken LexSyntaxToken()
322322 internal SyntaxTriviaList LexSyntaxLeadingTrivia ( )
323323 {
324324 _leadingTriviaCache . Clear ( ) ;
325- this . LexSyntaxTrivia ( afterFirstToken : TextWindow . Position > 0 , isTrailing : false , triviaList : ref _leadingTriviaCache ) ;
325+ this . LexSyntaxTrivia ( isFollowingToken : TextWindow . Position > 0 , isTrailing : false , triviaList : ref _leadingTriviaCache ) ;
326326 return new SyntaxTriviaList ( default ( Microsoft . CodeAnalysis . SyntaxToken ) ,
327327 _leadingTriviaCache . ToListNode ( ) , position : 0 , index : 0 ) ;
328328 }
329329
330330 internal SyntaxTriviaList LexSyntaxTrailingTrivia ( )
331331 {
332332 _trailingTriviaCache . Clear ( ) ;
333- this . LexSyntaxTrivia ( afterFirstToken : true , isTrailing : true , triviaList : ref _trailingTriviaCache ) ;
333+ this . LexSyntaxTrivia ( isFollowingToken : true , isTrailing : true , triviaList : ref _trailingTriviaCache ) ;
334334 return new SyntaxTriviaList ( default ( Microsoft . CodeAnalysis . SyntaxToken ) ,
335335 _trailingTriviaCache . ToListNode ( ) , position : 0 , index : 0 ) ;
336336 }
@@ -1889,7 +1889,7 @@ private bool ScanIdentifierOrKeyword(ref TokenInfo info)
18891889 }
18901890 }
18911891
1892- private void LexSyntaxTrivia ( bool afterFirstToken , bool isTrailing , ref SyntaxListBuilder triviaList )
1892+ private void LexSyntaxTrivia ( bool isFollowingToken , bool isTrailing , ref SyntaxListBuilder triviaList )
18931893 {
18941894 bool onlyWhitespaceOnLine = ! isTrailing ;
18951895
@@ -1995,7 +1995,33 @@ private void LexSyntaxTrivia(bool afterFirstToken, bool isTrailing, ref SyntaxLi
19951995 case '#' :
19961996 if ( _allowPreprocessorDirectives )
19971997 {
1998- this . LexDirectiveAndExcludedTrivia ( afterFirstToken , isTrailing || ! onlyWhitespaceOnLine , ref triviaList ) ;
1998+ if ( isTrailing || ! onlyWhitespaceOnLine )
1999+ {
2000+ // Directives cannot be in trailing trivia.
2001+ // We parse the directive (ignoring its effects like disabled text or defined symbols).
2002+ // We extract the text corresponding to the parsed directive
2003+ // and add it as a BadToken in SkippedTokensTrivia.
2004+
2005+ var savePosition = TextWindow . Position ;
2006+
2007+ // All the `false` arguments affect only error reporting and the resulting node, both of which we discard.
2008+ // However, passing `false` can skip some unnecessary checks.
2009+ this . ParseDirective ( isActive : false , endIsActive : false , isFollowingToken : false ) ;
2010+
2011+ var text = TextWindow . Text . GetSubText ( TextSpan . FromBounds ( savePosition , TextWindow . Position ) ) ;
2012+
2013+ var error = new SyntaxDiagnosticInfo ( offset : 0 , width : 1 , code : ErrorCode . ERR_BadDirectivePlacement ) ;
2014+
2015+ var token = SyntaxFactory . BadToken ( null , text . ToString ( ) , null ) . WithDiagnosticsGreen ( [ error ] ) ;
2016+
2017+ this . AddTrivia ( SyntaxFactory . SkippedTokensTrivia ( token ) , ref triviaList ) ;
2018+ }
2019+ else
2020+ {
2021+ this . LexDirectiveAndExcludedTrivia ( isFollowingToken , ref triviaList ) ;
2022+ }
2023+
2024+ onlyWhitespaceOnLine = true ;
19992025 break ;
20002026 }
20012027 else
@@ -2332,13 +2358,12 @@ private static SyntaxTrivia CreateWhitespaceTrivia(SlidingTextWindow textWindow)
23322358 }
23332359
23342360 private void LexDirectiveAndExcludedTrivia (
2335- bool afterFirstToken ,
2336- bool afterNonWhitespaceOnLine ,
2361+ bool isFollowingToken ,
23372362 ref SyntaxListBuilder triviaList )
23382363 {
2339- var directive = this . LexSingleDirective ( true , true , afterFirstToken , afterNonWhitespaceOnLine , ref triviaList ) ;
2364+ var directive = this . LexSingleDirective ( true , true , isFollowingToken , ref triviaList ) ;
23402365
2341- // also lex excluded stuff
2366+ // also lex excluded stuff
23422367 var branching = directive as BranchingDirectiveTriviaSyntax ;
23432368 if ( branching != null && ! branching . BranchTaken )
23442369 {
@@ -2362,7 +2387,7 @@ private void LexExcludedDirectivesAndTrivia(bool endIsActive, ref SyntaxListBuil
23622387 break ;
23632388 }
23642389
2365- var directive = this . LexSingleDirective ( false , endIsActive , false , false , ref triviaList ) ;
2390+ var directive = this . LexSingleDirective ( false , endIsActive , false , ref triviaList ) ;
23662391 var branching = directive as BranchingDirectiveTriviaSyntax ;
23672392 if ( directive . Kind == SyntaxKind . EndIfDirectiveTrivia || ( branching != null && branching . BranchTaken ) )
23682393 {
@@ -2378,8 +2403,7 @@ private void LexExcludedDirectivesAndTrivia(bool endIsActive, ref SyntaxListBuil
23782403 private CSharpSyntaxNode LexSingleDirective (
23792404 bool isActive ,
23802405 bool endIsActive ,
2381- bool afterFirstToken ,
2382- bool afterNonWhitespaceOnLine ,
2406+ bool isFollowingToken ,
23832407 ref SyntaxListBuilder triviaList )
23842408 {
23852409 if ( SyntaxFacts . IsWhitespace ( TextWindow . PeekChar ( ) ) )
@@ -2388,16 +2412,25 @@ private CSharpSyntaxNode LexSingleDirective(
23882412 this . AddTrivia ( this . ScanWhitespace ( ) , ref triviaList ) ;
23892413 }
23902414
2391- CSharpSyntaxNode directive ;
2415+ CSharpSyntaxNode directive = ParseDirective ( isActive , endIsActive , isFollowingToken ) ;
2416+
2417+ this . AddTrivia ( directive , ref triviaList ) ;
2418+ _directives = directive . ApplyDirectives ( _directives ) ;
2419+ return directive ;
2420+ }
2421+
2422+ private CSharpSyntaxNode ParseDirective (
2423+ bool isActive ,
2424+ bool endIsActive ,
2425+ bool isFollowingToken )
2426+ {
23922427 var saveMode = _mode ;
23932428
23942429 _directiveParser ??= new DirectiveParser ( this ) ;
23952430 _directiveParser . ReInitialize ( _directives ) ;
23962431
2397- directive = _directiveParser . ParseDirective ( isActive , endIsActive , afterFirstToken , afterNonWhitespaceOnLine ) ;
2432+ CSharpSyntaxNode directive = _directiveParser . ParseDirective ( isActive , endIsActive , isFollowingToken ) ;
23982433
2399- this . AddTrivia ( directive , ref triviaList ) ;
2400- _directives = directive . ApplyDirectives ( _directives ) ;
24012434 _mode = saveMode ;
24022435 return directive ;
24032436 }
0 commit comments