зеркало из https://github.com/microsoft/clang-1.git
Objective-C code completion within properties after "setter = " or
"getter = ", to provide suitable method names. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89334 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
217acbfa35
Коммит
4ad9685b3e
|
@ -2330,7 +2330,45 @@ public:
|
|||
///
|
||||
/// \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.
|
||||
///
|
||||
|
|
|
@ -810,7 +810,8 @@ private:
|
|||
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();
|
||||
|
||||
|
|
|
@ -270,7 +270,11 @@ public:
|
|||
/// \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 @@ public:
|
|||
: 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 {
|
||||
|
|
|
@ -326,7 +326,8 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
|
|||
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 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
|
|||
/// 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 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
|
|||
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);
|
||||
|
|
|
@ -3647,6 +3647,13 @@ public:
|
|||
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,
|
||||
|
|
|
@ -967,7 +967,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
|
|||
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 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
|
|||
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 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
|
|||
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 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
|
|||
/// \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 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
|
|||
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 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
|
|||
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 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
|
|||
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 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName,
|
|||
// 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 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
|
|||
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 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
|
|||
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();
|
||||
|
|
Загрузка…
Ссылка в новой задаче