10#include "clang-c/Index.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/AST/RawCommentList.h"
13#include "clang/Basic/SourceManager.h"
14#include "clang/Sema/CodeCompleteConsumer.h"
15#include "llvm/Support/JSON.h"
23bool isInformativeQualifierChunk(CodeCompletionString::Chunk
const &Chunk) {
24 return Chunk.Kind == CodeCompletionString::CK_Informative &&
25 llvm::StringRef(Chunk.Text).endswith(
"::");
28void appendEscapeSnippet(
const llvm::StringRef
Text, std::string *
Out) {
29 for (
const auto Character :
Text) {
30 if (Character ==
'$' || Character ==
'}' || Character ==
'\\')
32 Out->push_back(Character);
36void appendOptionalChunk(
const CodeCompletionString &CCS, std::string *
Out) {
37 for (
const CodeCompletionString::Chunk &
C : CCS) {
39 case CodeCompletionString::CK_Optional:
41 "Expected the optional code completion string to be non-null.");
42 appendOptionalChunk(*
C.Optional,
Out);
51bool looksLikeDocComment(llvm::StringRef CommentText) {
57 return CommentText.find_first_not_of(
"/*-= \t\r\n") != llvm::StringRef::npos;
62bool shouldPatchPlaceholder0(CodeCompletionResult::ResultKind ResultKind,
63 CXCursorKind CursorKind) {
64 bool CompletingPattern = ResultKind == CodeCompletionResult::RK_Pattern;
66 if (!CompletingPattern)
73 if (CursorKind == CXCursorKind::CXCursor_Constructor ||
74 CursorKind == CXCursorKind::CXCursor_Destructor)
83 const CodeCompletionResult &Result,
84 bool CommentsFromHeaders) {
88 if (Result.Kind != CodeCompletionResult::RK_Declaration)
90 return Result.getDeclaration() ?
getDeclComment(Ctx, *Result.getDeclaration())
95 if (isa<NamespaceDecl>(
Decl)) {
102 const RawComment *RC = getCompletionComment(Ctx, &
Decl);
107 assert(!Ctx.getSourceManager().isLoadedSourceLocation(RC->getBeginLoc()));
109 RC->getFormattedText(Ctx.getSourceManager(), Ctx.getDiagnostics());
110 if (!looksLikeDocComment(Doc))
113 if (!llvm::json::isUTF8(Doc))
114 Doc = llvm::json::fixUTF8(Doc);
120 CodeCompletionResult::ResultKind ResultKind,
121 CXCursorKind CursorKind, std::string *RequiredQualifiers) {
124 unsigned CursorSnippetArg = std::numeric_limits<unsigned>::max();
132 if (shouldPatchPlaceholder0(ResultKind, CursorKind)) {
134 llvm::count_if(CCS, [](
const CodeCompletionString::Chunk &
C) {
135 return C.Kind == CodeCompletionString::CK_Placeholder;
138 unsigned SnippetArg = 0;
139 bool HadObjCArguments =
false;
140 bool HadInformativeChunks =
false;
141 for (
const auto &Chunk : CCS) {
144 if (isInformativeQualifierChunk(Chunk))
147 switch (Chunk.Kind) {
148 case CodeCompletionString::CK_TypedText:
164 if (!llvm::StringRef(Chunk.Text).endswith(
":")) {
165 if (RequiredQualifiers)
166 *RequiredQualifiers = std::move(*
Signature);
176 if (!HadObjCArguments) {
177 HadObjCArguments =
true;
195 if (!HadInformativeChunks) {
196 if (RequiredQualifiers)
197 *RequiredQualifiers = std::move(*
Signature);
207 case CodeCompletionString::CK_Text:
211 case CodeCompletionString::CK_Optional:
212 assert(Chunk.Optional);
214 appendOptionalChunk(*Chunk.Optional,
Signature);
216 case CodeCompletionString::CK_Placeholder:
219 if (SnippetArg == CursorSnippetArg) {
224 *
Snippet +=
"${" + std::to_string(SnippetArg) +
':';
225 appendEscapeSnippet(Chunk.Text,
Snippet);
229 case CodeCompletionString::CK_Informative:
230 HadInformativeChunks =
true;
236 case CodeCompletionString::CK_ResultType:
239 case CodeCompletionString::CK_CurrentParameter:
242 llvm_unreachable(
"Unexpected CK_CurrentParameter while collecting "
245 case CodeCompletionString::CK_LeftParen:
246 case CodeCompletionString::CK_RightParen:
247 case CodeCompletionString::CK_LeftBracket:
248 case CodeCompletionString::CK_RightBracket:
249 case CodeCompletionString::CK_LeftBrace:
250 case CodeCompletionString::CK_RightBrace:
251 case CodeCompletionString::CK_LeftAngle:
252 case CodeCompletionString::CK_RightAngle:
253 case CodeCompletionString::CK_Comma:
254 case CodeCompletionString::CK_Colon:
255 case CodeCompletionString::CK_SemiColon:
256 case CodeCompletionString::CK_Equal:
257 case CodeCompletionString::CK_HorizontalSpace:
261 case CodeCompletionString::CK_VerticalSpace:
270 llvm::StringRef DocComment) {
274 const unsigned AnnotationCount = CCS.getAnnotationCount();
275 if (AnnotationCount > 0) {
276 Result +=
"Annotation";
277 if (AnnotationCount == 1) {
282 for (
unsigned I = 0; I < AnnotationCount; ++I) {
283 Result += CCS.getAnnotation(I);
284 Result.push_back(I == AnnotationCount - 1 ?
'\n' :
' ');
288 if (!DocComment.empty()) {
289 if (!Result.empty()) {
292 Result.push_back(
'\n');
294 Result += DocComment;
300 for (
const auto &Chunk : CCS)
301 if (Chunk.Kind == CodeCompletionString::CK_ResultType)
const FunctionDecl * Decl
CompiledFragmentImpl & Out
std::string formatDocumentation(const CodeCompletionString &CCS, llvm::StringRef DocComment)
Assembles formatted documentation for a completion result.
std::string getDeclComment(const ASTContext &Ctx, const NamedDecl &Decl)
Similar to getDocComment, but returns the comment for a NamedDecl.
std::string getReturnType(const CodeCompletionString &CCS)
Gets detail to be used as the detail field in an LSP completion item.
void getSignature(const CodeCompletionString &CCS, std::string *Signature, std::string *Snippet, CodeCompletionResult::ResultKind ResultKind, CXCursorKind CursorKind, std::string *RequiredQualifiers)
Formats the signature for an item, as a display string and snippet.
std::string getDocComment(const ASTContext &Ctx, const CodeCompletionResult &Result, bool CommentsFromHeaders)
Gets a minimally formatted documentation comment of Result, with comment markers stripped.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//