Skip to content

Commit f694c3c

Browse files
authored
Insert doc comments before declaration attributes (microsoft#192)
1 parent 13e3285 commit f694c3c

File tree

2 files changed

+24
-8
lines changed

2 files changed

+24
-8
lines changed

src/QsCompiler/CompilationManager/EditorSupport/CodeActions.cs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT License.
33

44
using System;
5+
using System.Collections;
56
using System.Collections.Generic;
67
using System.Collections.Immutable;
78
using System.Linq;
@@ -77,7 +78,7 @@ private static IEnumerable<CodeFragment> FragmentsOverlappingWithRange(this File
7778
if (file == null || range?.Start == null || range.End == null) return Enumerable.Empty<CodeFragment>();
7879
var (start, end) = (range.Start.Line, range.End.Line);
7980

80-
var fragAtStart = file.TryGetFragmentAt(range?.Start, out var _, includeEnd: true);
81+
var fragAtStart = file.TryGetFragmentAt(range.Start, out var _, includeEnd: true);
8182
var inRange = file.GetTokenizedLine(start).Select(t => t.WithUpdatedLineNumber(start)).Where(ContextBuilder.TokensAfter(range.Start)); // does not include fragAtStart
8283
inRange = start == end
8384
? inRange.Where(ContextBuilder.TokensStartingBefore(range.End))
@@ -408,17 +409,31 @@ WorkspaceEdit SuggestedRemoval(Position pos)
408409
{
409410
var overlapping = file?.FragmentsOverlappingWithRange(range);
410411
var fragment = overlapping?.FirstOrDefault();
411-
if (fragment?.Kind == null || overlapping.Count() > 1) return Enumerable.Empty<(string, WorkspaceEdit)>(); // only suggest doc comment directly on the declaration
412+
if (fragment?.Kind == null || overlapping.Count() != 1) return Enumerable.Empty<(string, WorkspaceEdit)>(); // only suggest doc comment directly on the declaration
412413

413414
var (nsDecl, callableDecl, typeDecl) = (fragment.Kind.DeclaredNamespace(), fragment.Kind.DeclaredCallable(), fragment.Kind.DeclaredType());
414415
var declSymbol = nsDecl.IsValue ? nsDecl.Item.Item1.Symbol
415416
: callableDecl.IsValue ? callableDecl.Item.Item1.Symbol
416417
: typeDecl.IsValue ? typeDecl.Item.Item1.Symbol : null;
417-
var declRange = fragment?.GetRange();
418-
if (declSymbol == null || file.DocumentingComments(declRange.Start).Any()) return Enumerable.Empty<(string, WorkspaceEdit)>();
418+
var declStart = fragment.GetRange().Start;
419+
if (declSymbol == null || file.DocumentingComments(declStart).Any()) return Enumerable.Empty<(string, WorkspaceEdit)>();
420+
421+
// set declStart to the position of the first attribute attached to the declaration
422+
bool EmptyOrFirstAttribute(IEnumerable<CodeFragment> line, out CodeFragment att)
423+
{
424+
att = line?.Reverse().TakeWhile(t => t.Kind is QsFragmentKind.DeclarationAttribute).LastOrDefault();
425+
return att != null || (line != null && !line.Any());
426+
}
427+
var preceding = file.GetTokenizedLine(declStart.Line).TakeWhile(ContextBuilder.TokensUpTo(new Position(0, declStart.Character)));
428+
for (var lineNr = declStart.Line; EmptyOrFirstAttribute(preceding, out var precedingAttribute); )
429+
{
430+
if (precedingAttribute != null)
431+
{ declStart = precedingAttribute.GetRange().Start.WithUpdatedLineNumber(lineNr); }
432+
preceding = lineNr-- > 0 ? file.GetTokenizedLine(lineNr) : (IEnumerable<CodeFragment>)null;
433+
}
419434

420435
var docPrefix = "/// ";
421-
var endLine = $"{Environment.NewLine}{file.GetLine(declRange.Start.Line).Text.Substring(0, declRange.Start.Character)}";
436+
var endLine = $"{Environment.NewLine}{file.GetLine(declStart.Line).Text.Substring(0, declStart.Character)}";
422437
var docString = $"{docPrefix}# Summary{endLine}{docPrefix}{endLine}";
423438

424439
var (argTuple, typeParams) =
@@ -441,7 +456,7 @@ WorkspaceEdit SuggestedRemoval(Position pos)
441456
);
442457

443458
var whichDecl = $" for {declSymbol.AsDeclarationName(null)}";
444-
var suggestedEdit = file.GetWorkspaceEdit(new TextEdit { Range = new Range { Start = declRange.Start, End = declRange.Start }, NewText = docString });
459+
var suggestedEdit = file.GetWorkspaceEdit(new TextEdit { Range = new Range { Start = declStart, End = declStart }, NewText = docString });
445460
return new[] { ($"Add documentation{whichDecl}.", suggestedEdit) };
446461
}
447462
}

src/QsCompiler/CompilationManager/EditorSupport/SymbolInformation.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,9 @@ internal static bool TryGetReferences(
165165
IImmutableSet<NonNullable<string>> limitToSourceFiles = null)
166166
{
167167
(referenceLocations, declarationLocation) = (null, null);
168-
var symbolInfo = file?.TryGetQsSymbolInfo(position, true, out var _); // includes the end position
169-
if (symbolInfo == null || compilation == null) return false;
168+
if (file == null || compilation == null) return false;
169+
var symbolInfo = file.TryGetQsSymbolInfo(position, true, out var fragment); // includes the end position
170+
if (symbolInfo == null || fragment?.Kind is QsFragmentKind.NamespaceDeclaration) return false;
170171

171172
var sym = symbolInfo.UsedTypes.Any()
172173
&& symbolInfo.UsedTypes.Single().Type is QsTypeKind<QsType, QsSymbol, QsSymbol, Characteristics>.UserDefinedType udt ? udt.Item

0 commit comments

Comments
 (0)