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.");
                }
            }
        }
示例#2
0
    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));
    }
示例#3
0
        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);
        }
示例#4
0
        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);
        }