aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-11-18 19:08:43 +0000
committerDouglas Gregor <dgregor@apple.com>2009-11-18 19:08:43 +0000
commit33ced0b8550f3e7169f326944731ee02e9338659 (patch)
treebf0f8e833f1101d048cec2758baff0e8c7c79e8a /lib
parent6d60ca9c5015a7e7eceab31bed24425aeb47db67 (diff)
Implement code completion for Objective-C category names in @interface
and @implementation declarations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89223 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/Parse/ParseObjc.cpp10
-rw-r--r--lib/Sema/Sema.h4
-rw-r--r--lib/Sema/SemaCodeComplete.cpp68
3 files changed, 81 insertions, 1 deletions
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index a60c89a0f1..e1f045bd8e 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -143,6 +143,11 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
SourceLocation categoryLoc, rparenLoc;
IdentifierInfo *categoryId = 0;
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteObjCInterfaceCategory(CurScope, nameId);
+ ConsumeToken();
+ }
+
// For ObjC2, the category name is optional (not an error).
if (Tok.is(tok::identifier)) {
categoryId = Tok.getIdentifierInfo();
@@ -1111,6 +1116,11 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
SourceLocation categoryLoc, rparenLoc;
IdentifierInfo *categoryId = 0;
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteObjCImplementationCategory(CurScope, nameId);
+ ConsumeToken();
+ }
+
if (Tok.is(tok::identifier)) {
categoryId = Tok.getIdentifierInfo();
categoryLoc = ConsumeToken();
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index abef317d62..a13ffc54da 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -3649,6 +3649,10 @@ public:
virtual void CodeCompleteObjCSuperclass(Scope *S,
IdentifierInfo *ClassName);
virtual void CodeCompleteObjCImplementationDecl(Scope *S);
+ virtual void CodeCompleteObjCInterfaceCategory(Scope *S,
+ IdentifierInfo *ClassName);
+ virtual void CodeCompleteObjCImplementationCategory(Scope *S,
+ IdentifierInfo *ClassName);
//@}
//===--------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index eaa4f1514a..93aa08c4da 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -1933,7 +1933,7 @@ void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName) {
// Make sure that we ignore the class we're currently defining.
NamedDecl *CurClass
= LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
- if (isa<ObjCInterfaceDecl>(CurClass))
+ if (CurClass && isa<ObjCInterfaceDecl>(CurClass))
Results.Ignore(CurClass);
// Add all classes.
@@ -1955,3 +1955,69 @@ void Sema::CodeCompleteObjCImplementationDecl(Scope *S) {
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
+
+void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
+ IdentifierInfo *ClassName) {
+ typedef CodeCompleteConsumer::Result Result;
+
+ ResultBuilder Results(*this);
+
+ // Ignore any categories we find that have already been implemented by this
+ // interface.
+ llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames;
+ NamedDecl *CurClass
+ = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
+ if (ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass))
+ for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category;
+ Category = Category->getNextClassCategory())
+ CategoryNames.insert(Category->getIdentifier());
+
+ // Add all of the categories we know about.
+ Results.EnterNewScope();
+ TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
+ for (DeclContext::decl_iterator D = TU->decls_begin(),
+ DEnd = TU->decls_end();
+ D != DEnd; ++D)
+ if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(*D))
+ if (CategoryNames.insert(Category->getIdentifier()))
+ Results.MaybeAddResult(Result(Category, 0), CurContext);
+ Results.ExitScope();
+
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}
+
+void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
+ IdentifierInfo *ClassName) {
+ typedef CodeCompleteConsumer::Result Result;
+
+ // Find the corresponding interface. If we couldn't find the interface, the
+ // program itself is ill-formed. However, we'll try to be helpful still by
+ // providing the list of all of the categories we know about.
+ NamedDecl *CurClass
+ = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
+ ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass);
+ if (!Class)
+ return CodeCompleteObjCInterfaceCategory(S, ClassName);
+
+ ResultBuilder Results(*this);
+
+ // Add all of the categories that have have corresponding interface
+ // declarations in this class and any of its superclasses, except for
+ // already-implemented categories in the class itself.
+ llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames;
+ Results.EnterNewScope();
+ bool IgnoreImplemented = true;
+ while (Class) {
+ for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category;
+ Category = Category->getNextClassCategory())
+ if ((!IgnoreImplemented || !Category->getImplementation()) &&
+ CategoryNames.insert(Category->getIdentifier()))
+ Results.MaybeAddResult(Result(Category, 0), CurContext);
+
+ Class = Class->getSuperClass();
+ IgnoreImplemented = false;
+ }
+ Results.ExitScope();
+
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}