示例#1
0
        // routines called by the file content manager upon updating a file

        /// <summary>
        /// Given the start line of a change, and how many lines have been updated from there,
        /// computes the position where the syntax check will start and end.
        /// Throws an ArgumentNullException if file is null.
        /// Throws an ArgumentOutOfRangeException if the range [start, start + count) is not a valid range within the current file content.
        /// </summary>
        internal static Range GetSyntaxCheckDelimiters(this FileContentManager file, int start, int count)
        {
            if (file == null)
            {
                throw new ArgumentNullException(nameof(file));
            }
            if (start < 0 || start >= file.NrLines())
            {
                throw new ArgumentOutOfRangeException(nameof(start));
            }
            if (count < 0 || start + count > file.NrLines())
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }

            // if no piece of code exists before the start of the modifications, then the check effectively starts at the beginning of the file
            var syntaxCheckStart = file.PositionAfterPrevious(new Position(start, 0)); // position (0,0) if there is no previous fragment
            // if the modification goes past what is currently the last piece of code, then the effectively the check extends to the end of the file
            var firstAfterModified = new Position(start + count, 0);
            var lastInFile         = LastInFile(file);
            var syntaxCheckEnd     = firstAfterModified.IsSmallerThan(lastInFile)
                ? file.FragmentEnd(ref firstAfterModified)
                : file.End();

            return(new Range {
                Start = syntaxCheckStart, End = lastInFile.IsSmallerThanOrEqualTo(syntaxCheckEnd) ? file.End() : syntaxCheckEnd
            });
        }
示例#2
0
        // external routines for context verification

        /// <summary>
        /// Given the line number of the lines that contain tokens that (possibly) have been modified,
        /// checks which callable declaration they can potentially belong to and returns the fully qualified name of those callables.
        /// Throws an ArgumentNullException if the given file or the collection of changed lines is null.
        /// </summary>
        internal static IEnumerable <(Range, QsQualifiedName)> CallablesWithContentModifications(this FileContentManager file, IEnumerable <int> changedLines)
        {
            if (file == null)
            {
                throw new ArgumentNullException(nameof(file));
            }
            if (changedLines == null)
            {
                throw new ArgumentNullException(nameof(changedLines));
            }

            var lastInFile = file.LastToken()?.GetFragment()?.GetRange()?.End ?? file.End();
            var callables  = file.GetCallableDeclarations().Select(tuple => // these are sorted according to their line number
            {
                var ns = file.TryGetNamespaceAt(tuple.Item2.Start);
                QsCompilerError.Verify(ns != null, "namespace for callable declaration should not be null"); // invalid namespace names default to an unknown namespace name, but remain included in the compilation
                return(tuple.Item2.Start, new QsQualifiedName(NonNullable <string> .New(ns), tuple.Item1));
            }).ToList();

            // NOTE: The range of modifications that has to trigger an update of the syntax tree for a callable
            // does need to go up to and include modifications to the line containing the next callable!
            // Otherwise inserting a callable declaration in the middle of an existing callable does not trigger the right behavior!
            (Range, QsQualifiedName) TypeCheckingRange((Position, QsQualifiedName) lastPreceding, IEnumerable <(Position, QsQualifiedName)> next)
            {
                var callableStart = lastPreceding.Item1;
                var callableEnd   = next.Any() ? next.First().Item1 : lastInFile;

                return(new Range {
                    Start = callableStart, End = callableEnd
                }, lastPreceding.Item2);
            }

            foreach (var lineNr in changedLines)
            {
                bool precedes((Position, QsQualifiedName) tuple) => tuple.Item1.Line < lineNr;

                var preceding = callables.TakeWhile(precedes);
                var following = callables.SkipWhile(precedes);

                if (preceding.Any())
                {
                    yield return(TypeCheckingRange(preceding.Last(), following));
                }
                if (following.Any() && following.First().Item1.Line == lineNr)
                {
                    yield return(TypeCheckingRange(following.First(), following.Skip(1)));
                }
            }
        }