Skip to content

Commit 873ed19

Browse files
committed
[SourceKit] Add the raw doc comment to the cursor info response
SourceKit-LSP currently parses the XML comment to generate Markdown again but round-tripping a (probably markdown) doc comment to XML to Markdown is lossy in many cases and unnecessary work. Include the comment as it is spelled in source in the cursor info response so that sourcekit-lsp can display it. Part of rdar://120685874
1 parent a2a2083 commit 873ed19

21 files changed

+133
-22
lines changed

include/swift/IDE/CommentConversion.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ bool getDocumentationCommentAsXML(
3232
const Decl *D, raw_ostream &OS,
3333
TypeOrExtensionDecl SynthesizedTarget = TypeOrExtensionDecl());
3434

35+
/// If the declaration has a documentation comment, prints the comment to \p OS
36+
/// in the form it's written in source.
37+
///
38+
/// \returns true if the declaration has a documentation comment.
39+
bool getRawDocumentationComment(const Decl *D, raw_ostream &OS);
40+
3541
/// If the declaration has a documentation comment and a localization key,
3642
/// print it into the given output stream and return true. Else, return false.
3743
bool getLocalizationKey(const Decl *D, raw_ostream &OS);

lib/IDE/CommentConversion.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/Support/MemoryBuffer.h"
2525
#include "llvm/Support/raw_ostream.h"
2626
#include "clang/AST/ASTContext.h"
27+
#include "clang/AST/Comment.h"
2728
#include "clang/AST/Decl.h"
2829
#include "clang/Index/CommentToXML.h"
2930

@@ -496,6 +497,38 @@ bool ide::getDocumentationCommentAsXML(const Decl *D, raw_ostream &OS,
496497
return true;
497498
}
498499

500+
bool ide::getRawDocumentationComment(const Decl *D, raw_ostream &OS) {
501+
ClangNode MaybeClangNode = D->getClangNode();
502+
if (MaybeClangNode) {
503+
const clang::Decl *CD = MaybeClangNode.getAsDecl();
504+
if (!CD) {
505+
return false;
506+
}
507+
const clang::ASTContext &ClangContext = CD->getASTContext();
508+
const clang::comments::FullComment *FC =
509+
ClangContext.getCommentForDecl(CD, /*PP=*/nullptr);
510+
if (!FC) {
511+
return false;
512+
}
513+
const clang::RawComment *rawComment = ClangContext.getRawCommentForAnyRedecl(FC->getDecl());
514+
if (!rawComment) {
515+
return false;
516+
}
517+
OS << rawComment->getFormattedText(ClangContext.getSourceManager(),
518+
ClangContext.getDiagnostics());
519+
return true;
520+
}
521+
522+
const Decl *docD = getDocCommentProvidingDecl(D);
523+
if (!docD) {
524+
return false;
525+
}
526+
RawComment rawComment = docD->getRawComment();
527+
OS << swift::markup::MarkupContext().getLineList(rawComment).str();
528+
OS.flush();
529+
return true;
530+
}
531+
499532
bool ide::getLocalizationKey(const Decl *D, raw_ostream &OS) {
500533
swift::markup::MarkupContext MC;
501534
auto DC = getCascadingDocComment(MC, D);

lib/Markup/LineList.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,19 @@ std::string LineList::str() const {
2424
if (Lines.empty())
2525
return "";
2626

27-
auto FirstLine = Lines.begin();
28-
while (FirstLine != Lines.end() && FirstLine->Text.empty())
29-
++FirstLine;
27+
Line *FirstNonEmptyLine = Lines.begin();
28+
while (FirstNonEmptyLine != Lines.end() && FirstNonEmptyLine->Text.empty())
29+
++FirstNonEmptyLine;
3030

31-
if (FirstLine == Lines.end())
31+
if (FirstNonEmptyLine == Lines.end())
3232
return "";
3333

34-
auto InitialIndentation = measureIndentation(FirstLine->Text);
34+
auto InitialIndentation = measureIndentation(FirstNonEmptyLine->Text);
3535

36-
for (auto Line = FirstLine; Line != Lines.end(); ++Line) {
36+
Stream << FirstNonEmptyLine->Text.drop_front(InitialIndentation);
37+
for (auto Line = FirstNonEmptyLine + 1; Line != Lines.end(); ++Line) {
3738
auto Drop = std::min(InitialIndentation, Line->FirstNonspaceOffset);
38-
Stream << Line->Text.drop_front(Drop) << "\n";
39+
Stream << '\n' << Line->Text.drop_front(Drop);
3940
}
4041

4142
Stream.flush();
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/// Test
2+
/// - Returns: An integer
3+
func test() -> Int {}
4+
// RUN: %sourcekitd-test -req=cursor -pos=%(line - 1):6 %s -- %s | %FileCheck %s
5+
6+
// CHECK-LABEL: DOC COMMENT
7+
// CHECK: Test
8+
// CHECK: - Returns: An integer
9+
10+
// CHECK-LABEL: DOC COMMENT XML
11+
// CHECK: <Function file="{{.*}}" line="3" column="6"><Name>test()</Name><USR>s:18cursor_doc_comment4testSiyF</USR><Declaration>func test() -&gt; Int</Declaration><CommentParts><Abstract><Para>Test</Para></Abstract><ResultDiscussion><Para>An integer</Para></ResultDiscussion></CommentParts></Function>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file --leading-lines %s %t
3+
4+
//--- header.h
5+
6+
/// This comment contains `markup`.
7+
///
8+
/// - And a list
9+
void testCDecl();
10+
11+
//--- module.modulemap
12+
13+
module MyClangModule { header "header.h" }
14+
15+
//--- test.swift
16+
17+
import MyClangModule
18+
19+
func test() {
20+
// RUN: %sourcekitd-test -req=cursor -pos=%(line + 1):3 %s -- %s -I %t | %FileCheck %s
21+
testCDecl()
22+
}
23+
24+
// CHECK-LABEL: DOC COMMENT
25+
// CHECK: This comment contains `markup`.
26+
// CHECK: - And a list
27+
// CHECK-LABEL: DOC COMMENT XML
28+
// CHECK: <Function file="{{.*}}" line="9" column="6"><Name>testCDecl</Name><USR>c:@F@testCDecl</USR><Declaration>func testCDecl()</Declaration><Abstract><Para> This comment contains `markup`.</Para></Abstract><Discussion><Para> - And a list</Para></Discussion></Function>

test/SourceKit/CursorInfo/cursor_info.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,9 @@ let strInterpolation = "This is a \(stringStr + "ing") interpolation"
288288
// CHECK4-NEXT: Foo{{$}}
289289
// CHECK4-NEXT: <Declaration>var fooIntVar: <Type usr="s:s5Int32V">Int32</Type></Declaration>
290290
// CHECK4-NEXT: <decl.var.global><syntaxtype.keyword>var</syntaxtype.keyword> <decl.name>fooIntVar</decl.name>: <decl.var.type><ref.struct usr="s:s5Int32V">Int32</ref.struct></decl.var.type></decl.var.global>
291+
// CHECK4-NEXT: DOC COMMENT
292+
// CHECK4-NEXT: Aaa. fooIntVar. Bbb.
293+
// CHECK4-NEXT: DOC COMMENT XML
291294
// CHECK4-NEXT: <Variable file="{{[^"]+}}Foo.h" line="{{[0-9]+}}" column="{{[0-9]+}}"><Name>fooIntVar</Name><USR>c:@fooIntVar</USR><Declaration>var fooIntVar: Int32</Declaration><Abstract><Para> Aaa. fooIntVar. Bbb.</Para></Abstract></Variable>
292295

293296
// RUN: %sourcekitd-test -req=cursor -pos=8:7 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %s | %FileCheck -check-prefix=CHECK5 %s
@@ -307,6 +310,9 @@ let strInterpolation = "This is a \(stringStr + "ing") interpolation"
307310
// CHECK6-NEXT: FooSwiftModule
308311
// CHECK6-NEXT: <Declaration>func fooSwiftFunc() -&gt; <Type usr="s:Si">Int</Type></Declaration>
309312
// CHECK6-NEXT: <decl.function.free><syntaxtype.keyword>func</syntaxtype.keyword> <decl.name>fooSwiftFunc</decl.name>() -&gt; <decl.function.returntype><ref.struct usr="s:Si">Int</ref.struct></decl.function.returntype></decl.function.free>
313+
// CHECK6-NEXT: DOC COMMENT
314+
// CHECK6-NEXT: This is 'fooSwiftFunc' from 'FooSwiftModule'.
315+
// CHECK6-NEXT: DOC COMMENT XML
310316
// CHECK6-NEXT: {{^}}<Function file="{{.*}}/FooSwiftModule.swift" line="2" column="13"><Name>fooSwiftFunc()</Name><USR>s:14FooSwiftModule03fooB4FuncSiyF</USR><Declaration>func fooSwiftFunc() -&gt; Int</Declaration><CommentParts><Abstract><Para>This is ‘fooSwiftFunc’ from ‘FooSwiftModule’.</Para></Abstract></CommentParts></Function>{{$}}
311317

312318
// RUN: %sourcekitd-test -req=cursor -pos=14:10 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %s | %FileCheck -check-prefix=CHECK7 %s
@@ -319,6 +325,9 @@ let strInterpolation = "This is a \(stringStr + "ing") interpolation"
319325
// CHECK7-NEXT: cursor_info{{$}}
320326
// CHECK7-NEXT: <Declaration>struct S1</Declaration>
321327
// CHECK7-NEXT: <decl.struct><syntaxtype.keyword>struct</syntaxtype.keyword> <decl.name>S1</decl.name></decl.struct>
328+
// CHECK7-NEXT: DOC COMMENT
329+
// CHECK7-NEXT: Aaa. S1. Bbb.
330+
// CHECK7-NEXT: DOC COMMENT XML
322331
// CHECK7-NEXT: <Class file="{{[^"]+}}cursor_info.swift" line="13" column="8"><Name>S1</Name><USR>s:11cursor_info2S1V</USR><Declaration>struct S1</Declaration><CommentParts><Abstract><Para>Aaa. S1. Bbb.</Para></Abstract></CommentParts></Class>
323332

324333
// RUN: %sourcekitd-test -req=cursor -pos=19:12 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %s | %FileCheck -check-prefix=CHECK8 %s
@@ -780,6 +789,11 @@ let strInterpolation = "This is a \(stringStr + "ing") interpolation"
780789
// CHECK87-NEXT: cursor_info{{$}}
781790
// CHECK87-NEXT: <Declaration>struct HasLocalizationKey</Declaration>
782791
// CHECK87-NEXT: <decl.struct><syntaxtype.keyword>struct</syntaxtype.keyword> <decl.name>HasLocalizationKey</decl.name></decl.struct>
792+
// CHECK87-NEXT: DOC COMMENT
793+
// CHECK87-NEXT: Brief.
794+
// CHECK87-EMPTY:
795+
// CHECK87-NEXT: - LocalizationKey: ABC
796+
// CHECK87-NEXT: DOC COMMENT XML
783797
// CHECK87-NEXT: <Class file="{{[^"]+}}cursor_info.swift" line="213" column="8"><Name>HasLocalizationKey</Name><USR>s:11cursor_info18HasLocalizationKeyV</USR><Declaration>struct HasLocalizationKey</Declaration><CommentParts><Abstract><Para>Brief.</Para></Abstract></CommentParts></Class>
784798
// CHECK87-NEXT: <LocalizationKey>ABC</LocalizationKey>
785799

@@ -793,6 +807,9 @@ let strInterpolation = "This is a \(stringStr + "ing") interpolation"
793807
// CHECK88-NEXT: cursor_info{{$}}
794808
// CHECK88-NEXT: <Declaration>func hasLocalizationKey2()</Declaration>
795809
// CHECK88-NEXT: <decl.function.free><syntaxtype.keyword>func</syntaxtype.keyword> <decl.name>hasLocalizationKey2</decl.name>()</decl.function.free>
810+
// CHECK88-NEXT: DOC COMMENT
811+
// CHECK88-NEXT: - LocalizationKey: ABC
812+
// CHECK88-NEXT: DOC COMMENT XML
796813
// CHECK88-NEXT: <Function file="{{[^"]+}}cursor_info.swift" line="216" column="6"><Name>hasLocalizationKey2()</Name><USR>s:11cursor_info19hasLocalizationKey2yyF</USR><Declaration>func hasLocalizationKey2()</Declaration><CommentParts></CommentParts></Function>
797814
// CHECK88-NEXT: <LocalizationKey>ABC</LocalizationKey>
798815

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
"\nDocComment 1\n\nDocComment 2\n"
1+
"\nDocComment 1\n\nDocComment 2"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
"Level1\n Level2\n Level3\n Level4\n Level5\n"
1+
"Level1\n Level2\n Level3\n Level4\n Level5"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
"Level4\nLevel3\nLevel2\nLevel1\n"
1+
"Level4\nLevel3\nLevel2\nLevel1"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
"DocComment 1\nDocComment 2\nDocComment 3\nDocComment 4\n"
1+
"DocComment 1\nDocComment 2\nDocComment 3\nDocComment 4"

0 commit comments

Comments
 (0)