blob: cb4e8ef826b10967540fe0ae545edff80a5241ca [file] [log] [blame]
Douglas Gregor86d9a522009-09-21 16:56:56 +00001//===--- CodeCompleteConsumer.cpp - Code Completion Interface ---*- C++ -*-===//
Douglas Gregor81b747b2009-09-17 21:32:03 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the CodeCompleteConsumer class.
11//
12//===----------------------------------------------------------------------===//
13#include "clang/Sema/CodeCompleteConsumer.h"
Douglas Gregor75b71282009-09-18 17:54:00 +000014#include "clang/AST/DeclCXX.h"
Douglas Gregor374929f2009-09-18 15:37:17 +000015#include "clang/Parse/Scope.h"
Douglas Gregor81b747b2009-09-17 21:32:03 +000016#include "clang/Lex/Preprocessor.h"
17#include "Sema.h"
18#include "llvm/ADT/STLExtras.h"
Douglas Gregor0c8296d2009-11-07 00:00:49 +000019#include "llvm/ADT/StringSwitch.h"
Douglas Gregor81b747b2009-09-17 21:32:03 +000020#include "llvm/Support/Compiler.h"
21#include "llvm/Support/raw_ostream.h"
22#include <algorithm>
Douglas Gregore6e03612009-09-18 22:15:54 +000023#include <cstring>
24#include <functional>
Douglas Gregor81b747b2009-09-17 21:32:03 +000025using namespace clang;
26
Douglas Gregore6e03612009-09-18 22:15:54 +000027//===----------------------------------------------------------------------===//
28// Code completion string implementation
29//===----------------------------------------------------------------------===//
Douglas Gregor0c8296d2009-11-07 00:00:49 +000030CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text)
Douglas Gregor0563c262009-09-22 23:15:58 +000031 : Kind(Kind), Text(0)
32{
Douglas Gregor0c8296d2009-11-07 00:00:49 +000033 switch (Kind) {
34 case CK_TypedText:
35 case CK_Text:
36 case CK_Placeholder:
37 case CK_Informative:
38 case CK_CurrentParameter: {
39 char *New = new char [Text.size() + 1];
40 std::memcpy(New, Text.data(), Text.size());
41 New[Text.size()] = '\0';
42 this->Text = New;
43 break;
44 }
45
46 case CK_Optional:
47 llvm::llvm_unreachable("Optional strings cannot be created from text");
48 break;
49
50 case CK_LeftParen:
51 this->Text = "(";
52 break;
53
54 case CK_RightParen:
55 this->Text = ")";
56 break;
57
58 case CK_LeftBracket:
59 this->Text = "[";
60 break;
61
62 case CK_RightBracket:
63 this->Text = "]";
64 break;
65
66 case CK_LeftBrace:
67 this->Text = "{";
68 break;
69
70 case CK_RightBrace:
71 this->Text = "}";
72 break;
73
74 case CK_LeftAngle:
75 this->Text = "<";
76 break;
77
78 case CK_RightAngle:
79 this->Text = ">";
80 break;
81
82 case CK_Comma:
83 this->Text = ", ";
84 break;
85 }
Douglas Gregor0563c262009-09-22 23:15:58 +000086}
87
88CodeCompletionString::Chunk
89CodeCompletionString::Chunk::CreateText(const char *Text) {
90 return Chunk(CK_Text, Text);
Douglas Gregore6e03612009-09-18 22:15:54 +000091}
92
93CodeCompletionString::Chunk
94CodeCompletionString::Chunk::CreateOptional(
95 std::auto_ptr<CodeCompletionString> Optional) {
96 Chunk Result;
97 Result.Kind = CK_Optional;
98 Result.Optional = Optional.release();
99 return Result;
100}
101
102CodeCompletionString::Chunk
103CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) {
Douglas Gregor0563c262009-09-22 23:15:58 +0000104 return Chunk(CK_Placeholder, Placeholder);
105}
106
107CodeCompletionString::Chunk
108CodeCompletionString::Chunk::CreateInformative(const char *Informative) {
109 return Chunk(CK_Informative, Informative);
Douglas Gregore6e03612009-09-18 22:15:54 +0000110}
111
Douglas Gregor0c8296d2009-11-07 00:00:49 +0000112CodeCompletionString::Chunk
113CodeCompletionString::Chunk::CreateCurrentParameter(
114 const char *CurrentParameter) {
115 return Chunk(CK_CurrentParameter, CurrentParameter);
116}
117
118
Douglas Gregore6e03612009-09-18 22:15:54 +0000119void
120CodeCompletionString::Chunk::Destroy() {
121 switch (Kind) {
Douglas Gregor0563c262009-09-22 23:15:58 +0000122 case CK_Optional:
123 delete Optional;
124 break;
125
Douglas Gregor0c8296d2009-11-07 00:00:49 +0000126 case CK_TypedText:
Douglas Gregor0563c262009-09-22 23:15:58 +0000127 case CK_Text:
128 case CK_Placeholder:
129 case CK_Informative:
Douglas Gregor0c8296d2009-11-07 00:00:49 +0000130 case CK_CurrentParameter:
131 delete [] Text;
132 break;
133
134 case CK_LeftParen:
135 case CK_RightParen:
136 case CK_LeftBracket:
137 case CK_RightBracket:
138 case CK_LeftBrace:
139 case CK_RightBrace:
140 case CK_LeftAngle:
141 case CK_RightAngle:
142 case CK_Comma:
Douglas Gregor0563c262009-09-22 23:15:58 +0000143 break;
Douglas Gregore6e03612009-09-18 22:15:54 +0000144 }
145}
146
147CodeCompletionString::~CodeCompletionString() {
148 std::for_each(Chunks.begin(), Chunks.end(),
149 std::mem_fun_ref(&Chunk::Destroy));
150}
151
152std::string CodeCompletionString::getAsString() const {
153 std::string Result;
154 llvm::raw_string_ostream OS(Result);
155
156 for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
157 switch (C->Kind) {
Douglas Gregore6e03612009-09-18 22:15:54 +0000158 case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break;
Douglas Gregor0563c262009-09-22 23:15:58 +0000159 case CK_Placeholder: OS << "<#" << C->Text << "#>"; break;
160 case CK_Informative: OS << "[#" << C->Text << "#]"; break;
Douglas Gregor0c8296d2009-11-07 00:00:49 +0000161 case CK_CurrentParameter: OS << "<#" << C->Text << "#>"; break;
162 default: OS << C->Text; break;
Douglas Gregore6e03612009-09-18 22:15:54 +0000163 }
164 }
Douglas Gregore2b7eea2009-09-29 15:13:39 +0000165 OS.flush();
Douglas Gregore6e03612009-09-18 22:15:54 +0000166 return Result;
167}
168
Douglas Gregor0c8296d2009-11-07 00:00:49 +0000169
170namespace {
171 // Escape a string for XML-like formatting.
172 struct EscapedString {
173 EscapedString(llvm::StringRef Str) : Str(Str) { }
174
175 llvm::StringRef Str;
176 };
177
178 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, EscapedString EStr) {
179 llvm::StringRef Str = EStr.Str;
180 while (!Str.empty()) {
181 // Find the next escaped character.
182 llvm::StringRef::size_type Pos = Str.find_first_of("<>&\"'");
183
184 // Print everything before that escaped character.
185 OS << Str.substr(0, Pos);
186
187 // If we didn't find any escaped characters, we're done.
188 if (Pos == llvm::StringRef::npos)
189 break;
190
191 // Print the appropriate escape sequence.
192 switch (Str[Pos]) {
193 case '<': OS << "&lt;"; break;
194 case '>': OS << "&gt;"; break;
195 case '&': OS << "&amp;"; break;
196 case '"': OS << "&quot;"; break;
197 case '\'': OS << "&apos;"; break;
198 }
199
200 // Remove everything up to and including that escaped character.
201 Str = Str.substr(Pos + 1);
202 }
203
204 return OS;
205 }
206
207 /// \brief Remove XML-like escaping from a string.
208 std::string UnescapeString(llvm::StringRef Str) {
209 using llvm::StringRef;
210
211 std::string Result;
212 llvm::raw_string_ostream OS(Result);
213
214 while (!Str.empty()) {
215 StringRef::size_type Amp = Str.find('&');
216 OS << Str.substr(0, Amp);
217
218 if (Amp == StringRef::npos)
219 break;
220
221 StringRef::size_type Semi = Str.substr(Amp).find(';');
222 if (Semi == StringRef::npos) {
223 // Malformed input; do the best we can.
224 OS << '&';
225 Str = Str.substr(Amp + 1);
226 continue;
227 }
228
229 char Unescaped = llvm::StringSwitch<char>(Str.substr(Amp + 1, Semi - 1))
230 .Case("lt", '<')
231 .Case("gt", '>')
232 .Case("amp", '&')
233 .Case("quot", '"')
234 .Case("apos", '\'')
235 .Default('\0');
236
237 if (Unescaped)
238 OS << Unescaped;
239 else
240 OS << Str.substr(Amp, Semi + 1);
241 Str = Str.substr(Amp + Semi + 1);
242 }
243
244 return OS.str();
245 }
246}
247
248void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const {
249 for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
250 switch (C->Kind) {
251 case CK_TypedText:
252 OS << "<typed-text>" << EscapedString(C->Text) << "</>";
253 break;
254 case CK_Text:
255 OS << "<text>" << EscapedString(C->Text) << "</>";
256 break;
257 case CK_Optional:
258 OS << "<optional>";
259 C->Optional->Serialize(OS);
260 OS << "</>";
261 break;
262 case CK_Placeholder:
263 OS << "<placeholder>" << EscapedString(C->Text) << "</>";
264 break;
265 case CK_Informative:
266 OS << "<informative>" << EscapedString(C->Text) << "</>";
267 break;
268 case CK_CurrentParameter:
269 OS << "<current-parameter>" << EscapedString(C->Text) << "</>";
270 break;
271 case CK_LeftParen:
272 OS << "<lparen/>";
273 break;
274 case CK_RightParen:
275 OS << "<rparen/>";
276 break;
277 case CK_LeftBracket:
278 OS << "<lbracket/>";
279 break;
280 case CK_RightBracket:
281 OS << "<rbracket/>";
282 break;
283 case CK_LeftBrace:
284 OS << "<lbrace/>";
285 break;
286 case CK_RightBrace:
287 OS << "<rbrace/>";
288 break;
289 case CK_LeftAngle:
290 OS << "<langle/>";
291 break;
292 case CK_RightAngle:
293 OS << "<rangle/>";
294 break;
295 case CK_Comma:
296 OS << "<comma/>";
297 break;
298 }
299 }
300}
301
302/// \brief Parse the next XML-ish tag of the form <blah>.
303///
304/// \param Str the string in which we're looking for the next tag.
305///
306/// \param TagPos if successful, will be set to the start of the tag we found.
307///
308/// \param Standalone will indicate whether this is a "standalone" tag that
309/// has no associated data, e.g., <comma/>.
310///
311/// \param Terminator will indicate whether this is a terminating tag (that is
312/// or starts with '/').
313///
314/// \returns the tag itself, without the angle brackets.
315static llvm::StringRef ParseNextTag(llvm::StringRef Str,
316 llvm::StringRef::size_type &StartTag,
317 llvm::StringRef::size_type &AfterTag,
318 bool &Standalone, bool &Terminator) {
319 using llvm::StringRef;
320
321 Standalone = false;
322 Terminator = false;
323 AfterTag = StringRef::npos;
324
325 // Find the starting '<'.
326 StartTag = Str.find('<');
327 if (StartTag == StringRef::npos)
328 return llvm::StringRef();
329
330 // Find the corresponding '>'.
331 llvm::StringRef::size_type EndTag = Str.substr(StartTag).find('>');
332 if (EndTag == StringRef::npos)
333 return llvm::StringRef();
334 AfterTag = StartTag + EndTag + 1;
335
336 // Determine whether this is a terminating tag.
337 if (Str[StartTag + 1] == '/') {
338 Terminator = true;
339 Str = Str.substr(1);
340 --EndTag;
341 }
342
343 // Determine whether this is a standalone tag.
344 if (!Terminator && Str[StartTag + EndTag - 1] == '/') {
345 Standalone = true;
346 if (EndTag > 1)
347 --EndTag;
348 }
349
350 return Str.substr(StartTag + 1, EndTag - 1);
351}
352
353CodeCompletionString *CodeCompletionString::Deserialize(llvm::StringRef &Str) {
354 using llvm::StringRef;
355
356 CodeCompletionString *Result = new CodeCompletionString;
357
358 do {
359 // Parse the next tag.
360 StringRef::size_type StartTag, AfterTag;
361 bool Standalone, Terminator;
362 StringRef Tag = ParseNextTag(Str, StartTag, AfterTag, Standalone,
363 Terminator);
364
365 if (StartTag == StringRef::npos)
366 break;
367
368 // Figure out what kind of chunk we have.
369 const unsigned UnknownKind = 10000;
370 unsigned Kind = llvm::StringSwitch<unsigned>(Tag)
371 .Case("typed-text", CK_TypedText)
372 .Case("text", CK_Text)
373 .Case("optional", CK_Optional)
374 .Case("placeholder", CK_Placeholder)
375 .Case("informative", CK_Informative)
376 .Case("current-parameter", CK_CurrentParameter)
377 .Case("lparen", CK_LeftParen)
378 .Case("rparen", CK_RightParen)
379 .Case("lbracket", CK_LeftBracket)
380 .Case("rbracket", CK_RightBracket)
381 .Case("lbrace", CK_LeftBrace)
382 .Case("rbrace", CK_RightBrace)
383 .Case("langle", CK_LeftAngle)
384 .Case("rangle", CK_RightAngle)
385 .Case("comma", CK_Comma)
386 .Default(UnknownKind);
387
388 // If we've hit a terminator tag, we're done.
389 if (Terminator)
390 break;
391
392 // Consume the tag.
393 Str = Str.substr(AfterTag);
394
395 // Handle standalone tags now, since they don't need to be matched to
396 // anything.
397 if (Standalone) {
398 // Ignore anything we don't know about.
399 if (Kind == UnknownKind)
400 continue;
401
402 switch ((ChunkKind)Kind) {
403 case CK_TypedText:
404 case CK_Text:
405 case CK_Optional:
406 case CK_Placeholder:
407 case CK_Informative:
408 case CK_CurrentParameter:
409 // There is no point in creating empty chunks of these kinds.
410 break;
411
412 case CK_LeftParen:
413 case CK_RightParen:
414 case CK_LeftBracket:
415 case CK_RightBracket:
416 case CK_LeftBrace:
417 case CK_RightBrace:
418 case CK_LeftAngle:
419 case CK_RightAngle:
420 case CK_Comma:
421 Result->AddChunk(Chunk((ChunkKind)Kind));
422 break;
423 }
424
425 continue;
426 }
427
428 if (Kind == CK_Optional) {
429 // Deserialize the optional code-completion string.
430 std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str));
431 Result->AddOptionalChunk(Optional);
432 }
433
434 StringRef EndTag = ParseNextTag(Str, StartTag, AfterTag, Standalone,
435 Terminator);
436 if (StartTag == StringRef::npos || !Terminator || Standalone)
437 break; // Parsing failed; just give up.
438
439 if (EndTag.empty() || Tag == EndTag) {
440 // Found the matching end tag. Add this chunk based on the text
441 // between the tags, then consume that input.
442 StringRef Text = Str.substr(0, StartTag);
443 switch ((ChunkKind)Kind) {
444 case CK_TypedText:
445 case CK_Text:
446 case CK_Placeholder:
447 case CK_Informative:
448 case CK_CurrentParameter:
449 case CK_LeftParen:
450 case CK_RightParen:
451 case CK_LeftBracket:
452 case CK_RightBracket:
453 case CK_LeftBrace:
454 case CK_RightBrace:
455 case CK_LeftAngle:
456 case CK_RightAngle:
457 case CK_Comma:
458 Result->AddChunk(Chunk((ChunkKind)Kind, UnescapeString(Text)));
459 break;
460
461 case CK_Optional:
462 // We've already added the optional chunk.
463 break;
464 }
465 }
466
467 // Remove this tag.
468 Str = Str.substr(AfterTag);
469 } while (!Str.empty());
470
471 return Result;
472}
473
Douglas Gregore6e03612009-09-18 22:15:54 +0000474//===----------------------------------------------------------------------===//
Douglas Gregor05944382009-09-23 00:16:58 +0000475// Code completion overload candidate implementation
476//===----------------------------------------------------------------------===//
477FunctionDecl *
478CodeCompleteConsumer::OverloadCandidate::getFunction() const {
479 if (getKind() == CK_Function)
480 return Function;
481 else if (getKind() == CK_FunctionTemplate)
482 return FunctionTemplate->getTemplatedDecl();
483 else
484 return 0;
485}
486
487const FunctionType *
488CodeCompleteConsumer::OverloadCandidate::getFunctionType() const {
489 switch (Kind) {
490 case CK_Function:
491 return Function->getType()->getAs<FunctionType>();
492
493 case CK_FunctionTemplate:
494 return FunctionTemplate->getTemplatedDecl()->getType()
495 ->getAs<FunctionType>();
496
497 case CK_FunctionType:
498 return Type;
499 }
500
501 return 0;
502}
503
504//===----------------------------------------------------------------------===//
Douglas Gregore6e03612009-09-18 22:15:54 +0000505// Code completion consumer implementation
506//===----------------------------------------------------------------------===//
507
Douglas Gregor86d9a522009-09-21 16:56:56 +0000508CodeCompleteConsumer::~CodeCompleteConsumer() { }
Douglas Gregore6e03612009-09-18 22:15:54 +0000509
Douglas Gregor81b747b2009-09-17 21:32:03 +0000510void
511PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results,
512 unsigned NumResults) {
Douglas Gregor81b747b2009-09-17 21:32:03 +0000513 // Print the results.
514 for (unsigned I = 0; I != NumResults; ++I) {
Douglas Gregorf52cede2009-10-09 22:16:47 +0000515 OS << "COMPLETION: ";
Douglas Gregor81b747b2009-09-17 21:32:03 +0000516 switch (Results[I].Kind) {
517 case Result::RK_Declaration:
518 OS << Results[I].Declaration->getNameAsString() << " : "
519 << Results[I].Rank;
520 if (Results[I].Hidden)
521 OS << " (Hidden)";
Douglas Gregor86d9a522009-09-21 16:56:56 +0000522 if (CodeCompletionString *CCS
523 = Results[I].CreateCodeCompletionString(SemaRef)) {
Douglas Gregore6e03612009-09-18 22:15:54 +0000524 OS << " : " << CCS->getAsString();
525 delete CCS;
526 }
527
Douglas Gregor81b747b2009-09-17 21:32:03 +0000528 OS << '\n';
529 break;
530
531 case Result::RK_Keyword:
532 OS << Results[I].Keyword << " : " << Results[I].Rank << '\n';
533 break;
Douglas Gregor3f7c7f42009-10-30 16:50:04 +0000534
535 case Result::RK_Macro: {
536 OS << Results[I].Macro->getName() << " : " << Results[I].Rank;
537 if (CodeCompletionString *CCS
538 = Results[I].CreateCodeCompletionString(SemaRef)) {
539 OS << " : " << CCS->getAsString();
540 delete CCS;
541 }
542 OS << '\n';
543 break;
544 }
Douglas Gregor81b747b2009-09-17 21:32:03 +0000545 }
546 }
547
548 // Once we've printed the code-completion results, suppress remaining
549 // diagnostics.
550 // FIXME: Move this somewhere else!
Douglas Gregor86d9a522009-09-21 16:56:56 +0000551 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
Douglas Gregor81b747b2009-09-17 21:32:03 +0000552}
Douglas Gregor05944382009-09-23 00:16:58 +0000553
554void
555PrintingCodeCompleteConsumer::ProcessOverloadCandidates(unsigned CurrentArg,
556 OverloadCandidate *Candidates,
557 unsigned NumCandidates) {
558 for (unsigned I = 0; I != NumCandidates; ++I) {
Douglas Gregor86d802e2009-09-23 00:34:09 +0000559 if (CodeCompletionString *CCS
560 = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) {
Douglas Gregorf52cede2009-10-09 22:16:47 +0000561 OS << "OVERLOAD: " << CCS->getAsString() << "\n";
Douglas Gregor86d802e2009-09-23 00:34:09 +0000562 delete CCS;
Douglas Gregor05944382009-09-23 00:16:58 +0000563 }
564 }
565
566 // Once we've printed the code-completion results, suppress remaining
567 // diagnostics.
568 // FIXME: Move this somewhere else!
569 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
570}
Douglas Gregor0c8296d2009-11-07 00:00:49 +0000571
572void
573CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results,
574 unsigned NumResults) {
575 // Print the results.
576 for (unsigned I = 0; I != NumResults; ++I) {
577 OS << "COMPLETION:" << Results[I].Rank << ":";
578 switch (Results[I].Kind) {
579 case Result::RK_Declaration:
580 if (RecordDecl *Record = dyn_cast<RecordDecl>(Results[I].Declaration)) {
581 if (Record->isStruct())
582 OS << "Struct:";
583 else if (Record->isUnion())
584 OS << "Union:";
585 else
586 OS << "Class:";
587 } else if (ObjCMethodDecl *Method
588 = dyn_cast<ObjCMethodDecl>(Results[I].Declaration)) {
589 if (Method->isInstanceMethod())
590 OS << "ObjCInstanceMethod:";
591 else
592 OS << "ObjCClassMethod:";
593 } else {
594 OS << Results[I].Declaration->getDeclKindName() << ":";
595 }
596 if (CodeCompletionString *CCS
597 = Results[I].CreateCodeCompletionString(SemaRef)) {
598 CCS->Serialize(OS);
599 delete CCS;
600 } else {
601 OS << "<typed-text>"
602 << Results[I].Declaration->getNameAsString()
603 << "</>";
604 }
605
606 OS << '\n';
607 break;
608
609 case Result::RK_Keyword:
610 OS << "Keyword:<typed-text>" << Results[I].Keyword << "</>\n";
611 break;
612
613 case Result::RK_Macro: {
614 OS << "Macro:";
615 if (CodeCompletionString *CCS
616 = Results[I].CreateCodeCompletionString(SemaRef)) {
617 CCS->Serialize(OS);
618 delete CCS;
619 } else {
620 OS << "<typed-text>" << Results[I].Macro->getName() << "</>";
621 }
622 OS << '\n';
623 break;
624 }
625 }
626 }
627
628 // Once we've printed the code-completion results, suppress remaining
629 // diagnostics.
630 // FIXME: Move this somewhere else!
631 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
632}
633
634void
635CIndexCodeCompleteConsumer::ProcessOverloadCandidates(unsigned CurrentArg,
636 OverloadCandidate *Candidates,
637 unsigned NumCandidates) {
638 for (unsigned I = 0; I != NumCandidates; ++I) {
639 if (CodeCompletionString *CCS
640 = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) {
641 OS << "OVERLOAD:";
642 CCS->Serialize(OS);
643 OS << '\n';
644 delete CCS;
645 }
646 }
647
648 // Once we've printed the code-completion results, suppress remaining
649 // diagnostics.
650 // FIXME: Move this somewhere else!
651 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
652}