summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaCodeComplete.cpp
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2009-12-15 18:49:47 +0000
committerrdivacky <rdivacky@FreeBSD.org>2009-12-15 18:49:47 +0000
commit77212133072dc40f070a280af8217032f55a9eb4 (patch)
tree2fd5819f49caecc5f520219b6b9254fe94ebb138 /lib/Sema/SemaCodeComplete.cpp
parent4b08eb6308ca90a6c08e2fc79d100821b1b1f6aa (diff)
downloadFreeBSD-src-77212133072dc40f070a280af8217032f55a9eb4.zip
FreeBSD-src-77212133072dc40f070a280af8217032f55a9eb4.tar.gz
Update clang to 91430.
Diffstat (limited to 'lib/Sema/SemaCodeComplete.cpp')
-rw-r--r--lib/Sema/SemaCodeComplete.cpp522
1 files changed, 479 insertions, 43 deletions
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index b386adb..4ce9330 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -45,11 +45,64 @@ namespace {
/// the result set twice.
llvm::SmallPtrSet<Decl*, 16> AllDeclsFound;
+ typedef std::pair<NamedDecl *, unsigned> DeclIndexPair;
+
+ /// \brief An entry in the shadow map, which is optimized to store
+ /// a single (declaration, index) mapping (the common case) but
+ /// can also store a list of (declaration, index) mappings.
+ class ShadowMapEntry {
+ typedef llvm::SmallVector<DeclIndexPair, 4> DeclIndexPairVector;
+
+ /// \brief Contains either the solitary NamedDecl * or a vector
+ /// of (declaration, index) pairs.
+ llvm::PointerUnion<NamedDecl *, DeclIndexPairVector*> DeclOrVector;
+
+ /// \brief When the entry contains a single declaration, this is
+ /// the index associated with that entry.
+ unsigned SingleDeclIndex;
+
+ public:
+ ShadowMapEntry() : DeclOrVector(), SingleDeclIndex(0) { }
+
+ void Add(NamedDecl *ND, unsigned Index) {
+ if (DeclOrVector.isNull()) {
+ // 0 - > 1 elements: just set the single element information.
+ DeclOrVector = ND;
+ SingleDeclIndex = Index;
+ return;
+ }
+
+ if (NamedDecl *PrevND = DeclOrVector.dyn_cast<NamedDecl *>()) {
+ // 1 -> 2 elements: create the vector of results and push in the
+ // existing declaration.
+ DeclIndexPairVector *Vec = new DeclIndexPairVector;
+ Vec->push_back(DeclIndexPair(PrevND, SingleDeclIndex));
+ DeclOrVector = Vec;
+ }
+
+ // Add the new element to the end of the vector.
+ DeclOrVector.get<DeclIndexPairVector*>()->push_back(
+ DeclIndexPair(ND, Index));
+ }
+
+ void Destroy() {
+ if (DeclIndexPairVector *Vec
+ = DeclOrVector.dyn_cast<DeclIndexPairVector *>()) {
+ delete Vec;
+ DeclOrVector = ((NamedDecl *)0);
+ }
+ }
+
+ // Iteration.
+ class iterator;
+ iterator begin() const;
+ iterator end() const;
+ };
+
/// \brief A mapping from declaration names to the declarations that have
/// this name within a particular scope and their index within the list of
/// results.
- typedef std::multimap<DeclarationName,
- std::pair<NamedDecl *, unsigned> > ShadowMap;
+ typedef llvm::DenseMap<DeclarationName, ShadowMapEntry> ShadowMap;
/// \brief The semantic analysis object for which results are being
/// produced.
@@ -117,6 +170,95 @@ namespace {
};
}
+class ResultBuilder::ShadowMapEntry::iterator {
+ llvm::PointerUnion<NamedDecl*, const DeclIndexPair*> DeclOrIterator;
+ unsigned SingleDeclIndex;
+
+public:
+ typedef DeclIndexPair value_type;
+ typedef value_type reference;
+ typedef std::ptrdiff_t difference_type;
+ typedef std::input_iterator_tag iterator_category;
+
+ class pointer {
+ DeclIndexPair Value;
+
+ public:
+ pointer(const DeclIndexPair &Value) : Value(Value) { }
+
+ const DeclIndexPair *operator->() const {
+ return &Value;
+ }
+ };
+
+ iterator() : DeclOrIterator((NamedDecl *)0), SingleDeclIndex(0) { }
+
+ iterator(NamedDecl *SingleDecl, unsigned Index)
+ : DeclOrIterator(SingleDecl), SingleDeclIndex(Index) { }
+
+ iterator(const DeclIndexPair *Iterator)
+ : DeclOrIterator(Iterator), SingleDeclIndex(0) { }
+
+ iterator &operator++() {
+ if (DeclOrIterator.is<NamedDecl *>()) {
+ DeclOrIterator = (NamedDecl *)0;
+ SingleDeclIndex = 0;
+ return *this;
+ }
+
+ const DeclIndexPair *I = DeclOrIterator.get<const DeclIndexPair*>();
+ ++I;
+ DeclOrIterator = I;
+ return *this;
+ }
+
+ iterator operator++(int) {
+ iterator tmp(*this);
+ ++(*this);
+ return tmp;
+ }
+
+ reference operator*() const {
+ if (NamedDecl *ND = DeclOrIterator.dyn_cast<NamedDecl *>())
+ return reference(ND, SingleDeclIndex);
+
+ return *DeclOrIterator.get<const DeclIndexPair*>();
+ }
+
+ pointer operator->() const {
+ return pointer(**this);
+ }
+
+ friend bool operator==(const iterator &X, const iterator &Y) {
+ return X.DeclOrIterator.getOpaqueValue()
+ == Y.DeclOrIterator.getOpaqueValue() &&
+ X.SingleDeclIndex == Y.SingleDeclIndex;
+ }
+
+ friend bool operator!=(const iterator &X, const iterator &Y) {
+ return !(X == Y);
+ }
+};
+
+ResultBuilder::ShadowMapEntry::iterator
+ResultBuilder::ShadowMapEntry::begin() const {
+ if (DeclOrVector.isNull())
+ return iterator();
+
+ if (NamedDecl *ND = DeclOrVector.dyn_cast<NamedDecl *>())
+ return iterator(ND, SingleDeclIndex);
+
+ return iterator(DeclOrVector.get<DeclIndexPairVector *>()->begin());
+}
+
+ResultBuilder::ShadowMapEntry::iterator
+ResultBuilder::ShadowMapEntry::end() const {
+ if (DeclOrVector.is<NamedDecl *>() || DeclOrVector.isNull())
+ return iterator();
+
+ return iterator(DeclOrVector.get<DeclIndexPairVector *>()->end());
+}
+
/// \brief Determines whether the given hidden result could be found with
/// some extra work, e.g., by qualifying the name.
///
@@ -214,7 +356,16 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
if (isa<FriendDecl>(CanonDecl) ||
(IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend)))
return;
+
+ // Class template (partial) specializations are never added as results.
+ if (isa<ClassTemplateSpecializationDecl>(CanonDecl) ||
+ isa<ClassTemplatePartialSpecializationDecl>(CanonDecl))
+ return;
+ // Using declarations themselves are never added as results.
+ if (isa<UsingDecl>(CanonDecl))
+ return;
+
if (const IdentifierInfo *Id = R.Declaration->getIdentifier()) {
// __va_list_tag is a freak of nature. Find it and skip it.
if (Id->isStr("__va_list_tag") || Id->isStr("__builtin_va_list"))
@@ -241,14 +392,18 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
return;
ShadowMap &SMap = ShadowMaps.back();
- ShadowMap::iterator I, IEnd;
- for (llvm::tie(I, IEnd) = SMap.equal_range(R.Declaration->getDeclName());
- I != IEnd; ++I) {
- NamedDecl *ND = I->second.first;
- unsigned Index = I->second.second;
+ ShadowMapEntry::iterator I, IEnd;
+ ShadowMap::iterator NamePos = SMap.find(R.Declaration->getDeclName());
+ if (NamePos != SMap.end()) {
+ I = NamePos->second.begin();
+ IEnd = NamePos->second.end();
+ }
+
+ for (; I != IEnd; ++I) {
+ NamedDecl *ND = I->first;
+ unsigned Index = I->second;
if (ND->getCanonicalDecl() == CanonDecl) {
// This is a redeclaration. Always pick the newer declaration.
- I->second.first = R.Declaration;
Results[Index].Declaration = R.Declaration;
// Pick the best rank of the two.
@@ -265,23 +420,28 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
std::list<ShadowMap>::iterator SM, SMEnd = ShadowMaps.end();
--SMEnd;
for (SM = ShadowMaps.begin(); SM != SMEnd; ++SM) {
- for (llvm::tie(I, IEnd) = SM->equal_range(R.Declaration->getDeclName());
- I != IEnd; ++I) {
+ ShadowMapEntry::iterator I, IEnd;
+ ShadowMap::iterator NamePos = SM->find(R.Declaration->getDeclName());
+ if (NamePos != SM->end()) {
+ I = NamePos->second.begin();
+ IEnd = NamePos->second.end();
+ }
+ for (; I != IEnd; ++I) {
// A tag declaration does not hide a non-tag declaration.
- if (I->second.first->getIdentifierNamespace() == Decl::IDNS_Tag &&
+ if (I->first->getIdentifierNamespace() == Decl::IDNS_Tag &&
(IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
Decl::IDNS_ObjCProtocol)))
continue;
// Protocols are in distinct namespaces from everything else.
- if (((I->second.first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol)
+ if (((I->first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol)
|| (IDNS & Decl::IDNS_ObjCProtocol)) &&
- I->second.first->getIdentifierNamespace() != IDNS)
+ I->first->getIdentifierNamespace() != IDNS)
continue;
// The newly-added result is hidden by an entry in the shadow map.
if (canHiddenResultBeFound(SemaRef.getLangOptions(), R.Declaration,
- I->second.first)) {
+ I->first)) {
// Note that this result was hidden.
R.Hidden = true;
R.QualifierIsInformative = false;
@@ -327,8 +487,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
// Insert this result into the set of results and into the current shadow
// map.
- SMap.insert(std::make_pair(R.Declaration->getDeclName(),
- std::make_pair(R.Declaration, Results.size())));
+ SMap[R.Declaration->getDeclName()].Add(R.Declaration, Results.size());
Results.push_back(R);
}
@@ -339,6 +498,12 @@ void ResultBuilder::EnterNewScope() {
/// \brief Exit from the current scope.
void ResultBuilder::ExitScope() {
+ for (ShadowMap::iterator E = ShadowMaps.back().begin(),
+ EEnd = ShadowMaps.back().end();
+ E != EEnd;
+ ++E)
+ E->second.Destroy();
+
ShadowMaps.pop_back();
}
@@ -403,18 +568,20 @@ bool ResultBuilder::IsNamespaceOrAlias(NamedDecl *ND) const {
return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
}
-/// \brief Brief determines whether the given declaration is a namespace or
-/// namespace alias.
+/// \brief Determines whether the given declaration is a type.
bool ResultBuilder::IsType(NamedDecl *ND) const {
return isa<TypeDecl>(ND);
}
-/// \brief Since every declaration found within a class is a member that we
-/// care about, always returns true. This predicate exists mostly to
-/// communicate to the result builder that we are performing a lookup for
-/// member access.
+/// \brief Determines which members of a class should be visible via
+/// "." or "->". Only value declarations, nested name specifiers, and
+/// using declarations thereof should show up.
bool ResultBuilder::IsMember(NamedDecl *ND) const {
- return true;
+ if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND))
+ ND = Using->getTargetDecl();
+
+ return isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND) ||
+ isa<ObjCPropertyDecl>(ND);
}
// Find the next outer declaration context corresponding to this scope.
@@ -615,7 +782,7 @@ static unsigned CollectLookupResults(Scope *S,
}
/// \brief Add type specifiers for the current language as keyword results.
-static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank,
+static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank,
ResultBuilder &Results) {
typedef CodeCompleteConsumer::Result Result;
Results.MaybeAddResult(Result("short", Rank));
@@ -773,10 +940,11 @@ static void AddTemplateParameterChunks(ASTContext &Context,
/// \brief Add a qualifier to the given code-completion string, if the
/// provided nested-name-specifier is non-NULL.
-void AddQualifierToCompletionString(CodeCompletionString *Result,
- NestedNameSpecifier *Qualifier,
- bool QualifierIsInformative,
- ASTContext &Context) {
+static void
+AddQualifierToCompletionString(CodeCompletionString *Result,
+ NestedNameSpecifier *Qualifier,
+ bool QualifierIsInformative,
+ ASTContext &Context) {
if (!Qualifier)
return;
@@ -791,6 +959,23 @@ void AddQualifierToCompletionString(CodeCompletionString *Result,
Result->AddTextChunk(PrintedNNS);
}
+static void AddFunctionTypeQualsToCompletionString(CodeCompletionString *Result,
+ FunctionDecl *Function) {
+ const FunctionProtoType *Proto
+ = Function->getType()->getAs<FunctionProtoType>();
+ if (!Proto || !Proto->getTypeQuals())
+ return;
+
+ std::string QualsStr;
+ if (Proto->getTypeQuals() & Qualifiers::Const)
+ QualsStr += " const";
+ if (Proto->getTypeQuals() & Qualifiers::Volatile)
+ QualsStr += " volatile";
+ if (Proto->getTypeQuals() & Qualifiers::Restrict)
+ QualsStr += " restrict";
+ Result->AddInformativeChunk(QualsStr);
+}
+
/// \brief If possible, create a new code completion string for the given
/// result.
///
@@ -864,6 +1049,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
AddFunctionParameterChunks(S.Context, Function, Result);
Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen));
+ AddFunctionTypeQualsToCompletionString(Result, Function);
return Result;
}
@@ -917,6 +1103,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
AddFunctionParameterChunks(S.Context, Function, Result);
Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen));
+ AddFunctionTypeQualsToCompletionString(Result, Function);
return Result;
}
@@ -1064,13 +1251,54 @@ namespace {
typedef CodeCompleteConsumer::Result Result;
bool isEarlierDeclarationName(DeclarationName X, DeclarationName Y) const {
- if (!X.getObjCSelector().isNull() && !Y.getObjCSelector().isNull()) {
- // Consider all selector kinds to be equivalent.
- } else if (X.getNameKind() != Y.getNameKind())
+ Selector XSel = X.getObjCSelector();
+ Selector YSel = Y.getObjCSelector();
+ if (!XSel.isNull() && !YSel.isNull()) {
+ // We are comparing two selectors.
+ unsigned N = std::min(XSel.getNumArgs(), YSel.getNumArgs());
+ if (N == 0)
+ ++N;
+ for (unsigned I = 0; I != N; ++I) {
+ IdentifierInfo *XId = XSel.getIdentifierInfoForSlot(I);
+ IdentifierInfo *YId = YSel.getIdentifierInfoForSlot(I);
+ if (!XId || !YId)
+ return XId && !YId;
+
+ switch (XId->getName().compare_lower(YId->getName())) {
+ case -1: return true;
+ case 1: return false;
+ default: break;
+ }
+ }
+
+ return XSel.getNumArgs() < YSel.getNumArgs();
+ }
+
+ // For non-selectors, order by kind.
+ if (X.getNameKind() != Y.getNameKind())
return X.getNameKind() < Y.getNameKind();
- return llvm::LowercaseString(X.getAsString())
- < llvm::LowercaseString(Y.getAsString());
+ // Order identifiers by comparison of their lowercased names.
+ if (IdentifierInfo *XId = X.getAsIdentifierInfo())
+ return XId->getName().compare_lower(
+ Y.getAsIdentifierInfo()->getName()) < 0;
+
+ // Order overloaded operators by the order in which they appear
+ // in our list of operators.
+ if (OverloadedOperatorKind XOp = X.getCXXOverloadedOperator())
+ return XOp < Y.getCXXOverloadedOperator();
+
+ // Order C++0x user-defined literal operators lexically by their
+ // lowercased suffixes.
+ if (IdentifierInfo *XLit = X.getCXXLiteralIdentifier())
+ return XLit->getName().compare_lower(
+ Y.getCXXLiteralIdentifier()->getName()) < 0;
+
+ // The only stable ordering we have is to turn the name into a
+ // string and then compare the lower-case strings. This is
+ // inefficient, but thankfully does not happen too often.
+ return llvm::StringRef(X.getAsString()).compare_lower(
+ Y.getAsString()) < 0;
}
bool operator()(const Result &X, const Result &Y) const {
@@ -1088,7 +1316,7 @@ namespace {
: X.Pattern->getTypedText();
const char *YStr = (Y.Kind == Result::RK_Keyword)? Y.Keyword
: Y.Pattern->getTypedText();
- return strcmp(XStr, YStr) < 0;
+ return llvm::StringRef(XStr).compare_lower(YStr) < 0;
}
// Result kinds are ordered by decreasing importance.
@@ -1113,12 +1341,11 @@ namespace {
Y.Declaration->getDeclName());
case Result::RK_Macro:
- return llvm::LowercaseString(X.Macro->getName()) <
- llvm::LowercaseString(Y.Macro->getName());
+ return X.Macro->getName().compare_lower(Y.Macro->getName()) < 0;
case Result::RK_Keyword:
case Result::RK_Pattern:
- llvm::llvm_unreachable("Result kinds handled above");
+ llvm_unreachable("Result kinds handled above");
break;
}
@@ -1153,9 +1380,23 @@ static void HandleCodeCompleteResults(Sema *S,
}
void Sema::CodeCompleteOrdinaryName(Scope *S) {
+ typedef CodeCompleteConsumer::Result Result;
ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName);
unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
0, CurContext, Results);
+
+ Results.EnterNewScope();
+ AddTypeSpecifierResults(getLangOptions(), NextRank, Results);
+
+ if (getLangOptions().ObjC1) {
+ // Add the "super" keyword, if appropriate.
+ if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(CurContext))
+ if (Method->getClassInterface()->getSuperClass())
+ Results.MaybeAddResult(Result("super", NextRank));
+ }
+
+ Results.ExitScope();
+
if (CodeCompleter->includeMacros())
AddMacroResults(PP, NextRank, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
@@ -1257,6 +1498,8 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
// We could have the start of a nested-name-specifier. Add those
// results as well.
+ // FIXME: We should really walk base classes to produce
+ // nested-name-specifiers so that we produce more-precise results.
Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank,
CurContext, Results);
@@ -1448,14 +1691,21 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
ExprTy **ArgsIn, unsigned NumArgs) {
if (!CodeCompleter)
return;
-
+
+ // When we're code-completing for a call, we fall back to ordinary
+ // name code-completion whenever we can't produce specific
+ // results. We may want to revisit this strategy in the future,
+ // e.g., by merging the two kinds of results.
+
Expr *Fn = (Expr *)FnIn;
Expr **Args = (Expr **)ArgsIn;
-
+
// Ignore type-dependent call expressions entirely.
if (Fn->isTypeDependent() ||
- Expr::hasAnyTypeDependentArguments(Args, NumArgs))
+ Expr::hasAnyTypeDependentArguments(Args, NumArgs)) {
+ CodeCompleteOrdinaryName(S);
return;
+ }
llvm::SmallVector<NamedDecl*,8> Fns;
DeclarationName UnqualifiedName;
@@ -1498,8 +1748,12 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
if (Cand->Viable)
Results.push_back(ResultCandidate(Cand->Function));
}
- CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(),
- Results.size());
+
+ if (Results.empty())
+ CodeCompleteOrdinaryName(S);
+ else
+ CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(),
+ Results.size());
}
void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
@@ -1510,7 +1764,12 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
DeclContext *Ctx = computeDeclContext(SS, EnteringContext);
if (!Ctx)
return;
-
+
+ // Try to instantiate any non-dependent declaration contexts before
+ // we look in them.
+ if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS))
+ return;
+
ResultBuilder Results(*this);
unsigned NextRank = CollectMemberLookupResults(Ctx, 0, Ctx, Results);
@@ -1644,6 +1903,183 @@ void Sema::CodeCompleteOperatorName(Scope *S) {
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
+void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl,
+ bool InInterface) {
+ typedef CodeCompleteConsumer::Result Result;
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+ if (ObjCImpDecl) {
+ // Since we have an implementation, we can end it.
+ Results.MaybeAddResult(Result("end", 0));
+
+ CodeCompletionString *Pattern = 0;
+ Decl *ImpDecl = ObjCImpDecl.getAs<Decl>();
+ if (isa<ObjCImplementationDecl>(ImpDecl) ||
+ isa<ObjCCategoryImplDecl>(ImpDecl)) {
+ // @dynamic
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("dynamic");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("property");
+ Results.MaybeAddResult(Result(Pattern, 0));
+
+ // @synthesize
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("synthesize");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("property");
+ Results.MaybeAddResult(Result(Pattern, 0));
+ }
+ } else if (InInterface) {
+ // Since we have an interface or protocol, we can end it.
+ Results.MaybeAddResult(Result("end", 0));
+
+ if (LangOpts.ObjC2) {
+ // @property
+ Results.MaybeAddResult(Result("property", 0));
+ }
+
+ // @required
+ Results.MaybeAddResult(Result("required", 0));
+
+ // @optional
+ Results.MaybeAddResult(Result("optional", 0));
+ } else {
+ CodeCompletionString *Pattern = 0;
+
+ // @class name ;
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("class");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("identifier");
+ Pattern->AddTextChunk(";"); // add ';' chunk
+ Results.MaybeAddResult(Result(Pattern, 0));
+
+ // @interface name
+ // FIXME: Could introduce the whole pattern, including superclasses and
+ // such.
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("interface");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("class");
+ Results.MaybeAddResult(Result(Pattern, 0));
+
+ // @protocol name
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("protocol");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("protocol");
+ Results.MaybeAddResult(Result(Pattern, 0));
+
+ // @implementation name
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("implementation");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("class");
+ Results.MaybeAddResult(Result(Pattern, 0));
+
+ // @compatibility_alias name
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("compatibility_alias");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("alias");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("class");
+ Results.MaybeAddResult(Result(Pattern, 0));
+ }
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}
+
+static void AddObjCExpressionResults(unsigned Rank, ResultBuilder &Results) {
+ typedef CodeCompleteConsumer::Result Result;
+ CodeCompletionString *Pattern = 0;
+
+ // @encode ( type-name )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("encode");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("type-name");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.MaybeAddResult(Result(Pattern, Rank));
+
+ // @protocol ( protocol-name )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("protocol");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("protocol-name");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.MaybeAddResult(Result(Pattern, Rank));
+
+ // @selector ( selector )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("selector");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("selector");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.MaybeAddResult(Result(Pattern, Rank));
+}
+
+void Sema::CodeCompleteObjCAtStatement(Scope *S) {
+ typedef CodeCompleteConsumer::Result Result;
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+
+ CodeCompletionString *Pattern = 0;
+
+ // @try { statements } @catch ( declaration ) { statements } @finally
+ // { statements }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("try");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Pattern->AddTextChunk("@catch");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("parameter");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Pattern->AddTextChunk("@finally");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.MaybeAddResult(Result(Pattern, 0));
+
+ // @throw
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("throw");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddTextChunk(";");
+ Results.MaybeAddResult(Result(Pattern, 0)); // FIXME: add ';' chunk
+
+ // @synchronized ( expression ) { statements }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("synchronized");
+ Pattern->AddTextChunk(" ");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.MaybeAddResult(Result(Pattern, 0)); // FIXME: add ';' chunk
+
+ AddObjCExpressionResults(0, Results);
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}
+
+void Sema::CodeCompleteObjCAtExpression(Scope *S) {
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+ AddObjCExpressionResults(0, Results);
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}
+
/// \brief Determine whether the addition of the given flag to an Objective-C
/// property's attributes will cause a conflict.
static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) {
OpenPOWER on IntegriCloud