public SeparatedSyntaxList(IEnumerable <SyntaxBase> elements, IEnumerable <SyntaxBase> separators, TextSpan span) { this.Elements = elements.ToImmutableArray(); this.Separators = separators.ToImmutableArray(); this.Span = span; if (this.Elements.Any()) { if (this.Elements.Length != this.Separators.Length && this.Elements.Length != (this.Separators.Length + 1)) { throw new ArgumentException($"The number of separators ({this.Separators.Length}) must be the same or one less than the number of elements ({this.Elements.Length})."); } // with one or more elements, the span should be from the beginning of the first element to the end of the last element var expectedSpan = TextSpan.Between(this.Elements.First().Span, this.Elements.Last().Span); if (span.Equals(expectedSpan) == false) { throw new ArgumentException($"The specified span '{span}' must be from the beginning of the first element (inclusive) to the end of the last element (exclusive). Expected span '{expectedSpan}'."); } } else { if (this.Separators.Length != 0) { throw new ArgumentException("With zero elements, the number of separators must also be zero."); } if (span.Length != 0) { throw new ArgumentException($"The specified span was '{span}' but expected a zero-length span."); } } }
private static TextSpan GetSpanForRow(ProgramSyntax programSyntax, SyntaxBase declaringSyntax) { // Find the first & last token in the statement var startToken = declaringSyntax.TryFindMostSpecificNodeInclusive(declaringSyntax.Span.Position, x => x is Token) as Token; var endToken = declaringSyntax.TryFindMostSpecificNodeInclusive(declaringSyntax.Span.Position + declaringSyntax.Span.Length, x => x is Token) as Token; // This shouldn't happen, but if it does - fall back to just replacing the statement only if (startToken is null || endToken is null) { return(declaringSyntax.Span); } // If we have leading or trailing trivia (whitespace or comments), take the outermost trivia var startPosSpan = startToken.LeadingTrivia.FirstOrDefault()?.Span ?? startToken.Span; var endPosSpan = endToken.TrailingTrivia.LastOrDefault()?.Span ?? endToken.Span; // If we have a trailing newline, include it in the calculation so that it is removed var followingToken = programSyntax.TryFindMostSpecificNodeInclusive(endPosSpan.Position + endPosSpan.Length, x => x is Token); if (followingToken is Token { Type : TokenType.NewLine } newLineToken) { endPosSpan = newLineToken.Span; } return(TextSpan.Between(startPosSpan, endPosSpan)); }
public void Between_ShouldCalculateCorrectRange(int firstPosition, int firstLength, int secondPosition, int secondLength, string expectedBetweenRange) { var first = new TextSpan(firstPosition, firstLength); var second = new TextSpan(secondPosition, secondLength); TextSpan.Between(first, second).ToString().Should().Be(expectedBetweenRange); TextSpan.Between(second, first).ToString().Should().Be(expectedBetweenRange); }
private TypeSymbol GetFunctionSymbolType( FunctionCallSyntax syntax, FunctionSymbol function, ImmutableArray <FunctionArgumentSyntax> argumentSyntaxes, IList <TypeSymbol> argumentTypes, IList <ErrorDiagnostic> errors) { // Recover argument type errors so we can continue type checking for the parent function call. var recoveredArgumentTypes = argumentTypes .Select(t => t.TypeKind == TypeKind.Error ? LanguageConstants.Any : t) .ToList(); var matches = FunctionResolver.GetMatches( function, recoveredArgumentTypes, out IList <ArgumentCountMismatch> countMismatches, out IList <ArgumentTypeMismatch> typeMismatches).ToList(); if (matches.Count == 0) { if (typeMismatches.Any()) { if (typeMismatches.Count > 1 && typeMismatches.Skip(1).All(tm => tm.ArgumentIndex == typeMismatches[0].ArgumentIndex)) { // All type mismatches are equally good (or bad). var parameterTypes = typeMismatches.Select(tm => tm.ParameterType).ToList(); var argumentType = typeMismatches[0].ArgumentType; var signatures = typeMismatches.Select(tm => tm.Source.TypeSignature).ToList(); var argumentSyntax = argumentSyntaxes[typeMismatches[0].ArgumentIndex]; errors.Add(DiagnosticBuilder.ForPosition(argumentSyntax).CannotResolveFunctionOverload(signatures, argumentType, parameterTypes)); } else { // Choose the type mismatch that has the largest index as the best one. var(_, argumentIndex, argumentType, parameterType) = typeMismatches.OrderBy(tm => tm.ArgumentIndex).Last(); errors.Add(DiagnosticBuilder.ForPosition(argumentSyntaxes[argumentIndex]).ArgumentTypeMismatch(argumentType, parameterType)); } } else { // Argument type mismatch wins over count mismatch. Handle count mismatch only when there's no type mismatch. var(actualCount, mininumArgumentCount, maximumArgumentCount) = countMismatches.Aggregate(ArgumentCountMismatch.Reduce); var argumentsSpan = TextSpan.Between(syntax.OpenParen, syntax.CloseParen); errors.Add(DiagnosticBuilder.ForPosition(argumentsSpan).ArgumentCountMismatch(actualCount, mininumArgumentCount, maximumArgumentCount)); } } if (errors.Any()) { return(new ErrorTypeSymbol(errors)); } if (matches.Count == 1) { // we have an exact match or a single ambiguous match // return its type return(matches.Single().ReturnType); } // function arguments are ambiguous (due to "any" type) // technically, the correct behavior would be to return a union of all possible types // unfortunately our language lacks a good type checking construct // and we also don't want users to have to use the converter functions to work around it // instead, we will return the "any" type to short circuit the type checking for those cases return(LanguageConstants.Any); }