Introduce a new libclang API to determine the parent context of a code
completion item. For example, if the code completion itself represents
a declaration in a namespace (say, std::vector), then this API
retrieves the cursor kind and name of the namespace (std). Implements
<rdar://problem/11121951>.
llvm-svn: 153545
diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp
index caebe3a..dbc9b00 100644
--- a/clang/lib/Sema/CodeCompleteConsumer.cpp
+++ b/clang/lib/Sema/CodeCompleteConsumer.cpp
@@ -192,9 +192,12 @@
unsigned Priority,
CXAvailabilityKind Availability,
const char **Annotations,
- unsigned NumAnnotations)
- : NumChunks(NumChunks), NumAnnotations(NumAnnotations)
- , Priority(Priority), Availability(Availability)
+ unsigned NumAnnotations,
+ CXCursorKind ParentKind,
+ StringRef ParentName)
+ : NumChunks(NumChunks), NumAnnotations(NumAnnotations),
+ Priority(Priority), Availability(Availability), ParentKind(ParentKind),
+ ParentName(ParentName)
{
assert(NumChunks <= 0xffff);
assert(NumAnnotations <= 0xffff);
@@ -272,7 +275,8 @@
CodeCompletionString *Result
= new (Mem) CodeCompletionString(Chunks.data(), Chunks.size(),
Priority, Availability,
- Annotations.data(), Annotations.size());
+ Annotations.data(), Annotations.size(),
+ ParentKind, ParentName);
Chunks.clear();
return Result;
}
@@ -311,6 +315,70 @@
Chunks.push_back(Chunk(CK, Text));
}
+void CodeCompletionBuilder::addParentContext(DeclContext *DC) {
+ if (DC->isTranslationUnit()) {
+ ParentKind = CXCursor_TranslationUnit;
+ return;
+ }
+
+ if (DC->isFunctionOrMethod())
+ return;
+
+ NamedDecl *ND = dyn_cast<NamedDecl>(DC);
+ if (!ND)
+ return;
+
+ ParentKind = getCursorKindForDecl(ND);
+
+ // Check whether we've already cached the parent name.
+ StringRef &CachedParentName = Allocator.getParentNames()[DC];
+ if (!CachedParentName.empty()) {
+ ParentName = CachedParentName;
+ return;
+ }
+
+ // Find the interesting names.
+ llvm::SmallVector<DeclContext *, 2> Contexts;
+ while (DC && !DC->isFunctionOrMethod()) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(DC)) {
+ if (ND->getIdentifier())
+ Contexts.push_back(DC);
+ }
+
+ DC = DC->getParent();
+ }
+
+ {
+ llvm::SmallString<128> S;
+ llvm::raw_svector_ostream OS(S);
+ bool First = true;
+ for (unsigned I = Contexts.size(); I != 0; --I) {
+ if (First)
+ First = false;
+ else {
+ OS << "::";
+ }
+
+ DeclContext *CurDC = Contexts[I-1];
+ if (ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(CurDC))
+ CurDC = CatImpl->getCategoryDecl();
+
+ if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(CurDC)) {
+ ObjCInterfaceDecl *Interface = Cat->getClassInterface();
+ if (!Interface)
+ return;
+
+ OS << Interface->getName() << '(' << Cat->getName() << ')';
+ } else {
+ OS << cast<NamedDecl>(CurDC)->getName();
+ }
+ }
+
+ ParentName = Allocator.CopyString(OS.str());
+ CachedParentName = ParentName;
+ }
+}
+
unsigned CodeCompletionResult::getPriorityFromDecl(NamedDecl *ND) {
if (!ND)
return CCP_Unlikely;
@@ -444,6 +512,13 @@
void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) {
switch (Kind) {
+ case RK_Pattern:
+ if (!Declaration) {
+ // Do nothing: Patterns can come with cursor kinds!
+ break;
+ }
+ // Fall through
+
case RK_Declaration: {
// Set the availability based on attributes.
switch (getDeclAvailability(Declaration)) {
@@ -488,11 +563,7 @@
case RK_Keyword:
Availability = CXAvailability_Available;
CursorKind = CXCursor_NotImplemented;
- break;
-
- case RK_Pattern:
- // Do nothing: Patterns can come with cursor kinds!
- break;
+ break;
}
if (!Accessible)