Deleted Added
full compact
CodeCompleteConsumer.cpp (198893) CodeCompleteConsumer.cpp (199482)
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 "Sema.h"
18#include "llvm/ADT/STLExtras.h"
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 "Sema.h"
18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/StringSwitch.h"
19#include "llvm/Support/Compiler.h"
20#include "llvm/Support/raw_ostream.h"
21#include <algorithm>
22#include <cstring>
23#include <functional>
20#include "llvm/Support/Compiler.h"
21#include "llvm/Support/raw_ostream.h"
22#include <algorithm>
23#include <cstring>
24#include <functional>
25
24using namespace clang;
26using namespace clang;
27using llvm::StringRef;
25
26//===----------------------------------------------------------------------===//
27// Code completion string implementation
28//===----------------------------------------------------------------------===//
28
29//===----------------------------------------------------------------------===//
30// Code completion string implementation
31//===----------------------------------------------------------------------===//
29CodeCompletionString::Chunk::Chunk(ChunkKind Kind, const char *Text)
30 : Kind(Kind), Text(0)
32CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text)
33 : Kind(Kind), Text("")
31{
34{
32 assert((Kind == CK_Text || Kind == CK_Placeholder || Kind == CK_Informative)
33 && "Invalid text chunk kind");
34 char *New = new char [std::strlen(Text) + 1];
35 std::strcpy(New, Text);
36 this->Text = New;
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::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 }
37}
38
39CodeCompletionString::Chunk
88}
89
90CodeCompletionString::Chunk
40CodeCompletionString::Chunk::CreateText(const char *Text) {
91CodeCompletionString::Chunk::CreateText(StringRef Text) {
41 return Chunk(CK_Text, Text);
42}
43
44CodeCompletionString::Chunk
45CodeCompletionString::Chunk::CreateOptional(
46 std::auto_ptr<CodeCompletionString> Optional) {
47 Chunk Result;
48 Result.Kind = CK_Optional;
49 Result.Optional = Optional.release();
50 return Result;
51}
52
53CodeCompletionString::Chunk
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
54CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) {
105CodeCompletionString::Chunk::CreatePlaceholder(StringRef Placeholder) {
55 return Chunk(CK_Placeholder, Placeholder);
56}
57
58CodeCompletionString::Chunk
106 return Chunk(CK_Placeholder, Placeholder);
107}
108
109CodeCompletionString::Chunk
59CodeCompletionString::Chunk::CreateInformative(const char *Informative) {
110CodeCompletionString::Chunk::CreateInformative(StringRef Informative) {
60 return Chunk(CK_Informative, Informative);
61}
62
111 return Chunk(CK_Informative, Informative);
112}
113
114CodeCompletionString::Chunk
115CodeCompletionString::Chunk::CreateCurrentParameter(
116 StringRef CurrentParameter) {
117 return Chunk(CK_CurrentParameter, CurrentParameter);
118}
119
120
63void
64CodeCompletionString::Chunk::Destroy() {
65 switch (Kind) {
66 case CK_Optional:
67 delete Optional;
68 break;
69
121void
122CodeCompletionString::Chunk::Destroy() {
123 switch (Kind) {
124 case CK_Optional:
125 delete Optional;
126 break;
127
128 case CK_TypedText:
70 case CK_Text:
71 case CK_Placeholder:
72 case CK_Informative:
129 case CK_Text:
130 case CK_Placeholder:
131 case CK_Informative:
73 delete [] Text;
132 case CK_CurrentParameter:
133 delete [] Text;
74 break;
134 break;
135
136 case CK_LeftParen:
137 case CK_RightParen:
138 case CK_LeftBracket:
139 case CK_RightBracket:
140 case CK_LeftBrace:
141 case CK_RightBrace:
142 case CK_LeftAngle:
143 case CK_RightAngle:
144 case CK_Comma:
145 break;
75 }
76}
77
78CodeCompletionString::~CodeCompletionString() {
79 std::for_each(Chunks.begin(), Chunks.end(),
80 std::mem_fun_ref(&Chunk::Destroy));
81}
82
83std::string CodeCompletionString::getAsString() const {
84 std::string Result;
85 llvm::raw_string_ostream OS(Result);
86
87 for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
88 switch (C->Kind) {
146 }
147}
148
149CodeCompletionString::~CodeCompletionString() {
150 std::for_each(Chunks.begin(), Chunks.end(),
151 std::mem_fun_ref(&Chunk::Destroy));
152}
153
154std::string CodeCompletionString::getAsString() const {
155 std::string Result;
156 llvm::raw_string_ostream OS(Result);
157
158 for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
159 switch (C->Kind) {
89 case CK_Text: OS << C->Text; break;
90 case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break;
91 case CK_Placeholder: OS << "<#" << C->Text << "#>"; break;
92 case CK_Informative: OS << "[#" << C->Text << "#]"; break;
160 case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break;
161 case CK_Placeholder: OS << "<#" << C->Text << "#>"; break;
162 case CK_Informative: OS << "[#" << C->Text << "#]"; break;
163 case CK_CurrentParameter: OS << "<#" << C->Text << "#>"; break;
164 default: OS << C->Text; break;
93 }
94 }
95 OS.flush();
96 return Result;
97}
98
165 }
166 }
167 OS.flush();
168 return Result;
169}
170
171
172namespace {
173 // Escape a string for XML-like formatting.
174 struct EscapedString {
175 EscapedString(llvm::StringRef Str) : Str(Str) { }
176
177 llvm::StringRef Str;
178 };
179
180 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, EscapedString EStr) {
181 llvm::StringRef Str = EStr.Str;
182 while (!Str.empty()) {
183 // Find the next escaped character.
184 llvm::StringRef::size_type Pos = Str.find_first_of("<>&\"'");
185
186 // Print everything before that escaped character.
187 OS << Str.substr(0, Pos);
188
189 // If we didn't find any escaped characters, we're done.
190 if (Pos == llvm::StringRef::npos)
191 break;
192
193 // Print the appropriate escape sequence.
194 switch (Str[Pos]) {
195 case '<': OS << "&lt;"; break;
196 case '>': OS << "&gt;"; break;
197 case '&': OS << "&amp;"; break;
198 case '"': OS << "&quot;"; break;
199 case '\'': OS << "&apos;"; break;
200 }
201
202 // Remove everything up to and including that escaped character.
203 Str = Str.substr(Pos + 1);
204 }
205
206 return OS;
207 }
208
209 /// \brief Remove XML-like escaping from a string.
210 std::string UnescapeString(llvm::StringRef Str) {
211 using llvm::StringRef;
212
213 std::string Result;
214 llvm::raw_string_ostream OS(Result);
215
216 while (!Str.empty()) {
217 StringRef::size_type Amp = Str.find('&');
218 OS << Str.substr(0, Amp);
219
220 if (Amp == StringRef::npos)
221 break;
222
223 StringRef::size_type Semi = Str.substr(Amp).find(';');
224 if (Semi == StringRef::npos) {
225 // Malformed input; do the best we can.
226 OS << '&';
227 Str = Str.substr(Amp + 1);
228 continue;
229 }
230
231 char Unescaped = llvm::StringSwitch<char>(Str.substr(Amp + 1, Semi - 1))
232 .Case("lt", '<')
233 .Case("gt", '>')
234 .Case("amp", '&')
235 .Case("quot", '"')
236 .Case("apos", '\'')
237 .Default('\0');
238
239 if (Unescaped)
240 OS << Unescaped;
241 else
242 OS << Str.substr(Amp, Semi + 1);
243 Str = Str.substr(Amp + Semi + 1);
244 }
245
246 return OS.str();
247 }
248}
249
250void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const {
251 for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
252 switch (C->Kind) {
253 case CK_TypedText:
254 OS << "<typed-text>" << EscapedString(C->Text) << "</>";
255 break;
256 case CK_Text:
257 OS << "<text>" << EscapedString(C->Text) << "</>";
258 break;
259 case CK_Optional:
260 OS << "<optional>";
261 C->Optional->Serialize(OS);
262 OS << "</>";
263 break;
264 case CK_Placeholder:
265 OS << "<placeholder>" << EscapedString(C->Text) << "</>";
266 break;
267 case CK_Informative:
268 OS << "<informative>" << EscapedString(C->Text) << "</>";
269 break;
270 case CK_CurrentParameter:
271 OS << "<current-parameter>" << EscapedString(C->Text) << "</>";
272 break;
273 case CK_LeftParen:
274 OS << "<lparen/>";
275 break;
276 case CK_RightParen:
277 OS << "<rparen/>";
278 break;
279 case CK_LeftBracket:
280 OS << "<lbracket/>";
281 break;
282 case CK_RightBracket:
283 OS << "<rbracket/>";
284 break;
285 case CK_LeftBrace:
286 OS << "<lbrace/>";
287 break;
288 case CK_RightBrace:
289 OS << "<rbrace/>";
290 break;
291 case CK_LeftAngle:
292 OS << "<langle/>";
293 break;
294 case CK_RightAngle:
295 OS << "<rangle/>";
296 break;
297 case CK_Comma:
298 OS << "<comma/>";
299 break;
300 }
301 }
302}
303
304/// \brief Parse the next XML-ish tag of the form <blah>.
305///
306/// \param Str the string in which we're looking for the next tag.
307///
308/// \param TagPos if successful, will be set to the start of the tag we found.
309///
310/// \param Standalone will indicate whether this is a "standalone" tag that
311/// has no associated data, e.g., <comma/>.
312///
313/// \param Terminator will indicate whether this is a terminating tag (that is
314/// or starts with '/').
315///
316/// \returns the tag itself, without the angle brackets.
317static llvm::StringRef ParseNextTag(llvm::StringRef Str,
318 llvm::StringRef::size_type &StartTag,
319 llvm::StringRef::size_type &AfterTag,
320 bool &Standalone, bool &Terminator) {
321 using llvm::StringRef;
322
323 Standalone = false;
324 Terminator = false;
325 AfterTag = StringRef::npos;
326
327 // Find the starting '<'.
328 StartTag = Str.find('<');
329 if (StartTag == StringRef::npos)
330 return llvm::StringRef();
331
332 // Find the corresponding '>'.
333 llvm::StringRef::size_type EndTag = Str.substr(StartTag).find('>');
334 if (EndTag == StringRef::npos)
335 return llvm::StringRef();
336 AfterTag = StartTag + EndTag + 1;
337
338 // Determine whether this is a terminating tag.
339 if (Str[StartTag + 1] == '/') {
340 Terminator = true;
341 Str = Str.substr(1);
342 --EndTag;
343 }
344
345 // Determine whether this is a standalone tag.
346 if (!Terminator && Str[StartTag + EndTag - 1] == '/') {
347 Standalone = true;
348 if (EndTag > 1)
349 --EndTag;
350 }
351
352 return Str.substr(StartTag + 1, EndTag - 1);
353}
354
355CodeCompletionString *CodeCompletionString::Deserialize(llvm::StringRef &Str) {
356 using llvm::StringRef;
357
358 CodeCompletionString *Result = new CodeCompletionString;
359
360 do {
361 // Parse the next tag.
362 StringRef::size_type StartTag, AfterTag;
363 bool Standalone, Terminator;
364 StringRef Tag = ParseNextTag(Str, StartTag, AfterTag, Standalone,
365 Terminator);
366
367 if (StartTag == StringRef::npos)
368 break;
369
370 // Figure out what kind of chunk we have.
371 const unsigned UnknownKind = 10000;
372 unsigned Kind = llvm::StringSwitch<unsigned>(Tag)
373 .Case("typed-text", CK_TypedText)
374 .Case("text", CK_Text)
375 .Case("optional", CK_Optional)
376 .Case("placeholder", CK_Placeholder)
377 .Case("informative", CK_Informative)
378 .Case("current-parameter", CK_CurrentParameter)
379 .Case("lparen", CK_LeftParen)
380 .Case("rparen", CK_RightParen)
381 .Case("lbracket", CK_LeftBracket)
382 .Case("rbracket", CK_RightBracket)
383 .Case("lbrace", CK_LeftBrace)
384 .Case("rbrace", CK_RightBrace)
385 .Case("langle", CK_LeftAngle)
386 .Case("rangle", CK_RightAngle)
387 .Case("comma", CK_Comma)
388 .Default(UnknownKind);
389
390 // If we've hit a terminator tag, we're done.
391 if (Terminator)
392 break;
393
394 // Consume the tag.
395 Str = Str.substr(AfterTag);
396
397 // Handle standalone tags now, since they don't need to be matched to
398 // anything.
399 if (Standalone) {
400 // Ignore anything we don't know about.
401 if (Kind == UnknownKind)
402 continue;
403
404 switch ((ChunkKind)Kind) {
405 case CK_TypedText:
406 case CK_Text:
407 case CK_Optional:
408 case CK_Placeholder:
409 case CK_Informative:
410 case CK_CurrentParameter:
411 // There is no point in creating empty chunks of these kinds.
412 break;
413
414 case CK_LeftParen:
415 case CK_RightParen:
416 case CK_LeftBracket:
417 case CK_RightBracket:
418 case CK_LeftBrace:
419 case CK_RightBrace:
420 case CK_LeftAngle:
421 case CK_RightAngle:
422 case CK_Comma:
423 Result->AddChunk(Chunk((ChunkKind)Kind));
424 break;
425 }
426
427 continue;
428 }
429
430 if (Kind == CK_Optional) {
431 // Deserialize the optional code-completion string.
432 std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str));
433 Result->AddOptionalChunk(Optional);
434 }
435
436 StringRef EndTag = ParseNextTag(Str, StartTag, AfterTag, Standalone,
437 Terminator);
438 if (StartTag == StringRef::npos || !Terminator || Standalone)
439 break; // Parsing failed; just give up.
440
441 if (EndTag.empty() || Tag == EndTag) {
442 // Found the matching end tag. Add this chunk based on the text
443 // between the tags, then consume that input.
444 StringRef Text = Str.substr(0, StartTag);
445 switch ((ChunkKind)Kind) {
446 case CK_TypedText:
447 case CK_Text:
448 case CK_Placeholder:
449 case CK_Informative:
450 case CK_CurrentParameter:
451 case CK_LeftParen:
452 case CK_RightParen:
453 case CK_LeftBracket:
454 case CK_RightBracket:
455 case CK_LeftBrace:
456 case CK_RightBrace:
457 case CK_LeftAngle:
458 case CK_RightAngle:
459 case CK_Comma:
460 Result->AddChunk(Chunk((ChunkKind)Kind, UnescapeString(Text)));
461 break;
462
463 case CK_Optional:
464 // We've already added the optional chunk.
465 break;
466 }
467 }
468
469 // Remove this tag.
470 Str = Str.substr(AfterTag);
471 } while (!Str.empty());
472
473 return Result;
474}
475
99//===----------------------------------------------------------------------===//
100// Code completion overload candidate implementation
101//===----------------------------------------------------------------------===//
102FunctionDecl *
103CodeCompleteConsumer::OverloadCandidate::getFunction() const {
104 if (getKind() == CK_Function)
105 return Function;
106 else if (getKind() == CK_FunctionTemplate)

--- 21 unchanged lines hidden (view full) ---

128
129//===----------------------------------------------------------------------===//
130// Code completion consumer implementation
131//===----------------------------------------------------------------------===//
132
133CodeCompleteConsumer::~CodeCompleteConsumer() { }
134
135void
476//===----------------------------------------------------------------------===//
477// Code completion overload candidate implementation
478//===----------------------------------------------------------------------===//
479FunctionDecl *
480CodeCompleteConsumer::OverloadCandidate::getFunction() const {
481 if (getKind() == CK_Function)
482 return Function;
483 else if (getKind() == CK_FunctionTemplate)

--- 21 unchanged lines hidden (view full) ---

505
506//===----------------------------------------------------------------------===//
507// Code completion consumer implementation
508//===----------------------------------------------------------------------===//
509
510CodeCompleteConsumer::~CodeCompleteConsumer() { }
511
512void
136PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results,
513PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
514 Result *Results,
137 unsigned NumResults) {
138 // Print the results.
139 for (unsigned I = 0; I != NumResults; ++I) {
140 OS << "COMPLETION: ";
141 switch (Results[I].Kind) {
142 case Result::RK_Declaration:
143 OS << Results[I].Declaration->getNameAsString() << " : "
144 << Results[I].Rank;

--- 27 unchanged lines hidden (view full) ---

172
173 // Once we've printed the code-completion results, suppress remaining
174 // diagnostics.
175 // FIXME: Move this somewhere else!
176 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
177}
178
179void
515 unsigned NumResults) {
516 // Print the results.
517 for (unsigned I = 0; I != NumResults; ++I) {
518 OS << "COMPLETION: ";
519 switch (Results[I].Kind) {
520 case Result::RK_Declaration:
521 OS << Results[I].Declaration->getNameAsString() << " : "
522 << Results[I].Rank;

--- 27 unchanged lines hidden (view full) ---

550
551 // Once we've printed the code-completion results, suppress remaining
552 // diagnostics.
553 // FIXME: Move this somewhere else!
554 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
555}
556
557void
180PrintingCodeCompleteConsumer::ProcessOverloadCandidates(unsigned CurrentArg,
558PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
559 unsigned CurrentArg,
181 OverloadCandidate *Candidates,
182 unsigned NumCandidates) {
183 for (unsigned I = 0; I != NumCandidates; ++I) {
184 if (CodeCompletionString *CCS
185 = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) {
186 OS << "OVERLOAD: " << CCS->getAsString() << "\n";
187 delete CCS;
188 }
189 }
190
191 // Once we've printed the code-completion results, suppress remaining
192 // diagnostics.
193 // FIXME: Move this somewhere else!
194 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
195}
560 OverloadCandidate *Candidates,
561 unsigned NumCandidates) {
562 for (unsigned I = 0; I != NumCandidates; ++I) {
563 if (CodeCompletionString *CCS
564 = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) {
565 OS << "OVERLOAD: " << CCS->getAsString() << "\n";
566 delete CCS;
567 }
568 }
569
570 // Once we've printed the code-completion results, suppress remaining
571 // diagnostics.
572 // FIXME: Move this somewhere else!
573 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
574}
575
576void
577CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
578 Result *Results,
579 unsigned NumResults) {
580 // Print the results.
581 for (unsigned I = 0; I != NumResults; ++I) {
582 OS << "COMPLETION:" << Results[I].Rank << ":";
583 switch (Results[I].Kind) {
584 case Result::RK_Declaration:
585 if (RecordDecl *Record = dyn_cast<RecordDecl>(Results[I].Declaration)) {
586 if (Record->isStruct())
587 OS << "Struct:";
588 else if (Record->isUnion())
589 OS << "Union:";
590 else
591 OS << "Class:";
592 } else if (ObjCMethodDecl *Method
593 = dyn_cast<ObjCMethodDecl>(Results[I].Declaration)) {
594 if (Method->isInstanceMethod())
595 OS << "ObjCInstanceMethod:";
596 else
597 OS << "ObjCClassMethod:";
598 } else {
599 OS << Results[I].Declaration->getDeclKindName() << ":";
600 }
601 if (CodeCompletionString *CCS
602 = Results[I].CreateCodeCompletionString(SemaRef)) {
603 CCS->Serialize(OS);
604 delete CCS;
605 } else {
606 OS << "<typed-text>"
607 << Results[I].Declaration->getNameAsString()
608 << "</>";
609 }
610
611 OS << '\n';
612 break;
613
614 case Result::RK_Keyword:
615 OS << "Keyword:<typed-text>" << Results[I].Keyword << "</>\n";
616 break;
617
618 case Result::RK_Macro: {
619 OS << "Macro:";
620 if (CodeCompletionString *CCS
621 = Results[I].CreateCodeCompletionString(SemaRef)) {
622 CCS->Serialize(OS);
623 delete CCS;
624 } else {
625 OS << "<typed-text>" << Results[I].Macro->getName() << "</>";
626 }
627 OS << '\n';
628 break;
629 }
630 }
631 }
632
633 // Once we've printed the code-completion results, suppress remaining
634 // diagnostics.
635 // FIXME: Move this somewhere else!
636 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
637}
638
639void
640CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
641 unsigned CurrentArg,
642 OverloadCandidate *Candidates,
643 unsigned NumCandidates) {
644 for (unsigned I = 0; I != NumCandidates; ++I) {
645 if (CodeCompletionString *CCS
646 = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) {
647 OS << "OVERLOAD:";
648 CCS->Serialize(OS);
649 OS << '\n';
650 delete CCS;
651 }
652 }
653
654 // Once we've printed the code-completion results, suppress remaining
655 // diagnostics.
656 // FIXME: Move this somewhere else!
657 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
658}