Exemple #1
0
        /// <summary>
        /// Givent a position, verifies that the position is within the given file, and
        /// returns the effective indentation (i.e. the indentation when ignoring excess brackets throughout the file)
        /// at that position (i.e. not including the char at the given position).
        /// </summary>
        internal static int IndentationAt(this FileContentManager file, Position pos)
        {
            if (!file.ContainsPosition(pos))
            {
                throw new ArgumentException("given position is not within file");
            }
            var line  = file.GetLine(pos.Line);
            var index = pos.Column;

            // check if the given position is within a string or a comment, or denotes an excess bracket,
            // and find the next closest position that isn't
            if (index >= line.WithoutEnding.Length)
            {
                return(line.FinalIndentation());                                   // not necessary, but saves doing the rest of the computation
            }
            index = line.FindInCode(trimmed => trimmed.Length - 1, 0, pos.Column); // if the given position is within a string, then this is the most convenient way to get the closest position that isn't..
            if (index < 0)
            {
                return(line.Indentation); // perfectly valid scenario (if there is no relevant code before the given position)
            }

            // check how much the indentation changes in all valid (i.e. non-comment, non-string, non-excess-brackets) code up to that point
            // NOTE: per specification, this routine returns the indentation not incuding the char at the given position,
            // but if this char was within non-code text, then we need to include this char ... see (*)
            var indexInCode = IndexInRelevantCode(index, line);

            QsCompilerError.Verify(indexInCode >= 0, "index in code should be positive");
            var code        = RelevantCode(line).Substring(0, index < pos.Column ? indexInCode + 1 : indexInCode); // (*) - yep, that's a bit awkward, but the cleanest I can come up with right now
            var indentation = line.Indentation + NrIndents(code) - NrUnindents(code);

            QsCompilerError.Verify(indentation >= 0, "computed indentation at any position in the file should be positive");
            return(indentation);
        }
Exemple #2
0
 /// <summary>
 /// Returns the Position after the last character in the file (including comments).
 /// Throws an ArgumentException is file does not have any content.
 /// </summary>
 public static Position End(this FileContentManager file)
 {
     if (file.NrLines() == 0)
     {
         throw new ArgumentException("file is empty", nameof(file));
     }
     return(Position.Create(file.NrLines() - 1, file.GetLine(file.NrLines() - 1).Text.Length));
 }
Exemple #3
0
        /// <summary>
        /// Returns all namespaces in which a callable with the name of the symbol at the given position in the given
        /// file belongs to.
        ///
        /// Returns an empty collection if any of the arguments is null, if no unqualified symbol exists at that
        /// location, or if the position is not part of a namespace.
        ///
        /// Returns the name of the identifier as an out parameter if an unqualified symbol exists at that location.
        /// </summary>
        private static IEnumerable <string> IdNamespaceSuggestions(
            this FileContentManager file, Position pos, CompilationUnit compilation, out string?idName)
        {
            var variables = file?.TryGetQsSymbolInfo(pos, true, out CodeFragment _)?.UsedVariables;

            idName = variables != null && variables.Any() ? variables.Single().Symbol.AsDeclarationName(null) : null;
            return(idName != null && compilation != null
                ? compilation.GlobalSymbols.NamespacesContainingCallable(idName)
                : ImmutableArray <string> .Empty);
        }
Exemple #4
0
 /// <summary>
 /// Computes excess bracket errors for the given range of lines in file based on the corresponding CodeLine.
 /// Throws an ArgumentOutOfRangeException if the range [start, start + count) is not within file.
 /// </summary>
 private static IEnumerable <Diagnostic> ComputeScopeDiagnostics(this FileContentManager file, int start, int count)
 {
     foreach (var line in file.GetLines(start, count))
     {
         foreach (var pos in line.ExcessBracketPositions)
         {
             yield return(Errors.ExcessBracketError(file.FileName, Position.Create(start, pos)));
         }
         ++start;
     }
 }
Exemple #5
0
        /// <summary>
        /// Returns the position right after where the fragment containing the given position ends.
        /// If the closest previous ending was on the last character in a line, then the returned position is on the same line after the last character.
        /// Updates the given position to point to the first character in the fragment that contains code.
        /// Throws an ArgumentException if the given position is not smaller than the position after the last piece of code in the file (given by LastInFile).
        /// Throws an ArgumentException if the given position is not within file.
        /// </summary>
        internal static Position FragmentEnd(this FileContentManager file, ref Position current)
        {
            if (!file.ContainsPosition(current))
            {
                throw new ArgumentException("given position is not within file");
            }
            var lastInFile = LastInFile(file);

            if (lastInFile <= current)
            {
                throw new ArgumentException("no fragment exists at the given position");
            }
Exemple #6
0
        /// <summary>
        /// Returns names that match an alternative casing of the identifier at the given position in the file, or the
        /// empty enumerable if there is no valid identifier at the given position.
        /// </summary>
        private static IEnumerable <string> IdCaseSuggestions(
            this FileContentManager file, Position pos, CompilationUnit compilation)
        {
            IEnumerable <string> AlternateNames(string name) =>
            from callable in compilation.GlobalSymbols.AccessibleCallables()
            let otherName = callable.QualifiedName.Name
                                where otherName != name && otherName.Equals(name, StringComparison.OrdinalIgnoreCase)
                            select otherName;

            var symbolKind = file.TryGetQsSymbolInfo(pos, true, out _)?.UsedVariables?.SingleOrDefault()?.Symbol;

            return(symbolKind.AsDeclarationName(null)?.Apply(AlternateNames) ?? Enumerable.Empty <string>());
        }
Exemple #7
0
        /// <summary>
        /// Returns all namespaces in which a type with the name of the symbol at the given position in the given file
        /// belongs to.
        ///
        /// Returns an empty collection if any of the arguments is null, if no unqualified symbol exists at that
        /// location, or if the position is not part of a namespace.
        ///
        /// Returns the name of the type as an out parameter if an unqualified symbol exists at that location.
        /// </summary>
        private static IEnumerable <string> TypeNamespaceSuggestions(
            this FileContentManager file, Position pos, CompilationUnit compilation, out string?typeName)
        {
            var types = file?.TryGetQsSymbolInfo(pos, true, out CodeFragment _)?.UsedTypes;

            typeName = types != null && types.Any() &&
                       types.Single().Type is QsTypeKind <QsType, QsSymbol, QsSymbol, Characteristics> .UserDefinedType udt
                ? udt.Item.Symbol.AsDeclarationName(null) : null;

            return(typeName != null && compilation != null
                ? compilation.GlobalSymbols.NamespacesContainingType(typeName)
                : ImmutableArray <string> .Empty);
        }
Exemple #8
0
        /// <summary>
        /// Returns the Position right after where the last relevant (i.e. non-comment) code in the file ends,
        /// or the position (0,0) if no such line exists.
        /// Throws an ArgumentException if file does not contain any lines.
        /// </summary>
        private static Position LastInFile(FileContentManager file)
        {
            if (file.NrLines() == 0)
            {
                throw new ArgumentException("file is null or missing content", nameof(file));
            }
            var endIndex = file.NrLines();

            while (endIndex-- > 0 && file.GetLine(endIndex).WithoutEnding.Trim().Length == 0)
            {
            }
            return(endIndex < 0
                ? Position.Zero
                : Position.Create(endIndex, file.GetLine(endIndex).WithoutEnding.Length));
        }
Exemple #9
0
 /// <summary>
 /// Computes excess bracket errors for the given range of lines in file based on the corresponding CodeLine.
 /// </summary>
 /// <exception cref="ArgumentOutOfRangeException">The range [<paramref name="start"/>, <paramref name="start"/> + <paramref name="count"/>) is not within <paramref name="file"/>.</exception>
 private static IEnumerable <Diagnostic> ComputeScopeDiagnostics(this FileContentManager file, int start, int count)
 {
     foreach (var line in file.GetLines(start, count))
     {
         foreach (var pos in line.ExcessBracketPositions)
         {
             yield return(Errors.ExcessBracketError(file.FileName, Position.Create(start, pos)));
         }
         foreach (var pos in line.ErrorDelimiterPositions)
         {
             yield return(Errors.InvalidCharacterInInterpolatedArgument(file.FileName, Position.Create(start, pos), file.GetLine(start).Text[pos]));
         }
         ++start;
     }
 }
Exemple #10
0
        // routines used to compute scope diagnostics updates

        /// <summary>
        /// Given the total number of excess closings in the file
        /// checks for both an unclosed scope and a missing string ending on lastLine, and adds the corresponding error(s) to updatedScopeErrors.
        /// Throws an ArgumentException if the number of lines in the file is zero.
        /// </summary>
        private static IEnumerable <Diagnostic> CheckForMissingClosings(this FileContentManager file)
        {
            if (file.NrLines() == 0)
            {
                throw new ArgumentException("the number of lines in a file can never be zero");
            }
            var lastLine = file.GetLine(file.NrLines() - 1);

            if (lastLine.FinalIndentation() > 0)
            {
                yield return(Errors.MissingClosingBracketError(file.FileName, Position.Create(file.NrLines() - 1, lastLine.Text.Length)));
            }
            if (ContinueString(lastLine))
            {
                yield return(Errors.MissingStringDelimiterError(file.FileName, Position.Create(file.NrLines() - 1, lastLine.Text.Length)));
            }
        }
Exemple #11
0
 static int MoveNextLine(ref Position position)
 {
     position = Position.Create(position.Line + 1, position.Column);
     return(position.Line);
 }
        // utils for getting the necessary information for editor commands

        internal static Location AsLocation(string source, Position offset, Range relRange) =>