blob: d82047d912ecaa3a0dc12da0204e8bdba9b5424f [file] [log] [blame]
Douglas Gregor2436e712009-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 Gregor56c2dbc2009-09-18 17:54:00 +000014#include "clang/AST/DeclCXX.h"
Douglas Gregorf45b0cf2009-09-18 15:37:17 +000015#include "clang/Parse/Scope.h"
Douglas Gregor2436e712009-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>
22#include <string.h>
23using namespace clang;
24
25CodeCompleteConsumer::CodeCompleteConsumer(Sema &S) : SemaRef(S) {
26 SemaRef.setCodeCompleteConsumer(this);
27}
28
29CodeCompleteConsumer::~CodeCompleteConsumer() {
30 SemaRef.setCodeCompleteConsumer(0);
31}
32
33void
34CodeCompleteConsumer::CodeCompleteMemberReferenceExpr(Scope *S,
35 QualType BaseType,
36 bool IsArrow) {
37 if (IsArrow) {
38 if (const PointerType *Ptr = BaseType->getAs<PointerType>())
39 BaseType = Ptr->getPointeeType();
40 else if (BaseType->isObjCObjectPointerType())
41 /*Do nothing*/ ;
42 else
43 return;
44 }
45
Douglas Gregorf45b0cf2009-09-18 15:37:17 +000046 ResultSet Results(*this);
Douglas Gregor2436e712009-09-17 21:32:03 +000047 unsigned NextRank = 0;
48
49 if (const RecordType *Record = BaseType->getAs<RecordType>()) {
Douglas Gregorf45b0cf2009-09-18 15:37:17 +000050 NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank, Results);
Douglas Gregor2436e712009-09-17 21:32:03 +000051
52 if (getSema().getLangOptions().CPlusPlus) {
53 if (!Results.empty())
54 // The "template" keyword can follow "->" or "." in the grammar.
55 Results.MaybeAddResult(Result("template", NextRank++));
56
Douglas Gregor945e8d92009-09-18 17:42:29 +000057 // We could have the start of a nested-name-specifier. Add those
58 // results as well.
59 Results.setFilter(&CodeCompleteConsumer::IsNestedNameSpecifier);
60 CollectLookupResults(S, NextRank, Results);
Douglas Gregor2436e712009-09-17 21:32:03 +000061 }
62
63 // Hand off the results found for code completion.
64 ProcessCodeCompleteResults(Results.data(), Results.size());
65
66 // We're done!
67 return;
68 }
69}
70
Douglas Gregorf45b0cf2009-09-18 15:37:17 +000071void CodeCompleteConsumer::CodeCompleteTag(Scope *S, ElaboratedType::TagKind TK) {
72 ResultSet::LookupFilter Filter = 0;
73 switch (TK) {
74 case ElaboratedType::TK_enum:
75 Filter = &CodeCompleteConsumer::IsEnum;
76 break;
77
78 case ElaboratedType::TK_class:
79 case ElaboratedType::TK_struct:
80 Filter = &CodeCompleteConsumer::IsClassOrStruct;
81 break;
82
83 case ElaboratedType::TK_union:
84 Filter = &CodeCompleteConsumer::IsUnion;
85 break;
86 }
87
88 ResultSet Results(*this, Filter);
Douglas Gregor945e8d92009-09-18 17:42:29 +000089 unsigned NextRank = CollectLookupResults(S, 0, Results);
Douglas Gregorf45b0cf2009-09-18 15:37:17 +000090
Douglas Gregor945e8d92009-09-18 17:42:29 +000091 if (getSema().getLangOptions().CPlusPlus) {
92 // We could have the start of a nested-name-specifier. Add those
93 // results as well.
94 Results.setFilter(&CodeCompleteConsumer::IsNestedNameSpecifier);
95 CollectLookupResults(S, NextRank, Results);
96 }
Douglas Gregorf45b0cf2009-09-18 15:37:17 +000097
98 ProcessCodeCompleteResults(Results.data(), Results.size());
99}
100
Douglas Gregor2436e712009-09-17 21:32:03 +0000101void
102CodeCompleteConsumer::CodeCompleteQualifiedId(Scope *S,
103 NestedNameSpecifier *NNS,
104 bool EnteringContext) {
105 CXXScopeSpec SS;
106 SS.setScopeRep(NNS);
107 DeclContext *Ctx = getSema().computeDeclContext(SS, EnteringContext);
108 if (!Ctx)
109 return;
110
Douglas Gregorf45b0cf2009-09-18 15:37:17 +0000111 ResultSet Results(*this);
112 unsigned NextRank = CollectMemberLookupResults(Ctx, 0, Results);
Douglas Gregor2436e712009-09-17 21:32:03 +0000113
114 // The "template" keyword can follow "::" in the grammar
115 if (!Results.empty())
116 Results.MaybeAddResult(Result("template", NextRank));
117
118 ProcessCodeCompleteResults(Results.data(), Results.size());
119}
120
Douglas Gregor7e90c6d2009-09-18 19:03:04 +0000121void CodeCompleteConsumer::CodeCompleteUsing(Scope *S) {
122 ResultSet Results(*this, &CodeCompleteConsumer::IsNestedNameSpecifier);
123
124 // If we aren't in class scope, we could see the "namespace" keyword.
125 if (!S->isClassScope())
126 Results.MaybeAddResult(Result("namespace", 0));
127
128 // After "using", we can see anything that would start a
129 // nested-name-specifier.
130 CollectLookupResults(S, 0, Results);
131
132 ProcessCodeCompleteResults(Results.data(), Results.size());
133}
134
135void CodeCompleteConsumer::CodeCompleteUsingDirective(Scope *S) {
136 // After "using namespace", we expect to see a namespace name or namespace
137 // alias.
138 ResultSet Results(*this, &CodeCompleteConsumer::IsNamespaceOrAlias);
139 CollectLookupResults(S, 0, Results);
140 ProcessCodeCompleteResults(Results.data(), Results.size());
141}
142
143void CodeCompleteConsumer::CodeCompleteNamespaceDecl(Scope *S) {
144 ResultSet Results(*this, &CodeCompleteConsumer::IsNamespace);
145 DeclContext *Ctx = (DeclContext *)S->getEntity();
146 if (!S->getParent())
147 Ctx = getSema().Context.getTranslationUnitDecl();
148
149 if (Ctx && Ctx->isFileContext()) {
150 // We only want to see those namespaces that have already been defined
151 // within this scope, because its likely that the user is creating an
152 // extended namespace declaration. Keep track of the most recent
153 // definition of each namespace.
154 std::map<NamespaceDecl *, NamespaceDecl *> OrigToLatest;
155 for (DeclContext::specific_decl_iterator<NamespaceDecl>
156 NS(Ctx->decls_begin()), NSEnd(Ctx->decls_end());
157 NS != NSEnd; ++NS)
158 OrigToLatest[NS->getOriginalNamespace()] = *NS;
159
160 // Add the most recent definition (or extended definition) of each
161 // namespace to the list of results.
162 for (std::map<NamespaceDecl *, NamespaceDecl *>::iterator
163 NS = OrigToLatest.begin(), NSEnd = OrigToLatest.end();
164 NS != NSEnd; ++NS)
165 Results.MaybeAddResult(Result(NS->second, 0));
166 }
167
168 ProcessCodeCompleteResults(Results.data(), Results.size());
169}
170
171void CodeCompleteConsumer::CodeCompleteNamespaceAliasDecl(Scope *S) {
172 // After "namespace", we expect to see a namespace or alias.
173 ResultSet Results(*this, &CodeCompleteConsumer::IsNamespaceOrAlias);
174 CollectLookupResults(S, 0, Results);
175 ProcessCodeCompleteResults(Results.data(), Results.size());
176}
177
Douglas Gregorc811ede2009-09-18 20:05:18 +0000178void CodeCompleteConsumer::CodeCompleteOperatorName(Scope *S) {
179 ResultSet Results(*this, &CodeCompleteConsumer::IsType);
180
181 // Add the names of overloadable operators.
182#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
183 if (strcmp(Spelling, "?")) \
184 Results.MaybeAddResult(Result(Spelling, 0));
185#include "clang/Basic/OperatorKinds.def"
186
187 // Add any type names visible from the current scope
188 unsigned NextRank = CollectLookupResults(S, 0, Results);
189
190 // Add any type specifiers
191 AddTypeSpecifierResults(0, Results);
192
193 // Add any nested-name-specifiers
194 Results.setFilter(&CodeCompleteConsumer::IsNestedNameSpecifier);
195 CollectLookupResults(S, NextRank + 1, Results);
196
197 ProcessCodeCompleteResults(Results.data(), Results.size());
198}
199
Douglas Gregor2436e712009-09-17 21:32:03 +0000200void CodeCompleteConsumer::ResultSet::MaybeAddResult(Result R) {
201 if (R.Kind != Result::RK_Declaration) {
202 // For non-declaration results, just add the result.
203 Results.push_back(R);
204 return;
205 }
Douglas Gregor56c2dbc2009-09-18 17:54:00 +0000206
207 // Look through using declarations.
208 if (UsingDecl *Using = dyn_cast<UsingDecl>(R.Declaration))
209 return MaybeAddResult(Result(Using->getTargetDecl(), R.Rank));
Douglas Gregor2436e712009-09-17 21:32:03 +0000210
Douglas Gregor56c2dbc2009-09-18 17:54:00 +0000211 // Handle each declaration in an overload set separately.
212 if (OverloadedFunctionDecl *Ovl
213 = dyn_cast<OverloadedFunctionDecl>(R.Declaration)) {
214 for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
215 FEnd = Ovl->function_end();
216 F != FEnd; ++F)
217 MaybeAddResult(Result(*F, R.Rank));
218
219 return;
220 }
Douglas Gregorf45b0cf2009-09-18 15:37:17 +0000221
Douglas Gregor2436e712009-09-17 21:32:03 +0000222 Decl *CanonDecl = R.Declaration->getCanonicalDecl();
223 unsigned IDNS = CanonDecl->getIdentifierNamespace();
224
225 // Friend declarations and declarations introduced due to friends are never
226 // added as results.
227 if (isa<FriendDecl>(CanonDecl) ||
228 (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend)))
229 return;
230
Douglas Gregor945e8d92009-09-18 17:42:29 +0000231 if (const IdentifierInfo *Id = R.Declaration->getIdentifier()) {
232 // __va_list_tag is a freak of nature. Find it and skip it.
Douglas Gregorc811ede2009-09-18 20:05:18 +0000233 if (Id->isStr("__va_list_tag") || Id->isStr("__builtin_va_list"))
Douglas Gregor945e8d92009-09-18 17:42:29 +0000234 return;
235
236 // FIXME: Should we filter out other names in the implementation's
237 // namespace, e.g., those containing a __ or that start with _[A-Z]?
238 }
239
240 // C++ constructors are never found by name lookup.
241 if (isa<CXXConstructorDecl>(CanonDecl))
242 return;
243
244 // Filter out any unwanted results.
245 if (Filter && !(Completer.*Filter)(R.Declaration))
246 return;
247
Douglas Gregor2436e712009-09-17 21:32:03 +0000248 ShadowMap &SMap = ShadowMaps.back();
249 ShadowMap::iterator I, IEnd;
250 for (llvm::tie(I, IEnd) = SMap.equal_range(R.Declaration->getDeclName());
251 I != IEnd; ++I) {
252 NamedDecl *ND = I->second.first;
253 unsigned Index = I->second.second;
254 if (ND->getCanonicalDecl() == CanonDecl) {
255 // This is a redeclaration. Always pick the newer declaration.
256 I->second.first = R.Declaration;
257 Results[Index].Declaration = R.Declaration;
258
259 // Pick the best rank of the two.
260 Results[Index].Rank = std::min(Results[Index].Rank, R.Rank);
261
262 // We're done.
263 return;
264 }
265 }
266
267 // This is a new declaration in this scope. However, check whether this
268 // declaration name is hidden by a similarly-named declaration in an outer
269 // scope.
270 std::list<ShadowMap>::iterator SM, SMEnd = ShadowMaps.end();
271 --SMEnd;
272 for (SM = ShadowMaps.begin(); SM != SMEnd; ++SM) {
273 for (llvm::tie(I, IEnd) = SM->equal_range(R.Declaration->getDeclName());
274 I != IEnd; ++I) {
275 // A tag declaration does not hide a non-tag declaration.
276 if (I->second.first->getIdentifierNamespace() == Decl::IDNS_Tag &&
277 (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
278 Decl::IDNS_ObjCProtocol)))
279 continue;
280
281 // Protocols are in distinct namespaces from everything else.
282 if (((I->second.first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol)
283 || (IDNS & Decl::IDNS_ObjCProtocol)) &&
284 I->second.first->getIdentifierNamespace() != IDNS)
285 continue;
286
287 // The newly-added result is hidden by an entry in the shadow map.
Douglas Gregor2da11082009-09-18 15:51:54 +0000288 if (Completer.canHiddenResultBeFound(R.Declaration, I->second.first)) {
289 // Note that this result was hidden.
290 R.Hidden = true;
291 } else {
292 // This result was hidden and cannot be found; don't bother adding
293 // it.
294 return;
295 }
296
Douglas Gregor2436e712009-09-17 21:32:03 +0000297 break;
298 }
299 }
300
Douglas Gregor945e8d92009-09-18 17:42:29 +0000301 // Make sure that any given declaration only shows up in the result set once.
302 if (!AllDeclsFound.insert(CanonDecl))
303 return;
304
Douglas Gregor2436e712009-09-17 21:32:03 +0000305 // Insert this result into the set of results and into the current shadow
306 // map.
307 SMap.insert(std::make_pair(R.Declaration->getDeclName(),
308 std::make_pair(R.Declaration, Results.size())));
309 Results.push_back(R);
310}
311
312/// \brief Enter into a new scope.
313void CodeCompleteConsumer::ResultSet::EnterNewScope() {
314 ShadowMaps.push_back(ShadowMap());
315}
316
317/// \brief Exit from the current scope.
318void CodeCompleteConsumer::ResultSet::ExitScope() {
319 ShadowMaps.pop_back();
320}
321
Douglas Gregorf45b0cf2009-09-18 15:37:17 +0000322// Find the next outer declaration context corresponding to this scope.
323static DeclContext *findOuterContext(Scope *S) {
324 for (S = S->getParent(); S; S = S->getParent())
325 if (S->getEntity())
326 return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext();
327
328 return 0;
329}
330
331/// \brief Collect the results of searching for declarations within the given
332/// scope and its parent scopes.
333///
334/// \param S the scope in which we will start looking for declarations.
335///
336/// \param InitialRank the initial rank given to results in this scope.
337/// Larger rank values will be used for results found in parent scopes.
338unsigned CodeCompleteConsumer::CollectLookupResults(Scope *S,
339 unsigned InitialRank,
340 ResultSet &Results) {
341 if (!S)
342 return InitialRank;
343
344 // FIXME: Using directives!
345
346 unsigned NextRank = InitialRank;
347 Results.EnterNewScope();
348 if (S->getEntity() &&
349 !((DeclContext *)S->getEntity())->isFunctionOrMethod()) {
350 // Look into this scope's declaration context, along with any of its
351 // parent lookup contexts (e.g., enclosing classes), up to the point
352 // where we hit the context stored in the next outer scope.
353 DeclContext *Ctx = (DeclContext *)S->getEntity();
354 DeclContext *OuterCtx = findOuterContext(S);
355
356 for (; Ctx && Ctx->getPrimaryContext() != OuterCtx;
357 Ctx = Ctx->getLookupParent()) {
358 if (Ctx->isFunctionOrMethod())
359 continue;
360
361 NextRank = CollectMemberLookupResults(Ctx, NextRank + 1, Results);
362 }
363 } else if (!S->getParent()) {
364 // Look into the translation unit scope. We walk through the translation
365 // unit's declaration context, because the Scope itself won't have all of
366 // the declarations if
367 NextRank = CollectMemberLookupResults(
368 getSema().Context.getTranslationUnitDecl(),
369 NextRank + 1, Results);
370 } else {
371 // Walk through the declarations in this Scope.
372 for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
373 D != DEnd; ++D) {
374 if (NamedDecl *ND = dyn_cast<NamedDecl>((Decl *)((*D).get())))
375 Results.MaybeAddResult(Result(ND, NextRank));
376 }
377
378 NextRank = NextRank + 1;
379 }
380
381 // Lookup names in the parent scope.
382 NextRank = CollectLookupResults(S->getParent(), NextRank, Results);
383 Results.ExitScope();
384
385 return NextRank;
386}
387
Douglas Gregor2436e712009-09-17 21:32:03 +0000388/// \brief Collect the results of searching for members within the given
389/// declaration context.
390///
391/// \param Ctx the declaration context from which we will gather results.
392///
Douglas Gregorf45b0cf2009-09-18 15:37:17 +0000393/// \param InitialRank the initial rank given to results in this declaration
394/// context. Larger rank values will be used for, e.g., members found in
395/// base classes.
Douglas Gregor2436e712009-09-17 21:32:03 +0000396///
397/// \param Results the result set that will be extended with any results
398/// found within this declaration context (and, for a C++ class, its bases).
399///
400/// \returns the next higher rank value, after considering all of the
401/// names within this declaration context.
Douglas Gregorf45b0cf2009-09-18 15:37:17 +0000402unsigned CodeCompleteConsumer::CollectMemberLookupResults(DeclContext *Ctx,
Douglas Gregor2ecab752009-09-18 18:07:23 +0000403 unsigned InitialRank,
Douglas Gregorf45b0cf2009-09-18 15:37:17 +0000404 ResultSet &Results) {
Douglas Gregor2ecab752009-09-18 18:07:23 +0000405 llvm::SmallPtrSet<DeclContext *, 16> Visited;
406 return CollectMemberLookupResults(Ctx, InitialRank, Visited, Results);
407}
408
409/// \brief Collect the results of searching for members within the given
410/// declaration context.
411///
412/// \param Ctx the declaration context from which we will gather results.
413///
414/// \param InitialRank the initial rank given to results in this declaration
415/// context. Larger rank values will be used for, e.g., members found in
416/// base classes.
417///
418/// \param Visited the set of declaration contexts that have already been
419/// visited. Declaration contexts will only be visited once.
420///
421/// \param Results the result set that will be extended with any results
422/// found within this declaration context (and, for a C++ class, its bases).
423///
424/// \returns the next higher rank value, after considering all of the
425/// names within this declaration context.
426unsigned CodeCompleteConsumer::CollectMemberLookupResults(DeclContext *Ctx,
427 unsigned InitialRank,
428 llvm::SmallPtrSet<DeclContext *, 16> &Visited,
429 ResultSet &Results) {
430 // Make sure we don't visit the same context twice.
431 if (!Visited.insert(Ctx->getPrimaryContext()))
432 return InitialRank;
433
Douglas Gregor2436e712009-09-17 21:32:03 +0000434 // Enumerate all of the results in this context.
435 Results.EnterNewScope();
436 for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx;
437 CurCtx = CurCtx->getNextContext()) {
438 for (DeclContext::decl_iterator D = CurCtx->decls_begin(),
439 DEnd = CurCtx->decls_end();
440 D != DEnd; ++D) {
Douglas Gregorf45b0cf2009-09-18 15:37:17 +0000441 if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
Douglas Gregor2436e712009-09-17 21:32:03 +0000442 Results.MaybeAddResult(Result(ND, InitialRank));
Douglas Gregor2436e712009-09-17 21:32:03 +0000443 }
444 }
445
446 // Traverse the contexts of inherited classes.
447 unsigned NextRank = InitialRank;
448 if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
449 for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(),
450 BEnd = Record->bases_end();
451 B != BEnd; ++B) {
452 QualType BaseType = B->getType();
453
454 // Don't look into dependent bases, because name lookup can't look
455 // there anyway.
456 if (BaseType->isDependentType())
457 continue;
458
459 const RecordType *Record = BaseType->getAs<RecordType>();
460 if (!Record)
461 continue;
462
Douglas Gregor2436e712009-09-17 21:32:03 +0000463 // FIXME: It would be nice to be able to determine whether referencing
464 // a particular member would be ambiguous. For example, given
465 //
466 // struct A { int member; };
467 // struct B { int member; };
468 // struct C : A, B { };
469 //
470 // void f(C *c) { c->### }
471 // accessing 'member' would result in an ambiguity. However, code
472 // completion could be smart enough to qualify the member with the
473 // base class, e.g.,
474 //
475 // c->B::member
476 //
477 // or
478 //
479 // c->A::member
480
481 // Collect results from this base class (and its bases).
482 NextRank = std::max(NextRank,
Douglas Gregorf45b0cf2009-09-18 15:37:17 +0000483 CollectMemberLookupResults(Record->getDecl(),
Douglas Gregor2ecab752009-09-18 18:07:23 +0000484 InitialRank + 1,
485 Visited,
Douglas Gregorf45b0cf2009-09-18 15:37:17 +0000486 Results));
Douglas Gregor2436e712009-09-17 21:32:03 +0000487 }
488 }
489
490 // FIXME: Look into base classes in Objective-C!
491
492 Results.ExitScope();
493 return NextRank;
494}
495
Douglas Gregorf45b0cf2009-09-18 15:37:17 +0000496/// \brief Determines whether the given declaration is suitable as the
497/// start of a C++ nested-name-specifier, e.g., a class or namespace.
498bool CodeCompleteConsumer::IsNestedNameSpecifier(NamedDecl *ND) const {
499 // Allow us to find class templates, too.
500 if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
501 ND = ClassTemplate->getTemplatedDecl();
502
503 return getSema().isAcceptableNestedNameSpecifier(ND);
504}
505
506/// \brief Determines whether the given declaration is an enumeration.
507bool CodeCompleteConsumer::IsEnum(NamedDecl *ND) const {
508 return isa<EnumDecl>(ND);
509}
510
511/// \brief Determines whether the given declaration is a class or struct.
512bool CodeCompleteConsumer::IsClassOrStruct(NamedDecl *ND) const {
513 // Allow us to find class templates, too.
514 if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
515 ND = ClassTemplate->getTemplatedDecl();
516
517 if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
518 return RD->getTagKind() == TagDecl::TK_class ||
519 RD->getTagKind() == TagDecl::TK_struct;
520
521 return false;
522}
523
524/// \brief Determines whether the given declaration is a union.
525bool CodeCompleteConsumer::IsUnion(NamedDecl *ND) const {
526 // Allow us to find class templates, too.
527 if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
528 ND = ClassTemplate->getTemplatedDecl();
529
530 if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
531 return RD->getTagKind() == TagDecl::TK_union;
532
533 return false;
534}
535
Douglas Gregor7e90c6d2009-09-18 19:03:04 +0000536/// \brief Determines whether the given declaration is a namespace.
537bool CodeCompleteConsumer::IsNamespace(NamedDecl *ND) const {
538 return isa<NamespaceDecl>(ND);
539}
540
541/// \brief Determines whether the given declaration is a namespace or
542/// namespace alias.
543bool CodeCompleteConsumer::IsNamespaceOrAlias(NamedDecl *ND) const {
544 return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
545}
546
Douglas Gregorc811ede2009-09-18 20:05:18 +0000547/// \brief Brief determines whether the given declaration is a namespace or
548/// namespace alias.
549bool CodeCompleteConsumer::IsType(NamedDecl *ND) const {
550 return isa<TypeDecl>(ND);
551}
552
Douglas Gregor2436e712009-09-17 21:32:03 +0000553namespace {
554 struct VISIBILITY_HIDDEN SortCodeCompleteResult {
555 typedef CodeCompleteConsumer::Result Result;
556
557 bool operator()(const Result &X, const Result &Y) const {
558 // Sort first by rank.
559 if (X.Rank < Y.Rank)
560 return true;
561 else if (X.Rank > Y.Rank)
562 return false;
563
564 // Result kinds are ordered by decreasing importance.
565 if (X.Kind < Y.Kind)
566 return true;
567 else if (X.Kind > Y.Kind)
568 return false;
569
570 // Non-hidden names precede hidden names.
571 if (X.Hidden != Y.Hidden)
572 return !X.Hidden;
573
574 // Ordering depends on the kind of result.
575 switch (X.Kind) {
576 case Result::RK_Declaration:
577 // Order based on the declaration names.
578 return X.Declaration->getDeclName() < Y.Declaration->getDeclName();
579
580 case Result::RK_Keyword:
581 return strcmp(X.Keyword, Y.Keyword) == -1;
582 }
583
584 // If only our C++ compiler did control-flow warnings properly.
585 return false;
586 }
587 };
588}
589
Douglas Gregor2da11082009-09-18 15:51:54 +0000590/// \brief Determines whether the given hidden result could be found with
591/// some extra work, e.g., by qualifying the name.
592///
593/// \param Hidden the declaration that is hidden by the currenly \p Visible
594/// declaration.
595///
596/// \param Visible the declaration with the same name that is already visible.
597///
598/// \returns true if the hidden result can be found by some mechanism,
599/// false otherwise.
600bool CodeCompleteConsumer::canHiddenResultBeFound(NamedDecl *Hidden,
601 NamedDecl *Visible) {
602 // In C, there is no way to refer to a hidden name.
603 if (!getSema().getLangOptions().CPlusPlus)
604 return false;
605
606 DeclContext *HiddenCtx = Hidden->getDeclContext()->getLookupContext();
607
608 // There is no way to qualify a name declared in a function or method.
609 if (HiddenCtx->isFunctionOrMethod())
610 return false;
611
612 // If the hidden and visible declarations are in different name-lookup
613 // contexts, then we can qualify the name of the hidden declaration.
614 // FIXME: Optionally compute the string needed to refer to the hidden
615 // name.
616 return HiddenCtx != Visible->getDeclContext()->getLookupContext();
617}
618
Douglas Gregorc811ede2009-09-18 20:05:18 +0000619/// \brief Add type specifiers for the current language as keyword results.
620void CodeCompleteConsumer::AddTypeSpecifierResults(unsigned Rank,
621 ResultSet &Results) {
622 Results.MaybeAddResult(Result("short", Rank));
623 Results.MaybeAddResult(Result("long", Rank));
624 Results.MaybeAddResult(Result("signed", Rank));
625 Results.MaybeAddResult(Result("unsigned", Rank));
626 Results.MaybeAddResult(Result("void", Rank));
627 Results.MaybeAddResult(Result("char", Rank));
628 Results.MaybeAddResult(Result("int", Rank));
629 Results.MaybeAddResult(Result("float", Rank));
630 Results.MaybeAddResult(Result("double", Rank));
631 Results.MaybeAddResult(Result("enum", Rank));
632 Results.MaybeAddResult(Result("struct", Rank));
633 Results.MaybeAddResult(Result("union", Rank));
634
635 if (getSema().getLangOptions().C99) {
636 // C99-specific
637 Results.MaybeAddResult(Result("_Complex", Rank));
638 Results.MaybeAddResult(Result("_Imaginary", Rank));
639 Results.MaybeAddResult(Result("_Bool", Rank));
640 }
641
642 if (getSema().getLangOptions().CPlusPlus) {
643 // C++-specific
644 Results.MaybeAddResult(Result("bool", Rank));
645 Results.MaybeAddResult(Result("class", Rank));
646 Results.MaybeAddResult(Result("typename", Rank));
647 Results.MaybeAddResult(Result("wchar_t", Rank));
648
649 if (getSema().getLangOptions().CPlusPlus0x) {
650 Results.MaybeAddResult(Result("char16_t", Rank));
651 Results.MaybeAddResult(Result("char32_t", Rank));
652 Results.MaybeAddResult(Result("decltype", Rank));
653 }
654 }
655
656 // GNU extensions
657 if (getSema().getLangOptions().GNUMode) {
658 // FIXME: Enable when we actually support decimal floating point.
659 // Results.MaybeAddResult(Result("_Decimal32", Rank));
660 // Results.MaybeAddResult(Result("_Decimal64", Rank));
661 // Results.MaybeAddResult(Result("_Decimal128", Rank));
662 Results.MaybeAddResult(Result("typeof", Rank));
663 }
664}
665
Douglas Gregor2436e712009-09-17 21:32:03 +0000666void
667PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results,
668 unsigned NumResults) {
669 // Sort the results by rank/kind/etc.
670 std::stable_sort(Results, Results + NumResults, SortCodeCompleteResult());
671
672 // Print the results.
673 for (unsigned I = 0; I != NumResults; ++I) {
674 switch (Results[I].Kind) {
675 case Result::RK_Declaration:
676 OS << Results[I].Declaration->getNameAsString() << " : "
677 << Results[I].Rank;
678 if (Results[I].Hidden)
679 OS << " (Hidden)";
680 OS << '\n';
681 break;
682
683 case Result::RK_Keyword:
684 OS << Results[I].Keyword << " : " << Results[I].Rank << '\n';
685 break;
686 }
687 }
688
689 // Once we've printed the code-completion results, suppress remaining
690 // diagnostics.
691 // FIXME: Move this somewhere else!
692 getSema().PP.getDiagnostics().setSuppressAllDiagnostics();
693}