[cfe-commits] r89334 - in /cfe/trunk: include/clang/Parse/Action.h include/clang/Parse/Parser.h include/clang/Sema/CodeCompleteConsumer.h lib/Parse/ParseObjc.cpp lib/Sema/Sema.h lib/Sema/SemaCodeComplete.cpp
Douglas Gregor
dgregor at apple.com
Wed Nov 18 23:41:16 PST 2009
Author: dgregor
Date: Thu Nov 19 01:41:15 2009
New Revision: 89334
URL: http://llvm.org/viewvc/llvm-project?rev=89334&view=rev
Log:
Objective-C code completion within properties after "setter = " or
"getter = ", to provide suitable method names.
Modified:
cfe/trunk/include/clang/Parse/Action.h
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h
cfe/trunk/lib/Parse/ParseObjc.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaCodeComplete.cpp
Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=89334&r1=89333&r2=89334&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Thu Nov 19 01:41:15 2009
@@ -2330,7 +2330,45 @@
///
/// \param S the scope in which the operator keyword occurs.
virtual void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { }
-
+
+ /// \brief Code completion for the getter of an Objective-C property
+ /// declaration.
+ ///
+ /// This code completion action is invoked when the code-completion
+ /// token is found after the "getter = " in a property declaration.
+ ///
+ /// \param S the scope in which the property is being declared.
+ ///
+ /// \param ClassDecl the Objective-C class or category in which the property
+ /// is being defined.
+ ///
+ /// \param Methods the set of methods declared thus far within \p ClassDecl.
+ ///
+ /// \param NumMethods the number of methods in \p Methods
+ virtual void CodeCompleteObjCPropertyGetter(Scope *S, DeclPtrTy ClassDecl,
+ DeclPtrTy *Methods,
+ unsigned NumMethods) {
+ }
+
+ /// \brief Code completion for the setter of an Objective-C property
+ /// declaration.
+ ///
+ /// This code completion action is invoked when the code-completion
+ /// token is found after the "setter = " in a property declaration.
+ ///
+ /// \param S the scope in which the property is being declared.
+ ///
+ /// \param ClassDecl the Objective-C class or category in which the property
+ /// is being defined.
+ ///
+ /// \param Methods the set of methods declared thus far within \p ClassDecl.
+ ///
+ /// \param NumMethods the number of methods in \p Methods
+ virtual void CodeCompleteObjCPropertySetter(Scope *S, DeclPtrTy ClassDecl,
+ DeclPtrTy *Methods,
+ unsigned NumMethods) {
+ }
+
/// \brief Code completion for an ObjC message expression that refers to
/// a class method.
///
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=89334&r1=89333&r2=89334&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Thu Nov 19 01:41:15 2009
@@ -810,7 +810,8 @@
DeclPtrTy ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType,
DeclPtrTy classDecl,
tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword);
- void ParseObjCPropertyAttribute(ObjCDeclSpec &DS);
+ void ParseObjCPropertyAttribute(ObjCDeclSpec &DS, DeclPtrTy ClassDecl,
+ DeclPtrTy *Methods, unsigned NumMethods);
DeclPtrTy ParseObjCMethodDefinition();
Modified: cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h?rev=89334&r1=89333&r2=89334&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h (original)
+++ cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h Thu Nov 19 01:41:15 2009
@@ -270,7 +270,11 @@
/// \brief Whether this declaration is the beginning of a
/// nested-name-specifier and, therefore, should be followed by '::'.
bool StartsNestedNameSpecifier : 1;
-
+
+ /// \brief Whether all parameters (of a function, Objective-C
+ /// method, etc.) should be considered "informative".
+ bool AllParametersAreInformative : 1;
+
/// \brief If the result should have a nested-name-specifier, this is it.
/// When \c QualifierIsInformative, the nested-name-specifier is
/// informative rather than required.
@@ -283,25 +287,29 @@
: Kind(RK_Declaration), Declaration(Declaration), Rank(Rank),
StartParameter(0), Hidden(false),
QualifierIsInformative(QualifierIsInformative),
- StartsNestedNameSpecifier(false), Qualifier(Qualifier) { }
+ StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
+ Qualifier(Qualifier) { }
/// \brief Build a result that refers to a keyword or symbol.
Result(const char *Keyword, unsigned Rank)
: Kind(RK_Keyword), Keyword(Keyword), Rank(Rank), StartParameter(0),
Hidden(false), QualifierIsInformative(0),
- StartsNestedNameSpecifier(false), Qualifier(0) { }
+ StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
+ Qualifier(0) { }
/// \brief Build a result that refers to a macro.
Result(IdentifierInfo *Macro, unsigned Rank)
: Kind(RK_Macro), Macro(Macro), Rank(Rank), StartParameter(0),
Hidden(false), QualifierIsInformative(0),
- StartsNestedNameSpecifier(false), Qualifier(0) { }
+ StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
+ Qualifier(0) { }
/// \brief Build a result that refers to a pattern.
Result(CodeCompletionString *Pattern, unsigned Rank)
: Kind(RK_Pattern), Pattern(Pattern), Rank(Rank), StartParameter(0),
Hidden(false), QualifierIsInformative(0),
- StartsNestedNameSpecifier(false), Qualifier(0) { }
+ StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
+ Qualifier(0) { }
/// \brief Retrieve the declaration stored in this result.
NamedDecl *getDeclaration() const {
Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=89334&r1=89333&r2=89334&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Thu Nov 19 01:41:15 2009
@@ -326,7 +326,8 @@
ObjCDeclSpec OCDS;
// Parse property attribute list, if any.
if (Tok.is(tok::l_paren))
- ParseObjCPropertyAttribute(OCDS);
+ ParseObjCPropertyAttribute(OCDS, interfaceDecl,
+ allMethods.data(), allMethods.size());
struct ObjCPropertyCallback : FieldCallback {
Parser &P;
@@ -425,7 +426,9 @@
/// copy
/// nonatomic
///
-void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
+void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, DeclPtrTy ClassDecl,
+ DeclPtrTy *Methods,
+ unsigned NumMethods) {
assert(Tok.getKind() == tok::l_paren);
SourceLocation LHSLoc = ConsumeParen(); // consume '('
@@ -462,6 +465,16 @@
tok::r_paren))
return;
+ if (Tok.is(tok::code_completion)) {
+ if (II->getNameStart()[0] == 's')
+ Actions.CodeCompleteObjCPropertySetter(CurScope, ClassDecl,
+ Methods, NumMethods);
+ else
+ Actions.CodeCompleteObjCPropertyGetter(CurScope, ClassDecl,
+ Methods, NumMethods);
+ ConsumeToken();
+ }
+
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
SkipUntil(tok::r_paren);
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=89334&r1=89333&r2=89334&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Nov 19 01:41:15 2009
@@ -3647,6 +3647,13 @@
virtual void CodeCompleteOperatorName(Scope *S);
virtual void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS);
+ virtual void CodeCompleteObjCPropertyGetter(Scope *S, DeclPtrTy ClassDecl,
+ DeclPtrTy *Methods,
+ unsigned NumMethods);
+ virtual void CodeCompleteObjCPropertySetter(Scope *S, DeclPtrTy ClassDecl,
+ DeclPtrTy *Methods,
+ unsigned NumMethods);
+
virtual void CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName,
SourceLocation FNameLoc,
IdentifierInfo **SelIdents,
Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=89334&r1=89333&r2=89334&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Thu Nov 19 01:41:15 2009
@@ -967,7 +967,7 @@
if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx))
Keyword += II->getName().str();
Keyword += ":";
- if (Idx < StartParameter) {
+ if (Idx < StartParameter || AllParametersAreInformative) {
Result->AddInformativeChunk(Keyword);
} else if (Idx == StartParameter)
Result->AddTypedTextChunk(Keyword);
@@ -984,7 +984,10 @@
Arg = "(" + Arg + ")";
if (IdentifierInfo *II = (*P)->getIdentifier())
Arg += II->getName().str();
- Result->AddPlaceholderChunk(Arg);
+ if (AllParametersAreInformative)
+ Result->AddInformativeChunk(Arg);
+ else
+ Result->AddPlaceholderChunk(Arg);
}
return Result;
@@ -1721,6 +1724,35 @@
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
+/// \brief Descripts the kind of Objective-C method that we want to find
+/// via code completion.
+enum ObjCMethodKind {
+ MK_Any, //< Any kind of method, provided it means other specified criteria.
+ MK_ZeroArgSelector, //< Zero-argument (unary) selector.
+ MK_OneArgSelector //< One-argument selector.
+};
+
+static bool isAcceptableObjCMethod(ObjCMethodDecl *Method,
+ ObjCMethodKind WantKind,
+ IdentifierInfo **SelIdents,
+ unsigned NumSelIdents) {
+ Selector Sel = Method->getSelector();
+ if (NumSelIdents > Sel.getNumArgs())
+ return false;
+
+ switch (WantKind) {
+ case MK_Any: break;
+ case MK_ZeroArgSelector: return Sel.isUnarySelector();
+ case MK_OneArgSelector: return Sel.getNumArgs() == 1;
+ }
+
+ for (unsigned I = 0; I != NumSelIdents; ++I)
+ if (SelIdents[I] != Sel.getIdentifierInfoForSlot(I))
+ return false;
+
+ return true;
+}
+
/// \brief Add all of the Objective-C methods in the given Objective-C
/// container to the set of results.
///
@@ -1740,6 +1772,7 @@
/// \param Results the structure into which we'll add results.
static void AddObjCMethods(ObjCContainerDecl *Container,
bool WantInstanceMethods,
+ ObjCMethodKind WantKind,
IdentifierInfo **SelIdents,
unsigned NumSelIdents,
DeclContext *CurContext,
@@ -1751,20 +1784,12 @@
if ((*M)->isInstanceMethod() == WantInstanceMethods) {
// Check whether the selector identifiers we've been given are a
// subset of the identifiers for this particular method.
- Selector Sel = (*M)->getSelector();
- if (NumSelIdents > Sel.getNumArgs())
+ if (!isAcceptableObjCMethod(*M, WantKind, SelIdents, NumSelIdents))
continue;
-
- bool Failed = false;
- for (unsigned I = 0; I != NumSelIdents && !Failed; ++I)
- if (SelIdents[I] != Sel.getIdentifierInfoForSlot(I))
- Failed = true;
-
- if (Failed)
- continue;
-
+
Result R = Result(*M, 0);
R.StartParameter = NumSelIdents;
+ R.AllParametersAreInformative = (WantKind != MK_Any);
Results.MaybeAddResult(R, CurContext);
}
}
@@ -1778,14 +1803,14 @@
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
E = Protocols.end();
I != E; ++I)
- AddObjCMethods(*I, WantInstanceMethods, SelIdents, NumSelIdents,
+ AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, NumSelIdents,
CurContext, Results);
// Add methods in categories.
for (ObjCCategoryDecl *CatDecl = IFace->getCategoryList(); CatDecl;
CatDecl = CatDecl->getNextClassCategory()) {
- AddObjCMethods(CatDecl, WantInstanceMethods, SelIdents, NumSelIdents,
- CurContext, Results);
+ AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents,
+ NumSelIdents, CurContext, Results);
// Add a categories protocol methods.
const ObjCList<ObjCProtocolDecl> &Protocols
@@ -1793,24 +1818,104 @@
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
E = Protocols.end();
I != E; ++I)
- AddObjCMethods(*I, WantInstanceMethods, SelIdents, NumSelIdents,
- CurContext, Results);
+ AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents,
+ NumSelIdents, CurContext, Results);
// Add methods in category implementations.
if (ObjCCategoryImplDecl *Impl = CatDecl->getImplementation())
- AddObjCMethods(Impl, WantInstanceMethods, SelIdents, NumSelIdents,
- CurContext, Results);
+ AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents,
+ NumSelIdents, CurContext, Results);
}
// Add methods in superclass.
if (IFace->getSuperClass())
- AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, SelIdents,
- NumSelIdents, CurContext,Results);
+ AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, WantKind,
+ SelIdents, NumSelIdents, CurContext, Results);
// Add methods in our implementation, if any.
if (ObjCImplementationDecl *Impl = IFace->getImplementation())
- AddObjCMethods(Impl, WantInstanceMethods, SelIdents, NumSelIdents,
- CurContext, Results);
+ AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents,
+ NumSelIdents, CurContext, Results);
+}
+
+
+void Sema::CodeCompleteObjCPropertyGetter(Scope *S, DeclPtrTy ClassDecl,
+ DeclPtrTy *Methods,
+ unsigned NumMethods) {
+ typedef CodeCompleteConsumer::Result Result;
+
+ // Try to find the interface where getters might live.
+ ObjCInterfaceDecl *Class
+ = dyn_cast_or_null<ObjCInterfaceDecl>(ClassDecl.getAs<Decl>());
+ if (!Class) {
+ if (ObjCCategoryDecl *Category
+ = dyn_cast_or_null<ObjCCategoryDecl>(ClassDecl.getAs<Decl>()))
+ Class = Category->getClassInterface();
+
+ if (!Class)
+ return;
+ }
+
+ // Find all of the potential getters.
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+
+ // FIXME: We need to do this because Objective-C methods don't get
+ // pushed into DeclContexts early enough. Argh!
+ for (unsigned I = 0; I != NumMethods; ++I) {
+ if (ObjCMethodDecl *Method
+ = dyn_cast_or_null<ObjCMethodDecl>(Methods[I].getAs<Decl>()))
+ if (Method->isInstanceMethod() &&
+ isAcceptableObjCMethod(Method, MK_ZeroArgSelector, 0, 0)) {
+ Result R = Result(Method, 0);
+ R.AllParametersAreInformative = true;
+ Results.MaybeAddResult(R, CurContext);
+ }
+ }
+
+ AddObjCMethods(Class, true, MK_ZeroArgSelector, 0, 0, CurContext, Results);
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter,Results.data(),Results.size());
+}
+
+void Sema::CodeCompleteObjCPropertySetter(Scope *S, DeclPtrTy ObjCImplDecl,
+ DeclPtrTy *Methods,
+ unsigned NumMethods) {
+ typedef CodeCompleteConsumer::Result Result;
+
+ // Try to find the interface where setters might live.
+ ObjCInterfaceDecl *Class
+ = dyn_cast_or_null<ObjCInterfaceDecl>(ObjCImplDecl.getAs<Decl>());
+ if (!Class) {
+ if (ObjCCategoryDecl *Category
+ = dyn_cast_or_null<ObjCCategoryDecl>(ObjCImplDecl.getAs<Decl>()))
+ Class = Category->getClassInterface();
+
+ if (!Class)
+ return;
+ }
+
+ // Find all of the potential getters.
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+
+ // FIXME: We need to do this because Objective-C methods don't get
+ // pushed into DeclContexts early enough. Argh!
+ for (unsigned I = 0; I != NumMethods; ++I) {
+ if (ObjCMethodDecl *Method
+ = dyn_cast_or_null<ObjCMethodDecl>(Methods[I].getAs<Decl>()))
+ if (Method->isInstanceMethod() &&
+ isAcceptableObjCMethod(Method, MK_OneArgSelector, 0, 0)) {
+ Result R = Result(Method, 0);
+ R.AllParametersAreInformative = true;
+ Results.MaybeAddResult(R, CurContext);
+ }
+ }
+
+ AddObjCMethods(Class, true, MK_OneArgSelector, 0, 0, CurContext, Results);
+
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter,Results.data(),Results.size());
}
void Sema::CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName,
@@ -1873,7 +1978,8 @@
// superclasses, categories, implementation, etc.
ResultBuilder Results(*this);
Results.EnterNewScope();
- AddObjCMethods(CDecl, false, SelIdents, NumSelIdents, CurContext, Results);
+ AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, CurContext,
+ Results);
Results.ExitScope();
// This also suppresses remaining diagnostics.
@@ -1910,8 +2016,8 @@
ReceiverType->isObjCQualifiedClassType()) {
if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) {
if (ObjCInterfaceDecl *ClassDecl = CurMethod->getClassInterface())
- AddObjCMethods(ClassDecl, false, SelIdents, NumSelIdents, CurContext,
- Results);
+ AddObjCMethods(ClassDecl, false, MK_Any, SelIdents, NumSelIdents,
+ CurContext, Results);
}
}
// Handle messages to a qualified ID ("id<foo>").
@@ -1921,20 +2027,22 @@
for (ObjCObjectPointerType::qual_iterator I = QualID->qual_begin(),
E = QualID->qual_end();
I != E; ++I)
- AddObjCMethods(*I, true, SelIdents, NumSelIdents, CurContext, Results);
+ AddObjCMethods(*I, true, MK_Any, SelIdents, NumSelIdents, CurContext,
+ Results);
}
// Handle messages to a pointer to interface type.
else if (const ObjCObjectPointerType *IFacePtr
= ReceiverType->getAsObjCInterfacePointerType()) {
// Search the class, its superclasses, etc., for instance methods.
- AddObjCMethods(IFacePtr->getInterfaceDecl(), true, SelIdents, NumSelIdents,
- CurContext, Results);
+ AddObjCMethods(IFacePtr->getInterfaceDecl(), true, MK_Any, SelIdents,
+ NumSelIdents, CurContext, Results);
// Search protocols for instance methods.
for (ObjCObjectPointerType::qual_iterator I = IFacePtr->qual_begin(),
E = IFacePtr->qual_end();
I != E; ++I)
- AddObjCMethods(*I, true, SelIdents, NumSelIdents, CurContext, Results);
+ AddObjCMethods(*I, true, MK_Any, SelIdents, NumSelIdents, CurContext,
+ Results);
}
Results.ExitScope();
More information about the cfe-commits
mailing list