diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-08-26 15:07:07 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-08-26 15:07:07 +0000 |
commit | 458433d2f0f5c96a9e0d21decdd44bebccf20b11 (patch) | |
tree | 794359d35a7e2ddc77c732b524ab73c367639c6a /lib | |
parent | 9a2d44c5fbc46ce9ee6dd829a7bac8ca750ad090 (diff) |
Implement code completion for @selector expressions
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112186 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Frontend/ASTUnit.cpp | 1 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 18 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 81 |
3 files changed, 89 insertions, 11 deletions
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 874fd012b3..851c6669fe 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -1554,6 +1554,7 @@ void CalculateHiddenNames(const CodeCompletionContext &Context, case CodeCompletionContext::CCC_PreprocessorExpression: case CodeCompletionContext::CCC_PreprocessorDirective: case CodeCompletionContext::CCC_NaturalLanguage: + case CodeCompletionContext::CCC_SelectorName: // We're looking for nothing, or we're looking for names that cannot // be hidden. return; diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 1b09b1fe84..4b65652011 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -2194,6 +2194,15 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { llvm::SmallVector<IdentifierInfo *, 12> KeyIdents; SourceLocation LParenLoc = ConsumeParen(); SourceLocation sLoc; + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents.data(), + KeyIdents.size()); + ConsumeCodeCompletionToken(); + MatchRHSPunctuation(tok::r_paren, LParenLoc); + return ExprError(); + } + IdentifierInfo *SelIdent = ParseObjCSelectorPiece(sLoc); if (!SelIdent && Tok.isNot(tok::colon)) // missing selector name. return ExprError(Diag(Tok, diag::err_expected_ident)); @@ -2209,6 +2218,15 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { ConsumeToken(); // Eat the ':'. if (Tok.is(tok::r_paren)) break; + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents.data(), + KeyIdents.size()); + ConsumeCodeCompletionToken(); + MatchRHSPunctuation(tok::r_paren, LParenLoc); + return ExprError(); + } + // Check for another keyword selector. SourceLocation Loc; SelIdent = ParseObjCSelectorPiece(Loc); diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index d61ddcdf75..b75a7d05bb 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -25,6 +25,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" #include <list> #include <map> #include <vector> @@ -3401,26 +3402,33 @@ enum ObjCMethodKind { MK_OneArgSelector //< One-argument selector. }; -static bool isAcceptableObjCMethod(ObjCMethodDecl *Method, - ObjCMethodKind WantKind, - IdentifierInfo **SelIdents, - unsigned NumSelIdents) { - Selector Sel = Method->getSelector(); +static bool isAcceptableObjCSelector(Selector Sel, + ObjCMethodKind WantKind, + IdentifierInfo **SelIdents, + unsigned NumSelIdents) { 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; + 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; } + +static bool isAcceptableObjCMethod(ObjCMethodDecl *Method, + ObjCMethodKind WantKind, + IdentifierInfo **SelIdents, + unsigned NumSelIdents) { + return isAcceptableObjCSelector(Method->getSelector(), WantKind, SelIdents, + NumSelIdents); +} /// \brief Add all of the Objective-C methods in the given Objective-C /// container to the set of results. @@ -3979,6 +3987,57 @@ void Sema::CodeCompleteObjCForCollection(Scope *S, CodeCompleteExpression(S, Data); } +void Sema::CodeCompleteObjCSelector(Scope *S, IdentifierInfo **SelIdents, + unsigned NumSelIdents) { + // If we have an external source, load the entire class method + // pool from the AST file. + if (ExternalSource) { + for (uint32_t I = 0, N = ExternalSource->GetNumExternalSelectors(); + I != N; ++I) { + Selector Sel = ExternalSource->GetExternalSelector(I); + if (Sel.isNull() || MethodPool.count(Sel)) + continue; + + ReadMethodPool(Sel); + } + } + + ResultBuilder Results(*this); + Results.EnterNewScope(); + for (GlobalMethodPool::iterator M = MethodPool.begin(), + MEnd = MethodPool.end(); + M != MEnd; ++M) { + + Selector Sel = M->first; + if (!isAcceptableObjCSelector(Sel, MK_Any, SelIdents, NumSelIdents)) + continue; + + CodeCompletionString *Pattern = new CodeCompletionString; + if (Sel.isUnarySelector()) { + Pattern->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName()); + Results.AddResult(Pattern); + continue; + } + + for (unsigned I = 0, N = Sel.getNumArgs(); I != N; ++I) { + std::string Piece = Sel.getIdentifierInfoForSlot(I)->getName().str(); + Piece += ':'; + if (I < NumSelIdents) + Pattern->AddInformativeChunk(Piece); + else if (I == NumSelIdents) + Pattern->AddTypedTextChunk(Piece); + else + Pattern->AddTextChunk(Piece); + } + Results.AddResult(Pattern); + } + Results.ExitScope(); + + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_SelectorName, + Results.data(), Results.size()); +} + /// \brief Add all of the protocol declarations that we find in the given /// (translation unit) context. static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext, |