blob: 9bf9e15253987d48da3d4ebf1784833da7b4a8ac [file] [log] [blame]
Douglas Gregor81b747b2009-09-17 21:32:03 +00001//===---- CodeCompleteConsumer.h - 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"
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"
19#include "llvm/Support/Compiler.h"
20#include "llvm/Support/raw_ostream.h"
21#include <algorithm>
Douglas Gregore6e03612009-09-18 22:15:54 +000022#include <cstring>
23#include <functional>
Douglas Gregor81b747b2009-09-17 21:32:03 +000024using namespace clang;
25
Douglas Gregore6e03612009-09-18 22:15:54 +000026//===----------------------------------------------------------------------===//
27// Code completion string implementation
28//===----------------------------------------------------------------------===//
29CodeCompletionString::Chunk
30CodeCompletionString::Chunk::CreateText(const char *Text) {
31 Chunk Result;
32 Result.Kind = CK_Text;
33 char *New = new char [std::strlen(Text) + 1];
34 std::strcpy(New, Text);
35 Result.Text = New;
36 return Result;
37}
38
39CodeCompletionString::Chunk
40CodeCompletionString::Chunk::CreateOptional(
41 std::auto_ptr<CodeCompletionString> Optional) {
42 Chunk Result;
43 Result.Kind = CK_Optional;
44 Result.Optional = Optional.release();
45 return Result;
46}
47
48CodeCompletionString::Chunk
49CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) {
50 Chunk Result;
51 Result.Kind = CK_Placeholder;
52 char *New = new char [std::strlen(Placeholder) + 1];
53 std::strcpy(New, Placeholder);
54 Result.Placeholder = New;
55 return Result;
56}
57
58void
59CodeCompletionString::Chunk::Destroy() {
60 switch (Kind) {
61 case CK_Text: delete [] Text; break;
62 case CK_Optional: delete Optional; break;
63 case CK_Placeholder: delete [] Placeholder; break;
64 }
65}
66
67CodeCompletionString::~CodeCompletionString() {
68 std::for_each(Chunks.begin(), Chunks.end(),
69 std::mem_fun_ref(&Chunk::Destroy));
70}
71
72std::string CodeCompletionString::getAsString() const {
73 std::string Result;
74 llvm::raw_string_ostream OS(Result);
75
76 for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
77 switch (C->Kind) {
78 case CK_Text: OS << C->Text; break;
79 case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break;
80 case CK_Placeholder: OS << "<#" << C->Placeholder << "#>"; break;
81 }
82 }
83
84 return Result;
85}
86
87//===----------------------------------------------------------------------===//
88// Code completion consumer implementation
89//===----------------------------------------------------------------------===//
90
Douglas Gregor81b747b2009-09-17 21:32:03 +000091CodeCompleteConsumer::CodeCompleteConsumer(Sema &S) : SemaRef(S) {
92 SemaRef.setCodeCompleteConsumer(this);
93}
94
95CodeCompleteConsumer::~CodeCompleteConsumer() {
96 SemaRef.setCodeCompleteConsumer(0);
97}
98
99void
100CodeCompleteConsumer::CodeCompleteMemberReferenceExpr(Scope *S,
101 QualType BaseType,
102 bool IsArrow) {
103 if (IsArrow) {
104 if (const PointerType *Ptr = BaseType->getAs<PointerType>())
105 BaseType = Ptr->getPointeeType();
106 else if (BaseType->isObjCObjectPointerType())
107 /*Do nothing*/ ;
108 else
109 return;
110 }
111
Douglas Gregor374929f2009-09-18 15:37:17 +0000112 ResultSet Results(*this);
Douglas Gregor81b747b2009-09-17 21:32:03 +0000113 unsigned NextRank = 0;
114
115 if (const RecordType *Record = BaseType->getAs<RecordType>()) {
Douglas Gregor374929f2009-09-18 15:37:17 +0000116 NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank, Results);
Douglas Gregor81b747b2009-09-17 21:32:03 +0000117
118 if (getSema().getLangOptions().CPlusPlus) {
119 if (!Results.empty())
120 // The "template" keyword can follow "->" or "." in the grammar.
121 Results.MaybeAddResult(Result("template", NextRank++));
122
Douglas Gregor33224e62009-09-18 17:42:29 +0000123 // We could have the start of a nested-name-specifier. Add those
124 // results as well.
125 Results.setFilter(&CodeCompleteConsumer::IsNestedNameSpecifier);
126 CollectLookupResults(S, NextRank, Results);
Douglas Gregor81b747b2009-09-17 21:32:03 +0000127 }
128
129 // Hand off the results found for code completion.
130 ProcessCodeCompleteResults(Results.data(), Results.size());
131
132 // We're done!
133 return;
134 }
135}
136
Douglas Gregor374929f2009-09-18 15:37:17 +0000137void CodeCompleteConsumer::CodeCompleteTag(Scope *S, ElaboratedType::TagKind TK) {
138 ResultSet::LookupFilter Filter = 0;
139 switch (TK) {
140 case ElaboratedType::TK_enum:
141 Filter = &CodeCompleteConsumer::IsEnum;
142 break;
143
144 case ElaboratedType::TK_class:
145 case ElaboratedType::TK_struct:
146 Filter = &CodeCompleteConsumer::IsClassOrStruct;
147 break;
148
149 case ElaboratedType::TK_union:
150 Filter = &CodeCompleteConsumer::IsUnion;
151 break;
152 }
153
154 ResultSet Results(*this, Filter);
Douglas Gregor33224e62009-09-18 17:42:29 +0000155 unsigned NextRank = CollectLookupResults(S, 0, Results);
Douglas Gregor374929f2009-09-18 15:37:17 +0000156
Douglas Gregor33224e62009-09-18 17:42:29 +0000157 if (getSema().getLangOptions().CPlusPlus) {
158 // We could have the start of a nested-name-specifier. Add those
159 // results as well.
160 Results.setFilter(&CodeCompleteConsumer::IsNestedNameSpecifier);
161 CollectLookupResults(S, NextRank, Results);
162 }
Douglas Gregor374929f2009-09-18 15:37:17 +0000163
164 ProcessCodeCompleteResults(Results.data(), Results.size());
165}
166
Douglas Gregor81b747b2009-09-17 21:32:03 +0000167void
168CodeCompleteConsumer::CodeCompleteQualifiedId(Scope *S,
169 NestedNameSpecifier *NNS,
170 bool EnteringContext) {
171 CXXScopeSpec SS;
172 SS.setScopeRep(NNS);
173 DeclContext *Ctx = getSema().computeDeclContext(SS, EnteringContext);
174 if (!Ctx)
175 return;
176
Douglas Gregor374929f2009-09-18 15:37:17 +0000177 ResultSet Results(*this);
178 unsigned NextRank = CollectMemberLookupResults(Ctx, 0, Results);
Douglas Gregor81b747b2009-09-17 21:32:03 +0000179
180 // The "template" keyword can follow "::" in the grammar
181 if (!Results.empty())
182 Results.MaybeAddResult(Result("template", NextRank));
183
184 ProcessCodeCompleteResults(Results.data(), Results.size());
185}
186
Douglas Gregor49f40bd2009-09-18 19:03:04 +0000187void CodeCompleteConsumer::CodeCompleteUsing(Scope *S) {
188 ResultSet Results(*this, &CodeCompleteConsumer::IsNestedNameSpecifier);
189
190 // If we aren't in class scope, we could see the "namespace" keyword.
191 if (!S->isClassScope())
192 Results.MaybeAddResult(Result("namespace", 0));
193
194 // After "using", we can see anything that would start a
195 // nested-name-specifier.
196 CollectLookupResults(S, 0, Results);
197
198 ProcessCodeCompleteResults(Results.data(), Results.size());
199}
200
201void CodeCompleteConsumer::CodeCompleteUsingDirective(Scope *S) {
202 // After "using namespace", we expect to see a namespace name or namespace
203 // alias.
204 ResultSet Results(*this, &CodeCompleteConsumer::IsNamespaceOrAlias);
205 CollectLookupResults(S, 0, Results);
206 ProcessCodeCompleteResults(Results.data(), Results.size());
207}
208
209void CodeCompleteConsumer::CodeCompleteNamespaceDecl(Scope *S) {
210 ResultSet Results(*this, &CodeCompleteConsumer::IsNamespace);
211 DeclContext *Ctx = (DeclContext *)S->getEntity();
212 if (!S->getParent())
213 Ctx = getSema().Context.getTranslationUnitDecl();
214
215 if (Ctx && Ctx->isFileContext()) {
216 // We only want to see those namespaces that have already been defined
217 // within this scope, because its likely that the user is creating an
218 // extended namespace declaration. Keep track of the most recent
219 // definition of each namespace.
220 std::map<NamespaceDecl *, NamespaceDecl *> OrigToLatest;
221 for (DeclContext::specific_decl_iterator<NamespaceDecl>
222 NS(Ctx->decls_begin()), NSEnd(Ctx->decls_end());
223 NS != NSEnd; ++NS)
224 OrigToLatest[NS->getOriginalNamespace()] = *NS;
225
226 // Add the most recent definition (or extended definition) of each
227 // namespace to the list of results.
228 for (std::map<NamespaceDecl *, NamespaceDecl *>::iterator
229 NS = OrigToLatest.begin(), NSEnd = OrigToLatest.end();
230 NS != NSEnd; ++NS)
231 Results.MaybeAddResult(Result(NS->second, 0));
232 }
233
234 ProcessCodeCompleteResults(Results.data(), Results.size());
235}
236
237void CodeCompleteConsumer::CodeCompleteNamespaceAliasDecl(Scope *S) {
238 // After "namespace", we expect to see a namespace or alias.
239 ResultSet Results(*this, &CodeCompleteConsumer::IsNamespaceOrAlias);
240 CollectLookupResults(S, 0, Results);
241 ProcessCodeCompleteResults(Results.data(), Results.size());
242}
243
Douglas Gregored8d3222009-09-18 20:05:18 +0000244void CodeCompleteConsumer::CodeCompleteOperatorName(Scope *S) {
245 ResultSet Results(*this, &CodeCompleteConsumer::IsType);
246
247 // Add the names of overloadable operators.
248#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
Douglas Gregore6e03612009-09-18 22:15:54 +0000249 if (std::strcmp(Spelling, "?")) \
Douglas Gregored8d3222009-09-18 20:05:18 +0000250 Results.MaybeAddResult(Result(Spelling, 0));
251#include "clang/Basic/OperatorKinds.def"
252
253 // Add any type names visible from the current scope
254 unsigned NextRank = CollectLookupResults(S, 0, Results);
255
256 // Add any type specifiers
257 AddTypeSpecifierResults(0, Results);
258
259 // Add any nested-name-specifiers
260 Results.setFilter(&CodeCompleteConsumer::IsNestedNameSpecifier);
261 CollectLookupResults(S, NextRank + 1, Results);
262
263 ProcessCodeCompleteResults(Results.data(), Results.size());
264}
265
Douglas Gregor81b747b2009-09-17 21:32:03 +0000266void CodeCompleteConsumer::ResultSet::MaybeAddResult(Result R) {
267 if (R.Kind != Result::RK_Declaration) {
268 // For non-declaration results, just add the result.
269 Results.push_back(R);
270 return;
271 }
Douglas Gregor75b71282009-09-18 17:54:00 +0000272
273 // Look through using declarations.
274 if (UsingDecl *Using = dyn_cast<UsingDecl>(R.Declaration))
275 return MaybeAddResult(Result(Using->getTargetDecl(), R.Rank));
Douglas Gregor81b747b2009-09-17 21:32:03 +0000276
Douglas Gregor75b71282009-09-18 17:54:00 +0000277 // Handle each declaration in an overload set separately.
278 if (OverloadedFunctionDecl *Ovl
279 = dyn_cast<OverloadedFunctionDecl>(R.Declaration)) {
280 for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
281 FEnd = Ovl->function_end();
282 F != FEnd; ++F)
283 MaybeAddResult(Result(*F, R.Rank));
284
285 return;
286 }
Douglas Gregor374929f2009-09-18 15:37:17 +0000287
Douglas Gregor81b747b2009-09-17 21:32:03 +0000288 Decl *CanonDecl = R.Declaration->getCanonicalDecl();
289 unsigned IDNS = CanonDecl->getIdentifierNamespace();
290
291 // Friend declarations and declarations introduced due to friends are never
292 // added as results.
293 if (isa<FriendDecl>(CanonDecl) ||
294 (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend)))
295 return;
296
Douglas Gregor33224e62009-09-18 17:42:29 +0000297 if (const IdentifierInfo *Id = R.Declaration->getIdentifier()) {
298 // __va_list_tag is a freak of nature. Find it and skip it.
Douglas Gregored8d3222009-09-18 20:05:18 +0000299 if (Id->isStr("__va_list_tag") || Id->isStr("__builtin_va_list"))
Douglas Gregor33224e62009-09-18 17:42:29 +0000300 return;
301
302 // FIXME: Should we filter out other names in the implementation's
303 // namespace, e.g., those containing a __ or that start with _[A-Z]?
304 }
305
306 // C++ constructors are never found by name lookup.
307 if (isa<CXXConstructorDecl>(CanonDecl))
308 return;
309
310 // Filter out any unwanted results.
311 if (Filter && !(Completer.*Filter)(R.Declaration))
312 return;
313
Douglas Gregor81b747b2009-09-17 21:32:03 +0000314 ShadowMap &SMap = ShadowMaps.back();
315 ShadowMap::iterator I, IEnd;
316 for (llvm::tie(I, IEnd) = SMap.equal_range(R.Declaration->getDeclName());
317 I != IEnd; ++I) {
318 NamedDecl *ND = I->second.first;
319 unsigned Index = I->second.second;
320 if (ND->getCanonicalDecl() == CanonDecl) {
321 // This is a redeclaration. Always pick the newer declaration.
322 I->second.first = R.Declaration;
323 Results[Index].Declaration = R.Declaration;
324
325 // Pick the best rank of the two.
326 Results[Index].Rank = std::min(Results[Index].Rank, R.Rank);
327
328 // We're done.
329 return;
330 }
331 }
332
333 // This is a new declaration in this scope. However, check whether this
334 // declaration name is hidden by a similarly-named declaration in an outer
335 // scope.
336 std::list<ShadowMap>::iterator SM, SMEnd = ShadowMaps.end();
337 --SMEnd;
338 for (SM = ShadowMaps.begin(); SM != SMEnd; ++SM) {
339 for (llvm::tie(I, IEnd) = SM->equal_range(R.Declaration->getDeclName());
340 I != IEnd; ++I) {
341 // A tag declaration does not hide a non-tag declaration.
342 if (I->second.first->getIdentifierNamespace() == Decl::IDNS_Tag &&
343 (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
344 Decl::IDNS_ObjCProtocol)))
345 continue;
346
347 // Protocols are in distinct namespaces from everything else.
348 if (((I->second.first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol)
349 || (IDNS & Decl::IDNS_ObjCProtocol)) &&
350 I->second.first->getIdentifierNamespace() != IDNS)
351 continue;
352
353 // The newly-added result is hidden by an entry in the shadow map.
Douglas Gregorb1c28a12009-09-18 15:51:54 +0000354 if (Completer.canHiddenResultBeFound(R.Declaration, I->second.first)) {
355 // Note that this result was hidden.
356 R.Hidden = true;
357 } else {
358 // This result was hidden and cannot be found; don't bother adding
359 // it.
360 return;
361 }
362
Douglas Gregor81b747b2009-09-17 21:32:03 +0000363 break;
364 }
365 }
366
Douglas Gregor33224e62009-09-18 17:42:29 +0000367 // Make sure that any given declaration only shows up in the result set once.
368 if (!AllDeclsFound.insert(CanonDecl))
369 return;
370
Douglas Gregor81b747b2009-09-17 21:32:03 +0000371 // Insert this result into the set of results and into the current shadow
372 // map.
373 SMap.insert(std::make_pair(R.Declaration->getDeclName(),
374 std::make_pair(R.Declaration, Results.size())));
375 Results.push_back(R);
376}
377
378/// \brief Enter into a new scope.
379void CodeCompleteConsumer::ResultSet::EnterNewScope() {
380 ShadowMaps.push_back(ShadowMap());
381}
382
383/// \brief Exit from the current scope.
384void CodeCompleteConsumer::ResultSet::ExitScope() {
385 ShadowMaps.pop_back();
386}
387
Douglas Gregor374929f2009-09-18 15:37:17 +0000388// Find the next outer declaration context corresponding to this scope.
389static DeclContext *findOuterContext(Scope *S) {
390 for (S = S->getParent(); S; S = S->getParent())
391 if (S->getEntity())
392 return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext();
393
394 return 0;
395}
396
397/// \brief Collect the results of searching for declarations within the given
398/// scope and its parent scopes.
399///
400/// \param S the scope in which we will start looking for declarations.
401///
402/// \param InitialRank the initial rank given to results in this scope.
403/// Larger rank values will be used for results found in parent scopes.
404unsigned CodeCompleteConsumer::CollectLookupResults(Scope *S,
405 unsigned InitialRank,
406 ResultSet &Results) {
407 if (!S)
408 return InitialRank;
409
410 // FIXME: Using directives!
411
412 unsigned NextRank = InitialRank;
413 Results.EnterNewScope();
414 if (S->getEntity() &&
415 !((DeclContext *)S->getEntity())->isFunctionOrMethod()) {
416 // Look into this scope's declaration context, along with any of its
417 // parent lookup contexts (e.g., enclosing classes), up to the point
418 // where we hit the context stored in the next outer scope.
419 DeclContext *Ctx = (DeclContext *)S->getEntity();
420 DeclContext *OuterCtx = findOuterContext(S);
421
422 for (; Ctx && Ctx->getPrimaryContext() != OuterCtx;
423 Ctx = Ctx->getLookupParent()) {
424 if (Ctx->isFunctionOrMethod())
425 continue;
426
427 NextRank = CollectMemberLookupResults(Ctx, NextRank + 1, Results);
428 }
429 } else if (!S->getParent()) {
430 // Look into the translation unit scope. We walk through the translation
431 // unit's declaration context, because the Scope itself won't have all of
432 // the declarations if
433 NextRank = CollectMemberLookupResults(
434 getSema().Context.getTranslationUnitDecl(),
435 NextRank + 1, Results);
436 } else {
437 // Walk through the declarations in this Scope.
438 for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
439 D != DEnd; ++D) {
440 if (NamedDecl *ND = dyn_cast<NamedDecl>((Decl *)((*D).get())))
441 Results.MaybeAddResult(Result(ND, NextRank));
442 }
443
444 NextRank = NextRank + 1;
445 }
446
447 // Lookup names in the parent scope.
448 NextRank = CollectLookupResults(S->getParent(), NextRank, Results);
449 Results.ExitScope();
450
451 return NextRank;
452}
453
Douglas Gregor81b747b2009-09-17 21:32:03 +0000454/// \brief Collect the results of searching for members within the given
455/// declaration context.
456///
457/// \param Ctx the declaration context from which we will gather results.
458///
Douglas Gregor374929f2009-09-18 15:37:17 +0000459/// \param InitialRank the initial rank given to results in this declaration
460/// context. Larger rank values will be used for, e.g., members found in
461/// base classes.
Douglas Gregor81b747b2009-09-17 21:32:03 +0000462///
463/// \param Results the result set that will be extended with any results
464/// found within this declaration context (and, for a C++ class, its bases).
465///
466/// \returns the next higher rank value, after considering all of the
467/// names within this declaration context.
Douglas Gregor374929f2009-09-18 15:37:17 +0000468unsigned CodeCompleteConsumer::CollectMemberLookupResults(DeclContext *Ctx,
Douglas Gregor5836b012009-09-18 18:07:23 +0000469 unsigned InitialRank,
Douglas Gregor374929f2009-09-18 15:37:17 +0000470 ResultSet &Results) {
Douglas Gregor5836b012009-09-18 18:07:23 +0000471 llvm::SmallPtrSet<DeclContext *, 16> Visited;
472 return CollectMemberLookupResults(Ctx, InitialRank, Visited, Results);
473}
474
475/// \brief Collect the results of searching for members within the given
476/// declaration context.
477///
478/// \param Ctx the declaration context from which we will gather results.
479///
480/// \param InitialRank the initial rank given to results in this declaration
481/// context. Larger rank values will be used for, e.g., members found in
482/// base classes.
483///
484/// \param Visited the set of declaration contexts that have already been
485/// visited. Declaration contexts will only be visited once.
486///
487/// \param Results the result set that will be extended with any results
488/// found within this declaration context (and, for a C++ class, its bases).
489///
490/// \returns the next higher rank value, after considering all of the
491/// names within this declaration context.
492unsigned CodeCompleteConsumer::CollectMemberLookupResults(DeclContext *Ctx,
493 unsigned InitialRank,
494 llvm::SmallPtrSet<DeclContext *, 16> &Visited,
495 ResultSet &Results) {
496 // Make sure we don't visit the same context twice.
497 if (!Visited.insert(Ctx->getPrimaryContext()))
498 return InitialRank;
499
Douglas Gregor81b747b2009-09-17 21:32:03 +0000500 // Enumerate all of the results in this context.
501 Results.EnterNewScope();
502 for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx;
503 CurCtx = CurCtx->getNextContext()) {
504 for (DeclContext::decl_iterator D = CurCtx->decls_begin(),
505 DEnd = CurCtx->decls_end();
506 D != DEnd; ++D) {
Douglas Gregor374929f2009-09-18 15:37:17 +0000507 if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
Douglas Gregor81b747b2009-09-17 21:32:03 +0000508 Results.MaybeAddResult(Result(ND, InitialRank));
Douglas Gregor81b747b2009-09-17 21:32:03 +0000509 }
510 }
511
512 // Traverse the contexts of inherited classes.
513 unsigned NextRank = InitialRank;
514 if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
515 for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(),
516 BEnd = Record->bases_end();
517 B != BEnd; ++B) {
518 QualType BaseType = B->getType();
519
520 // Don't look into dependent bases, because name lookup can't look
521 // there anyway.
522 if (BaseType->isDependentType())
523 continue;
524
525 const RecordType *Record = BaseType->getAs<RecordType>();
526 if (!Record)
527 continue;
528
Douglas Gregor81b747b2009-09-17 21:32:03 +0000529 // FIXME: It would be nice to be able to determine whether referencing
530 // a particular member would be ambiguous. For example, given
531 //
532 // struct A { int member; };
533 // struct B { int member; };
534 // struct C : A, B { };
535 //
536 // void f(C *c) { c->### }
537 // accessing 'member' would result in an ambiguity. However, code
538 // completion could be smart enough to qualify the member with the
539 // base class, e.g.,
540 //
541 // c->B::member
542 //
543 // or
544 //
545 // c->A::member
546
547 // Collect results from this base class (and its bases).
548 NextRank = std::max(NextRank,
Douglas Gregor374929f2009-09-18 15:37:17 +0000549 CollectMemberLookupResults(Record->getDecl(),
Douglas Gregor5836b012009-09-18 18:07:23 +0000550 InitialRank + 1,
551 Visited,
Douglas Gregor374929f2009-09-18 15:37:17 +0000552 Results));
Douglas Gregor81b747b2009-09-17 21:32:03 +0000553 }
554 }
555
556 // FIXME: Look into base classes in Objective-C!
557
558 Results.ExitScope();
559 return NextRank;
560}
561
Douglas Gregor374929f2009-09-18 15:37:17 +0000562/// \brief Determines whether the given declaration is suitable as the
563/// start of a C++ nested-name-specifier, e.g., a class or namespace.
564bool CodeCompleteConsumer::IsNestedNameSpecifier(NamedDecl *ND) const {
565 // Allow us to find class templates, too.
566 if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
567 ND = ClassTemplate->getTemplatedDecl();
568
569 return getSema().isAcceptableNestedNameSpecifier(ND);
570}
571
572/// \brief Determines whether the given declaration is an enumeration.
573bool CodeCompleteConsumer::IsEnum(NamedDecl *ND) const {
574 return isa<EnumDecl>(ND);
575}
576
577/// \brief Determines whether the given declaration is a class or struct.
578bool CodeCompleteConsumer::IsClassOrStruct(NamedDecl *ND) const {
579 // Allow us to find class templates, too.
580 if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
581 ND = ClassTemplate->getTemplatedDecl();
582
583 if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
584 return RD->getTagKind() == TagDecl::TK_class ||
585 RD->getTagKind() == TagDecl::TK_struct;
586
587 return false;
588}
589
590/// \brief Determines whether the given declaration is a union.
591bool CodeCompleteConsumer::IsUnion(NamedDecl *ND) const {
592 // Allow us to find class templates, too.
593 if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
594 ND = ClassTemplate->getTemplatedDecl();
595
596 if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
597 return RD->getTagKind() == TagDecl::TK_union;
598
599 return false;
600}
601
Douglas Gregor49f40bd2009-09-18 19:03:04 +0000602/// \brief Determines whether the given declaration is a namespace.
603bool CodeCompleteConsumer::IsNamespace(NamedDecl *ND) const {
604 return isa<NamespaceDecl>(ND);
605}
606
607/// \brief Determines whether the given declaration is a namespace or
608/// namespace alias.
609bool CodeCompleteConsumer::IsNamespaceOrAlias(NamedDecl *ND) const {
610 return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
611}
612
Douglas Gregored8d3222009-09-18 20:05:18 +0000613/// \brief Brief determines whether the given declaration is a namespace or
614/// namespace alias.
615bool CodeCompleteConsumer::IsType(NamedDecl *ND) const {
616 return isa<TypeDecl>(ND);
617}
618
Douglas Gregor81b747b2009-09-17 21:32:03 +0000619namespace {
620 struct VISIBILITY_HIDDEN SortCodeCompleteResult {
621 typedef CodeCompleteConsumer::Result Result;
622
623 bool operator()(const Result &X, const Result &Y) const {
624 // Sort first by rank.
625 if (X.Rank < Y.Rank)
626 return true;
627 else if (X.Rank > Y.Rank)
628 return false;
629
630 // Result kinds are ordered by decreasing importance.
631 if (X.Kind < Y.Kind)
632 return true;
633 else if (X.Kind > Y.Kind)
634 return false;
635
636 // Non-hidden names precede hidden names.
637 if (X.Hidden != Y.Hidden)
638 return !X.Hidden;
639
640 // Ordering depends on the kind of result.
641 switch (X.Kind) {
642 case Result::RK_Declaration:
643 // Order based on the declaration names.
644 return X.Declaration->getDeclName() < Y.Declaration->getDeclName();
645
646 case Result::RK_Keyword:
647 return strcmp(X.Keyword, Y.Keyword) == -1;
648 }
649
650 // If only our C++ compiler did control-flow warnings properly.
651 return false;
652 }
653 };
654}
655
Douglas Gregorb1c28a12009-09-18 15:51:54 +0000656/// \brief Determines whether the given hidden result could be found with
657/// some extra work, e.g., by qualifying the name.
658///
659/// \param Hidden the declaration that is hidden by the currenly \p Visible
660/// declaration.
661///
662/// \param Visible the declaration with the same name that is already visible.
663///
664/// \returns true if the hidden result can be found by some mechanism,
665/// false otherwise.
666bool CodeCompleteConsumer::canHiddenResultBeFound(NamedDecl *Hidden,
667 NamedDecl *Visible) {
668 // In C, there is no way to refer to a hidden name.
669 if (!getSema().getLangOptions().CPlusPlus)
670 return false;
671
672 DeclContext *HiddenCtx = Hidden->getDeclContext()->getLookupContext();
673
674 // There is no way to qualify a name declared in a function or method.
675 if (HiddenCtx->isFunctionOrMethod())
676 return false;
677
678 // If the hidden and visible declarations are in different name-lookup
679 // contexts, then we can qualify the name of the hidden declaration.
680 // FIXME: Optionally compute the string needed to refer to the hidden
681 // name.
682 return HiddenCtx != Visible->getDeclContext()->getLookupContext();
683}
684
Douglas Gregored8d3222009-09-18 20:05:18 +0000685/// \brief Add type specifiers for the current language as keyword results.
686void CodeCompleteConsumer::AddTypeSpecifierResults(unsigned Rank,
687 ResultSet &Results) {
688 Results.MaybeAddResult(Result("short", Rank));
689 Results.MaybeAddResult(Result("long", Rank));
690 Results.MaybeAddResult(Result("signed", Rank));
691 Results.MaybeAddResult(Result("unsigned", Rank));
692 Results.MaybeAddResult(Result("void", Rank));
693 Results.MaybeAddResult(Result("char", Rank));
694 Results.MaybeAddResult(Result("int", Rank));
695 Results.MaybeAddResult(Result("float", Rank));
696 Results.MaybeAddResult(Result("double", Rank));
697 Results.MaybeAddResult(Result("enum", Rank));
698 Results.MaybeAddResult(Result("struct", Rank));
699 Results.MaybeAddResult(Result("union", Rank));
700
701 if (getSema().getLangOptions().C99) {
702 // C99-specific
703 Results.MaybeAddResult(Result("_Complex", Rank));
704 Results.MaybeAddResult(Result("_Imaginary", Rank));
705 Results.MaybeAddResult(Result("_Bool", Rank));
706 }
707
708 if (getSema().getLangOptions().CPlusPlus) {
709 // C++-specific
710 Results.MaybeAddResult(Result("bool", Rank));
711 Results.MaybeAddResult(Result("class", Rank));
712 Results.MaybeAddResult(Result("typename", Rank));
713 Results.MaybeAddResult(Result("wchar_t", Rank));
714
715 if (getSema().getLangOptions().CPlusPlus0x) {
716 Results.MaybeAddResult(Result("char16_t", Rank));
717 Results.MaybeAddResult(Result("char32_t", Rank));
718 Results.MaybeAddResult(Result("decltype", Rank));
719 }
720 }
721
722 // GNU extensions
723 if (getSema().getLangOptions().GNUMode) {
724 // FIXME: Enable when we actually support decimal floating point.
725 // Results.MaybeAddResult(Result("_Decimal32", Rank));
726 // Results.MaybeAddResult(Result("_Decimal64", Rank));
727 // Results.MaybeAddResult(Result("_Decimal128", Rank));
728 Results.MaybeAddResult(Result("typeof", Rank));
729 }
730}
731
Douglas Gregore6e03612009-09-18 22:15:54 +0000732/// \brief Add function parameter chunks to the given code completion string.
733static void AddFunctionParameterChunks(ASTContext &Context,
734 FunctionDecl *Function,
735 CodeCompletionString *Result) {
736 CodeCompletionString *CCStr = Result;
737
738 for (unsigned P = 0, N = Function->getNumParams(); P != N; ++P) {
739 ParmVarDecl *Param = Function->getParamDecl(P);
740
741 if (Param->hasDefaultArg()) {
742 // When we see an optional default argument, put that argument and
743 // the remaining default arguments into a new, optional string.
744 CodeCompletionString *Opt = new CodeCompletionString;
745 CCStr->AddOptionalChunk(std::auto_ptr<CodeCompletionString>(Opt));
746 CCStr = Opt;
747 }
748
749 if (P != 0)
750 CCStr->AddTextChunk(", ");
751
752 // Format the placeholder string.
753 std::string PlaceholderStr;
754 if (Param->getIdentifier())
755 PlaceholderStr = Param->getIdentifier()->getName();
756
757 Param->getType().getAsStringInternal(PlaceholderStr,
758 Context.PrintingPolicy);
759
760 // Add the placeholder string.
761 CCStr->AddPlaceholderChunk(PlaceholderStr.c_str());
762 }
763}
764
765/// \brief If possible, create a new code completion string for the given
766/// result.
767///
768/// \returns Either a new, heap-allocated code completion string describing
769/// how to use this result, or NULL to indicate that the string or name of the
770/// result is all that is needed.
771CodeCompletionString *
772CodeCompleteConsumer::CreateCodeCompletionString(Result R) {
773 if (R.Kind != Result::RK_Declaration)
774 return 0;
775
776 NamedDecl *ND = R.Declaration;
777
778 if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
779 CodeCompletionString *Result = new CodeCompletionString;
780 Result->AddTextChunk(Function->getNameAsString().c_str());
781 Result->AddTextChunk("(");
782 AddFunctionParameterChunks(getSema().Context, Function, Result);
783 Result->AddTextChunk(")");
784 return Result;
785 }
786
787 return 0;
788}
789
Douglas Gregor81b747b2009-09-17 21:32:03 +0000790void
791PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results,
792 unsigned NumResults) {
793 // Sort the results by rank/kind/etc.
794 std::stable_sort(Results, Results + NumResults, SortCodeCompleteResult());
795
796 // Print the results.
797 for (unsigned I = 0; I != NumResults; ++I) {
798 switch (Results[I].Kind) {
799 case Result::RK_Declaration:
800 OS << Results[I].Declaration->getNameAsString() << " : "
801 << Results[I].Rank;
802 if (Results[I].Hidden)
803 OS << " (Hidden)";
Douglas Gregore6e03612009-09-18 22:15:54 +0000804 if (CodeCompletionString *CCS = CreateCodeCompletionString(Results[I])) {
805 OS << " : " << CCS->getAsString();
806 delete CCS;
807 }
808
Douglas Gregor81b747b2009-09-17 21:32:03 +0000809 OS << '\n';
810 break;
811
812 case Result::RK_Keyword:
813 OS << Results[I].Keyword << " : " << Results[I].Rank << '\n';
814 break;
815 }
816 }
817
818 // Once we've printed the code-completion results, suppress remaining
819 // diagnostics.
820 // FIXME: Move this somewhere else!
821 getSema().PP.getDiagnostics().setSuppressAllDiagnostics();
822}