CodeCompleteConsumer.cpp revision 200583
1//===--- CodeCompleteConsumer.cpp - Code Completion Interface ---*- C++ -*-===//
2//
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"
14#include "clang/AST/DeclCXX.h"
15#include "clang/Parse/Scope.h"
16#include "clang/Lex/Preprocessor.h"
17#include "clang-c/Index.h"
18#include "Sema.h"
19#include "llvm/ADT/STLExtras.h"
20#include "llvm/ADT/StringSwitch.h"
21#include "llvm/Support/raw_ostream.h"
22#include <algorithm>
23#include <cstring>
24#include <functional>
25
26using namespace clang;
27using llvm::StringRef;
28
29//===----------------------------------------------------------------------===//
30// Code completion string implementation
31//===----------------------------------------------------------------------===//
32CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text)
33  : Kind(Kind), Text("")
34{
35  switch (Kind) {
36  case CK_TypedText:
37  case CK_Text:
38  case CK_Placeholder:
39  case CK_Informative:
40  case CK_CurrentParameter: {
41    char *New = new char [Text.size() + 1];
42    std::memcpy(New, Text.data(), Text.size());
43    New[Text.size()] = '\0';
44    this->Text = New;
45    break;
46  }
47
48  case CK_Optional:
49    llvm_unreachable("Optional strings cannot be created from text");
50    break;
51
52  case CK_LeftParen:
53    this->Text = "(";
54    break;
55
56  case CK_RightParen:
57    this->Text = ")";
58    break;
59
60  case CK_LeftBracket:
61    this->Text = "[";
62    break;
63
64  case CK_RightBracket:
65    this->Text = "]";
66    break;
67
68  case CK_LeftBrace:
69    this->Text = "{";
70    break;
71
72  case CK_RightBrace:
73    this->Text = "}";
74    break;
75
76  case CK_LeftAngle:
77    this->Text = "<";
78    break;
79
80  case CK_RightAngle:
81    this->Text = ">";
82    break;
83
84  case CK_Comma:
85    this->Text = ", ";
86    break;
87  }
88}
89
90CodeCompletionString::Chunk
91CodeCompletionString::Chunk::CreateText(StringRef Text) {
92  return Chunk(CK_Text, Text);
93}
94
95CodeCompletionString::Chunk
96CodeCompletionString::Chunk::CreateOptional(
97                                 std::auto_ptr<CodeCompletionString> Optional) {
98  Chunk Result;
99  Result.Kind = CK_Optional;
100  Result.Optional = Optional.release();
101  return Result;
102}
103
104CodeCompletionString::Chunk
105CodeCompletionString::Chunk::CreatePlaceholder(StringRef Placeholder) {
106  return Chunk(CK_Placeholder, Placeholder);
107}
108
109CodeCompletionString::Chunk
110CodeCompletionString::Chunk::CreateInformative(StringRef Informative) {
111  return Chunk(CK_Informative, Informative);
112}
113
114CodeCompletionString::Chunk
115CodeCompletionString::Chunk::CreateCurrentParameter(
116                                                StringRef CurrentParameter) {
117  return Chunk(CK_CurrentParameter, CurrentParameter);
118}
119
120CodeCompletionString::Chunk CodeCompletionString::Chunk::Clone() const {
121  switch (Kind) {
122  case CK_TypedText:
123  case CK_Text:
124  case CK_Placeholder:
125  case CK_Informative:
126  case CK_CurrentParameter:
127  case CK_LeftParen:
128  case CK_RightParen:
129  case CK_LeftBracket:
130  case CK_RightBracket:
131  case CK_LeftBrace:
132  case CK_RightBrace:
133  case CK_LeftAngle:
134  case CK_RightAngle:
135  case CK_Comma:
136    return Chunk(Kind, Text);
137
138  case CK_Optional: {
139    std::auto_ptr<CodeCompletionString> Opt(Optional->Clone());
140    return CreateOptional(Opt);
141  }
142  }
143
144  // Silence GCC warning.
145  return Chunk();
146}
147
148void
149CodeCompletionString::Chunk::Destroy() {
150  switch (Kind) {
151  case CK_Optional:
152    delete Optional;
153    break;
154
155  case CK_TypedText:
156  case CK_Text:
157  case CK_Placeholder:
158  case CK_Informative:
159  case CK_CurrentParameter:
160    delete [] Text;
161    break;
162
163  case CK_LeftParen:
164  case CK_RightParen:
165  case CK_LeftBracket:
166  case CK_RightBracket:
167  case CK_LeftBrace:
168  case CK_RightBrace:
169  case CK_LeftAngle:
170  case CK_RightAngle:
171  case CK_Comma:
172    break;
173  }
174}
175
176CodeCompletionString::~CodeCompletionString() {
177  std::for_each(Chunks.begin(), Chunks.end(),
178                std::mem_fun_ref(&Chunk::Destroy));
179}
180
181std::string CodeCompletionString::getAsString() const {
182  std::string Result;
183  llvm::raw_string_ostream OS(Result);
184
185  for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
186    switch (C->Kind) {
187    case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break;
188    case CK_Placeholder: OS << "<#" << C->Text << "#>"; break;
189    case CK_Informative: OS << "[#" << C->Text << "#]"; break;
190    case CK_CurrentParameter: OS << "<#" << C->Text << "#>"; break;
191    default: OS << C->Text; break;
192    }
193  }
194  OS.flush();
195  return Result;
196}
197
198const char *CodeCompletionString::getTypedText() const {
199  for (iterator C = begin(), CEnd = end(); C != CEnd; ++C)
200    if (C->Kind == CK_TypedText)
201      return C->Text;
202
203  return 0;
204}
205
206CodeCompletionString *CodeCompletionString::Clone() const {
207  CodeCompletionString *Result = new CodeCompletionString;
208  for (iterator C = begin(), CEnd = end(); C != CEnd; ++C)
209    Result->AddChunk(C->Clone());
210  return Result;
211}
212
213static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) {
214  OS.write((const char *)&Value, sizeof(unsigned));
215}
216
217static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
218                         unsigned &Value) {
219  if (Memory + sizeof(unsigned) > MemoryEnd)
220    return true;
221
222  memmove(&Value, Memory, sizeof(unsigned));
223  Memory += sizeof(unsigned);
224  return false;
225}
226
227void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const {
228  // Write the number of chunks.
229  WriteUnsigned(OS, size());
230
231  for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
232    WriteUnsigned(OS, C->Kind);
233
234    switch (C->Kind) {
235    case CK_TypedText:
236    case CK_Text:
237    case CK_Placeholder:
238    case CK_Informative:
239    case CK_CurrentParameter: {
240      const char *Text = C->Text;
241      unsigned StrLen = strlen(Text);
242      WriteUnsigned(OS, StrLen);
243      OS.write(Text, StrLen);
244      break;
245    }
246
247    case CK_Optional:
248      C->Optional->Serialize(OS);
249      break;
250
251    case CK_LeftParen:
252    case CK_RightParen:
253    case CK_LeftBracket:
254    case CK_RightBracket:
255    case CK_LeftBrace:
256    case CK_RightBrace:
257    case CK_LeftAngle:
258    case CK_RightAngle:
259    case CK_Comma:
260      break;
261    }
262  }
263}
264
265CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str,
266                                                        const char *StrEnd) {
267  if (Str == StrEnd || *Str == 0)
268    return 0;
269
270  CodeCompletionString *Result = new CodeCompletionString;
271  unsigned NumBlocks;
272  if (ReadUnsigned(Str, StrEnd, NumBlocks))
273    return Result;
274
275  for (unsigned I = 0; I != NumBlocks; ++I) {
276    if (Str + 1 >= StrEnd)
277      break;
278
279    // Parse the next kind.
280    unsigned KindValue;
281    if (ReadUnsigned(Str, StrEnd, KindValue))
282      return Result;
283
284    switch (ChunkKind Kind = (ChunkKind)KindValue) {
285    case CK_TypedText:
286    case CK_Text:
287    case CK_Placeholder:
288    case CK_Informative:
289    case CK_CurrentParameter: {
290      unsigned StrLen;
291      if (ReadUnsigned(Str, StrEnd, StrLen) || (Str + StrLen > StrEnd))
292        return Result;
293
294      Result->AddChunk(Chunk(Kind, StringRef(Str, StrLen)));
295      Str += StrLen;
296      break;
297    }
298
299    case CK_Optional: {
300      std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str, StrEnd));
301      Result->AddOptionalChunk(Optional);
302      break;
303    }
304
305    case CK_LeftParen:
306    case CK_RightParen:
307    case CK_LeftBracket:
308    case CK_RightBracket:
309    case CK_LeftBrace:
310    case CK_RightBrace:
311    case CK_LeftAngle:
312    case CK_RightAngle:
313    case CK_Comma:
314      Result->AddChunk(Chunk(Kind));
315      break;
316    }
317  };
318
319  return Result;
320}
321
322void CodeCompleteConsumer::Result::Destroy() {
323  if (Kind == RK_Pattern) {
324    delete Pattern;
325    Pattern = 0;
326  }
327}
328
329//===----------------------------------------------------------------------===//
330// Code completion overload candidate implementation
331//===----------------------------------------------------------------------===//
332FunctionDecl *
333CodeCompleteConsumer::OverloadCandidate::getFunction() const {
334  if (getKind() == CK_Function)
335    return Function;
336  else if (getKind() == CK_FunctionTemplate)
337    return FunctionTemplate->getTemplatedDecl();
338  else
339    return 0;
340}
341
342const FunctionType *
343CodeCompleteConsumer::OverloadCandidate::getFunctionType() const {
344  switch (Kind) {
345  case CK_Function:
346    return Function->getType()->getAs<FunctionType>();
347
348  case CK_FunctionTemplate:
349    return FunctionTemplate->getTemplatedDecl()->getType()
350             ->getAs<FunctionType>();
351
352  case CK_FunctionType:
353    return Type;
354  }
355
356  return 0;
357}
358
359//===----------------------------------------------------------------------===//
360// Code completion consumer implementation
361//===----------------------------------------------------------------------===//
362
363CodeCompleteConsumer::~CodeCompleteConsumer() { }
364
365void
366PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
367                                                         Result *Results,
368                                                         unsigned NumResults) {
369  // Print the results.
370  for (unsigned I = 0; I != NumResults; ++I) {
371    OS << "COMPLETION: ";
372    switch (Results[I].Kind) {
373    case Result::RK_Declaration:
374      OS << Results[I].Declaration->getNameAsString() << " : "
375         << Results[I].Rank;
376      if (Results[I].Hidden)
377        OS << " (Hidden)";
378      if (CodeCompletionString *CCS
379            = Results[I].CreateCodeCompletionString(SemaRef)) {
380        OS << " : " << CCS->getAsString();
381        delete CCS;
382      }
383
384      OS << '\n';
385      break;
386
387    case Result::RK_Keyword:
388      OS << Results[I].Keyword << " : " << Results[I].Rank << '\n';
389      break;
390
391    case Result::RK_Macro: {
392      OS << Results[I].Macro->getName() << " : " << Results[I].Rank;
393      if (CodeCompletionString *CCS
394          = Results[I].CreateCodeCompletionString(SemaRef)) {
395        OS << " : " << CCS->getAsString();
396        delete CCS;
397      }
398      OS << '\n';
399      break;
400    }
401
402    case Result::RK_Pattern: {
403      OS << "Pattern : " << Results[I].Rank << " : "
404         << Results[I].Pattern->getAsString() << '\n';
405      break;
406    }
407    }
408  }
409
410  // Once we've printed the code-completion results, suppress remaining
411  // diagnostics.
412  // FIXME: Move this somewhere else!
413  SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
414}
415
416void
417PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
418                                                        unsigned CurrentArg,
419                                              OverloadCandidate *Candidates,
420                                                     unsigned NumCandidates) {
421  for (unsigned I = 0; I != NumCandidates; ++I) {
422    if (CodeCompletionString *CCS
423          = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) {
424      OS << "OVERLOAD: " << CCS->getAsString() << "\n";
425      delete CCS;
426    }
427  }
428
429  // Once we've printed the code-completion results, suppress remaining
430  // diagnostics.
431  // FIXME: Move this somewhere else!
432  SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
433}
434
435void
436CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
437                                                       Result *Results,
438                                                       unsigned NumResults) {
439  // Print the results.
440  for (unsigned I = 0; I != NumResults; ++I) {
441    CXCursorKind Kind = CXCursor_NotImplemented;
442
443    switch (Results[I].Kind) {
444    case Result::RK_Declaration:
445      switch (Results[I].Declaration->getKind()) {
446      case Decl::Record:
447      case Decl::CXXRecord:
448      case Decl::ClassTemplateSpecialization: {
449        RecordDecl *Record = cast<RecordDecl>(Results[I].Declaration);
450        if (Record->isStruct())
451          Kind = CXCursor_StructDecl;
452        else if (Record->isUnion())
453          Kind = CXCursor_UnionDecl;
454        else
455          Kind = CXCursor_ClassDecl;
456        break;
457      }
458
459      case Decl::ObjCMethod: {
460        ObjCMethodDecl *Method = cast<ObjCMethodDecl>(Results[I].Declaration);
461        if (Method->isInstanceMethod())
462            Kind = CXCursor_ObjCInstanceMethodDecl;
463        else
464          Kind = CXCursor_ObjCClassMethodDecl;
465        break;
466      }
467
468      case Decl::Typedef:
469        Kind = CXCursor_TypedefDecl;
470        break;
471
472      case Decl::Enum:
473        Kind = CXCursor_EnumDecl;
474        break;
475
476      case Decl::Field:
477        Kind = CXCursor_FieldDecl;
478        break;
479
480      case Decl::EnumConstant:
481        Kind = CXCursor_EnumConstantDecl;
482        break;
483
484      case Decl::Function:
485      case Decl::CXXMethod:
486      case Decl::CXXConstructor:
487      case Decl::CXXDestructor:
488      case Decl::CXXConversion:
489        Kind = CXCursor_FunctionDecl;
490        break;
491
492      case Decl::Var:
493        Kind = CXCursor_VarDecl;
494        break;
495
496      case Decl::ParmVar:
497        Kind = CXCursor_ParmDecl;
498        break;
499
500      case Decl::ObjCInterface:
501        Kind = CXCursor_ObjCInterfaceDecl;
502        break;
503
504      case Decl::ObjCCategory:
505        Kind = CXCursor_ObjCCategoryDecl;
506        break;
507
508      case Decl::ObjCProtocol:
509        Kind = CXCursor_ObjCProtocolDecl;
510        break;
511
512      case Decl::ObjCProperty:
513        Kind = CXCursor_ObjCPropertyDecl;
514        break;
515
516      case Decl::ObjCIvar:
517        Kind = CXCursor_ObjCIvarDecl;
518        break;
519
520      case Decl::ObjCImplementation:
521        Kind = CXCursor_ObjCClassDefn;
522        break;
523
524      case Decl::ObjCCategoryImpl:
525        Kind = CXCursor_ObjCCategoryDefn;
526        break;
527
528      default:
529        break;
530      }
531      break;
532
533    case Result::RK_Keyword:
534    case Result::RK_Macro:
535    case Result::RK_Pattern:
536      Kind = CXCursor_NotImplemented;
537      break;
538    }
539
540    WriteUnsigned(OS, Kind);
541    CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef);
542    assert(CCS && "No code-completion string?");
543    CCS->Serialize(OS);
544    delete CCS;
545  }
546
547  // Once we've printed the code-completion results, suppress remaining
548  // diagnostics.
549  // FIXME: Move this somewhere else!
550  SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
551}
552
553void
554CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
555                                                      unsigned CurrentArg,
556                                                OverloadCandidate *Candidates,
557                                                       unsigned NumCandidates) {
558  for (unsigned I = 0; I != NumCandidates; ++I) {
559    WriteUnsigned(OS, CXCursor_NotImplemented);
560    CodeCompletionString *CCS
561      = Candidates[I].CreateSignatureString(CurrentArg, SemaRef);
562    assert(CCS && "No code-completion string?");
563    CCS->Serialize(OS);
564    delete CCS;
565  }
566
567  // Once we've printed the code-completion results, suppress remaining
568  // diagnostics.
569  // FIXME: Move this somewhere else!
570  SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
571}
572