private static Location GetLocationWithToken(TypeSyntax type, SeparatedSyntaxList <BaseTypeSyntax> baseTypes) { int start; int end; if (baseTypes.Count == 1 || baseTypes.First().Type != type) { start = type.GetFirstToken().GetPreviousToken().Span.Start; end = type.Span.End; } else { start = type.SpanStart; end = type.GetLastToken().GetNextToken().Span.End; } return(Location.Create(type.SyntaxTree, new TextSpan(start, end - start))); }
private VariableDeclaratorSyntax ParseVariableDeclarator(TypeSyntax parentType, bool isExpressionContext = false) { if (!isExpressionContext) { // Check for the common pattern of: // // C //<-- here // Console.WriteLine(); // // Standard greedy parsing will assume that this should be parsed as a variable // declaration: "C Console". We want to avoid that as it can confused parts of the // system further up. So, if we see certain things following the identifier, then we can // assume it's not the actual name. // // So, if we're after a newline and we see a name followed by the list below, then we // assume that we're accidently consuming too far into the next statement. // // <dot>, <arrow>, any binary operator (except =), <question>. None of these characters // are allowed in a normal variable declaration. This also provides a more useful error // message to the user. Instead of telling them that a semicolon is expected after the // following token, then instead get a useful message about an identifier being missing. // The above list prevents: // // C //<-- here // Console.WriteLine(); // // C //<-- here // Console->WriteLine(); // // C // A + B; // etc. // // C // A ? B : D; var resetPoint = GetResetPoint(); try { var currentTokenKind = Current.Kind; if (currentTokenKind == SyntaxKind.IdentifierToken && !parentType.IsMissing) { var isAfterNewLine = parentType.GetLastToken().TrailingTrivia.Any(t => t.Kind == SyntaxKind.EndOfLineTrivia); if (isAfterNewLine) { NextToken(); currentTokenKind = Current.Kind; var isNonEqualsBinaryToken = currentTokenKind != SyntaxKind.EqualsToken && SyntaxFacts.IsBinaryExpression(currentTokenKind); if (currentTokenKind == SyntaxKind.DotToken || isNonEqualsBinaryToken) { var missingIdentifier = InsertMissingToken(SyntaxKind.IdentifierToken); return(new VariableDeclaratorSyntax(missingIdentifier, new List <ArrayRankSpecifierSyntax>(), new List <VariableDeclaratorQualifierSyntax>(), null, null)); } } } } finally { Reset(ref resetPoint); } } var name = Match(SyntaxKind.IdentifierToken); var arrayRankSpecifiers = new List <ArrayRankSpecifierSyntax>(); if (Current.Kind == SyntaxKind.OpenBracketToken) { ParseArrayRankSpecifiers(arrayRankSpecifiers, false); } var qualifiers = new List <VariableDeclaratorQualifierSyntax>(); while (Current.Kind == SyntaxKind.ColonToken) { if (IsPossibleVariableDeclaratorQualifier(Lookahead)) { qualifiers.Add(ParseVariableDeclaratorQualifier()); } else { var action = SkipBadTokens( p => !p.IsPossibleVariableDeclaratorQualifier(Current), p => p.Current.Kind == SyntaxKind.EqualsToken || p.Current.Kind == SyntaxKind.OpenBraceToken || p.IsTerminator(), SyntaxKind.RegisterKeyword); if (action == PostSkipAction.Abort) { break; } } } AnnotationsSyntax annotations = null; if (Current.Kind == SyntaxKind.LessThanToken) { annotations = ParseAnnotations(); } InitializerSyntax initializer = null; if (Current.Kind == SyntaxKind.EqualsToken) { if (Lookahead.Kind == SyntaxKind.SamplerStateLegacyKeyword) { initializer = ParseSamplerStateInitializer(); } else { var equals = NextToken(); var init = ParseVariableInitializer(); initializer = new EqualsValueClauseSyntax(equals, init); } } else if (Current.Kind == SyntaxKind.OpenBraceToken) { if (Lookahead.Kind == SyntaxKind.OpenBraceToken) { initializer = ParseStateArrayInitializer(); } else { initializer = ParseStateInitializer(); } } return(new VariableDeclaratorSyntax(name, arrayRankSpecifiers, qualifiers, annotations, initializer)); }