Skip to content

Commit 9ba232d

Browse files
committed
[CodeCompletion] Implement completion at custom attribute argument
1 parent 878c9c6 commit 9ba232d

11 files changed

+253
-115
lines changed

include/swift/Parse/CodeCompletionCallbacks.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ class CodeCompletionCallbacks {
115115
}
116116
};
117117

118+
/// Set target decl for attribute if the CC token is in attribute of the decl.
119+
virtual void setAttrTargetDecl(Decl *D) {}
120+
118121
/// Complete the whole expression. This is a fallback that should
119122
/// produce results when more specific completion methods failed.
120123
virtual void completeExpr() {};
@@ -186,7 +189,7 @@ class CodeCompletionCallbacks {
186189
virtual void completeAccessorBeginning(CodeCompletionExpr *E) {};
187190

188191
/// Complete the keyword in attribute, for instance, @available.
189-
virtual void completeDeclAttrBeginning(Decl *D, bool Sil, bool Param) {};
192+
virtual void completeDeclAttrBeginning(bool Sil) {};
190193

191194
/// Complete the parameters in attribute, for instance, version specifier for
192195
/// @available.

include/swift/Parse/Parser.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -904,8 +904,7 @@ class Parser {
904904
void setLocalDiscriminatorToParamList(ParameterList *PL);
905905

906906
/// Parse the optional attributes before a declaration.
907-
bool parseDeclAttributeList(DeclAttributes &Attributes,
908-
bool &FoundCodeCompletionToken);
907+
ParserStatus parseDeclAttributeList(DeclAttributes &Attributes);
909908

910909
/// Parse the optional modifiers before a declaration.
911910
bool parseDeclModifierList(DeclAttributes &Attributes, SourceLoc &StaticLoc,
@@ -941,7 +940,7 @@ class Parser {
941940
SourceLoc Loc);
942941

943942
/// Parse a specific attribute.
944-
bool parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc);
943+
ParserStatus parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc);
945944

946945
bool parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
947946
DeclAttrKind DK);

lib/AST/ASTWalker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
126126
// Attributes
127127
//===--------------------------------------------------------------------===//
128128
bool visitCustomAttributes(Decl *D) {
129-
for (auto *customAttr : D->getAttrs().getAttributes<CustomAttr>()) {
129+
for (auto *customAttr : D->getAttrs().getAttributes<CustomAttr, true>()) {
130130
CustomAttr *mutableCustomAttr = const_cast<CustomAttr *>(customAttr);
131131
if (doIt(mutableCustomAttr->getTypeLoc()))
132132
return true;

lib/IDE/CodeCompletion.cpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,6 +1348,17 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks {
13481348
Consumer(Consumer) {
13491349
}
13501350

1351+
void setAttrTargetDecl(Decl *D) override {
1352+
if (D == nullptr) {
1353+
AttTargetDK = None;
1354+
return;
1355+
}
1356+
auto DK = D->getKind();
1357+
if (DK == DeclKind::PatternBinding)
1358+
DK = DeclKind::Var;
1359+
AttTargetDK = DK;
1360+
}
1361+
13511362
void completeExpr() override;
13521363
void completeDotExpr(Expr *E, SourceLoc DotLoc) override;
13531364
void completeStmtOrExpr(CodeCompletionExpr *E) override;
@@ -1367,7 +1378,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks {
13671378
void completeCaseStmtKeyword() override;
13681379
void completeCaseStmtBeginning() override;
13691380
void completeCaseStmtDotPrefix() override;
1370-
void completeDeclAttrBeginning(Decl *D, bool Sil, bool Param) override;
1381+
void completeDeclAttrBeginning(bool Sil) override;
13711382
void completeDeclAttrParam(DeclAttrKind DK, int Index) override;
13721383
void completeInPrecedenceGroup(SyntaxKind SK) override;
13731384
void completeNominalMemberBeginning(
@@ -4601,17 +4612,9 @@ void CodeCompletionCallbacksImpl::completeDeclAttrParam(DeclAttrKind DK,
46014612
CurDeclContext = P.CurDeclContext;
46024613
}
46034614

4604-
void CodeCompletionCallbacksImpl::completeDeclAttrBeginning(Decl *D, bool Sil,
4605-
bool Param) {
4615+
void CodeCompletionCallbacksImpl::completeDeclAttrBeginning(bool Sil) {
46064616
Kind = CompletionKind::AttributeBegin;
46074617
IsInSil = Sil;
4608-
if (Param) {
4609-
AttTargetDK = DeclKind::Param;
4610-
} else if (D) {
4611-
AttTargetDK = D->getKind();
4612-
if (AttTargetDK == DeclKind::PatternBinding)
4613-
AttTargetDK = DeclKind::Var;
4614-
}
46154618
CurDeclContext = P.CurDeclContext;
46164619
}
46174620

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,15 @@ void typeCheckContextImpl(DeclContext *DC, SourceLoc Loc) {
5757

5858
case DeclContextKind::Initializer:
5959
if (auto *patternInit = dyn_cast<PatternBindingInitializer>(DC)) {
60-
auto *PBD = patternInit->getBinding();
61-
auto i = patternInit->getBindingIndex();
62-
if (PBD->getInit(i)) {
63-
PBD->getPattern(i)->forEachVariable([](VarDecl *VD) {
64-
typeCheckCompletionDecl(VD);
65-
});
66-
if (!PBD->isInitializerChecked(i))
67-
typeCheckPatternBinding(PBD, i);
60+
if (auto *PBD = patternInit->getBinding()) {
61+
auto i = patternInit->getBindingIndex();
62+
if (PBD->getInit(i)) {
63+
PBD->getPattern(i)->forEachVariable([](VarDecl *VD) {
64+
typeCheckCompletionDecl(VD);
65+
});
66+
if (!PBD->isInitializerChecked(i))
67+
typeCheckPatternBinding(PBD, i);
68+
}
6869
}
6970
}
7071
break;

lib/Parse/ParseDecl.cpp

Lines changed: 75 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1746,13 +1746,21 @@ static PatternBindingInitializer *findAttributeInitContent(
17461746
/// Note that various attributes (like mutating, weak, and unowned) are parsed
17471747
/// but rejected since they have context-sensitive keywords.
17481748
///
1749-
bool Parser::parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc) {
1749+
ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc) {
17501750
// If this not an identifier, the attribute is malformed.
17511751
if (Tok.isNot(tok::identifier) &&
17521752
Tok.isNot(tok::kw_in) &&
17531753
Tok.isNot(tok::kw_inout)) {
1754+
1755+
if (Tok.is(tok::code_complete)) {
1756+
if (CodeCompletion)
1757+
CodeCompletion->completeDeclAttrBeginning(isInSILMode());
1758+
consumeToken(tok::code_complete);
1759+
return makeParserCodeCompletionStatus();
1760+
}
1761+
17541762
diagnose(Tok, diag::expected_attribute_name);
1755-
return true;
1763+
return makeParserError();
17561764
}
17571765

17581766
// If the attribute follows the new representation, switch
@@ -1802,7 +1810,8 @@ bool Parser::parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc) {
18021810
diagnose(AtLoc, diag::attr_warn_unused_result_removed)
18031811
.fixItRemove(SourceRange(AtLoc, attrLoc));
18041812

1805-
return false;
1813+
// Recovered.
1814+
return makeParserSuccess();
18061815
}
18071816

18081817
// @warn_unused_result with arguments.
@@ -1823,11 +1832,14 @@ bool Parser::parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc) {
18231832
diagnose(AtLoc, diag::attr_warn_unused_result_removed)
18241833
.fixItRemove(SourceRange(AtLoc, rParenLoc));
18251834

1826-
return false;
1835+
// Recovered.
1836+
return makeParserSuccess();
18271837
}
18281838

1829-
if (DK != DAK_Count && !DeclAttribute::shouldBeRejectedByParser(DK))
1830-
return parseNewDeclAttribute(Attributes, AtLoc, DK);
1839+
if (DK != DAK_Count && !DeclAttribute::shouldBeRejectedByParser(DK)) {
1840+
parseNewDeclAttribute(Attributes, AtLoc, DK);
1841+
return makeParserSuccess();
1842+
}
18311843

18321844
if (TypeAttributes::getAttrKindFromString(Tok.getText()) != TAK_Count)
18331845
diagnose(Tok, diag::type_attribute_applied_to_decl);
@@ -1842,7 +1854,7 @@ bool Parser::parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc) {
18421854
if (Tok.is(tok::l_paren))
18431855
skipSingle();
18441856

1845-
return true;
1857+
return ParserStatus(type);
18461858
}
18471859

18481860
// Parse the optional arguments.
@@ -1852,55 +1864,63 @@ bool Parser::parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc) {
18521864
SmallVector<SourceLoc, 2> argLabelLocs;
18531865
Expr *trailingClosure = nullptr;
18541866
bool hasInitializer = false;
1867+
ParserStatus status;
18551868

18561869
// If we're not in a local context, we'll need a context to parse
18571870
// initializers into (should we have one). This happens for properties
18581871
// and global variables in libraries.
18591872
PatternBindingInitializer *initContext = nullptr;
18601873

18611874
if (Tok.isFollowingLParen()) {
1862-
1863-
// If we have no local context to parse the initial value into, create one
1864-
// for the PBD we'll eventually create. This allows us to have reasonable
1865-
// DeclContexts for any closures that may live inside of initializers.
1866-
Optional<ParseFunctionBody> initParser;
1867-
if (!CurDeclContext->isLocalContext()) {
1868-
initContext = findAttributeInitContent(Attributes);
1869-
if (!initContext)
1870-
initContext = new (Context) PatternBindingInitializer(CurDeclContext);
1871-
1872-
initParser.emplace(*this, initContext);
1875+
if (peekToken().is(tok::code_complete)) {
1876+
consumeToken(tok::l_paren);
1877+
if (CodeCompletion) {
1878+
auto typeE = new (Context) TypeExpr(type.get());
1879+
auto CCE = new (Context) CodeCompletionExpr(Tok.getLoc());
1880+
CodeCompletion->completePostfixExprParen(typeE, CCE);
1881+
}
1882+
consumeToken(tok::code_complete);
1883+
skipUntil(tok::r_paren);
1884+
consumeIf(tok::r_paren);
1885+
status.setHasCodeCompletion();
1886+
} else {
1887+
// If we have no local context to parse the initial value into, create
1888+
// one for the PBD we'll eventually create. This allows us to have
1889+
// reasonable DeclContexts for any closures that may live inside of
1890+
// initializers.
1891+
Optional<ParseFunctionBody> initParser;
1892+
if (!CurDeclContext->isLocalContext()) {
1893+
initContext = findAttributeInitContent(Attributes);
1894+
if (!initContext)
1895+
initContext =
1896+
new (Context) PatternBindingInitializer(CurDeclContext);
1897+
1898+
initParser.emplace(*this, initContext);
1899+
}
1900+
status |= parseExprList(tok::l_paren, tok::r_paren,
1901+
/*isPostfix=*/false, /*isExprBasic=*/true,
1902+
lParenLoc, args, argLabels, argLabelLocs,
1903+
rParenLoc, trailingClosure,
1904+
SyntaxKind::FunctionCallArgumentList);
1905+
assert(!trailingClosure && "Cannot parse a trailing closure here");
1906+
hasInitializer = true;
18731907
}
1874-
1875-
ParserStatus status = parseExprList(tok::l_paren, tok::r_paren,
1876-
/*isPostfix=*/false,
1877-
/*isExprBasic=*/true,
1878-
lParenLoc, args, argLabels,
1879-
argLabelLocs,
1880-
rParenLoc,
1881-
trailingClosure,
1882-
SyntaxKind::FunctionCallArgumentList);
1883-
if (status.hasCodeCompletion())
1884-
return true;
1885-
1886-
assert(!trailingClosure && "Cannot parse a trailing closure here");
1887-
hasInitializer = true;
18881908
}
18891909

18901910
// Form the attribute.
18911911
auto attr = CustomAttr::create(Context, AtLoc, type.get(), hasInitializer,
18921912
initContext, lParenLoc, args, argLabels,
18931913
argLabelLocs, rParenLoc);
18941914
Attributes.add(attr);
1895-
return false;
1915+
return status;
18961916
}
18971917

18981918
// Recover by eating @foo(...) when foo is not known.
18991919
consumeToken();
19001920
if (Tok.is(tok::l_paren))
19011921
skipSingle();
19021922

1903-
return true;
1923+
return makeParserError();
19041924
}
19051925

19061926
bool Parser::canParseTypeAttribute() {
@@ -2180,30 +2200,18 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, bool justChecking) {
21802200
/// attribute-list-clause:
21812201
/// '@' attribute
21822202
/// \endverbatim
2183-
bool Parser::parseDeclAttributeList(DeclAttributes &Attributes,
2184-
bool &FoundCCToken) {
2185-
FoundCCToken = false;
2203+
ParserStatus Parser::parseDeclAttributeList(DeclAttributes &Attributes) {
21862204
if (Tok.isNot(tok::at_sign))
2187-
return false;
2188-
2189-
bool error = false;
2205+
return makeParserSuccess();
21902206

2207+
ParserStatus Status;
21912208
SyntaxParsingContext AttrListCtx(SyntaxContext, SyntaxKind::AttributeList);
21922209
do {
2193-
if (peekToken().is(tok::code_complete)) {
2194-
consumeToken(tok::at_sign);
2195-
consumeToken(tok::code_complete);
2196-
FoundCCToken = true;
2197-
continue;
2198-
}
21992210
SyntaxParsingContext AttrCtx(SyntaxContext, SyntaxKind::Attribute);
22002211
SourceLoc AtLoc = consumeToken();
2201-
if (parseDeclAttribute(Attributes, AtLoc)) {
2202-
// Consume any remaining attributes for better error recovery.
2203-
error = true;
2204-
}
2212+
Status |= parseDeclAttribute(Attributes, AtLoc);
22052213
} while (Tok.is(tok::at_sign));
2206-
return error;
2214+
return Status;
22072215
}
22082216

22092217
/// \verbatim
@@ -2788,8 +2796,7 @@ Parser::parseDecl(ParseDeclOptions Flags,
27882796
DeclAttributes Attributes;
27892797
if (Tok.hasComment())
27902798
Attributes.add(new (Context) RawDocCommentAttr(Tok.getCommentRange()));
2791-
bool FoundCCTokenInAttr;
2792-
parseDeclAttributeList(Attributes, FoundCCTokenInAttr);
2799+
ParserStatus AttrStatus = parseDeclAttributeList(Attributes);
27932800

27942801
// Parse modifiers.
27952802
// Keep track of where and whether we see a contextual keyword on the decl.
@@ -2936,15 +2943,6 @@ Parser::parseDecl(ParseDeclOptions Flags,
29362943

29372944
// Obvious nonsense.
29382945
default:
2939-
if (FoundCCTokenInAttr) {
2940-
if (!CodeCompletion) {
2941-
delayParseFromBeginningToHere(BeginParserPosition, Flags);
2942-
} else {
2943-
CodeCompletion->completeDeclAttrBeginning(nullptr, isInSILMode(),
2944-
false);
2945-
}
2946-
}
2947-
29482946
diagnose(Tok, diag::expected_decl);
29492947

29502948
if (CurDeclContext) {
@@ -2960,7 +2958,6 @@ Parser::parseDecl(ParseDeclOptions Flags,
29602958
}
29612959
}
29622960
}
2963-
return makeParserErrorResult<Decl>();
29642961
}
29652962

29662963
if (DeclResult.isParseError() && Tok.is(tok::code_complete)) {
@@ -2999,22 +2996,9 @@ Parser::parseDecl(ParseDeclOptions Flags,
29992996
consumeToken(tok::code_complete);
30002997
}
30012998

3002-
if (auto SF = CurDeclContext->getParentSourceFile()) {
3003-
if (!getScopeInfo().isInactiveConfigBlock()) {
3004-
for (auto Attr : Attributes) {
3005-
if (isa<ObjCAttr>(Attr) ||
3006-
/* Pre Swift 5 dymamic implied @objc */
3007-
(!Context.LangOpts.isSwiftVersionAtLeast(5) &&
3008-
isa<DynamicAttr>(Attr)))
3009-
SF->AttrsRequiringFoundation.insert(Attr);
3010-
}
3011-
}
3012-
}
3013-
3014-
if (FoundCCTokenInAttr) {
2999+
if (AttrStatus.hasCodeCompletion()) {
30153000
if (CodeCompletion) {
3016-
CodeCompletion->completeDeclAttrBeginning(DeclResult.getPtrOrNull(),
3017-
isInSILMode(), false);
3001+
CodeCompletion->setAttrTargetDecl(DeclResult.getPtrOrNull());
30183002
} else {
30193003
delayParseFromBeginningToHere(BeginParserPosition, Flags);
30203004
return makeParserError();
@@ -3030,6 +3014,18 @@ Parser::parseDecl(ParseDeclOptions Flags,
30303014
return makeParserError();
30313015
}
30323016

3017+
if (auto SF = CurDeclContext->getParentSourceFile()) {
3018+
if (!getScopeInfo().isInactiveConfigBlock()) {
3019+
for (auto Attr : Attributes) {
3020+
if (isa<ObjCAttr>(Attr) ||
3021+
/* Pre Swift 5 dymamic implied @objc */
3022+
(!Context.LangOpts.isSwiftVersionAtLeast(5) &&
3023+
isa<DynamicAttr>(Attr)))
3024+
SF->AttrsRequiringFoundation.insert(Attr);
3025+
}
3026+
}
3027+
}
3028+
30333029
if (DeclResult.isNonNull()) {
30343030
Decl *D = DeclResult.get();
30353031
if (!declWasHandledAlready(D))
@@ -4402,8 +4398,7 @@ static bool parseAccessorIntroducer(Parser &P,
44024398
AccessorKind &Kind,
44034399
SourceLoc &Loc) {
44044400
assert(Attributes.isEmpty());
4405-
bool FoundCCToken;
4406-
P.parseDeclAttributeList(Attributes, FoundCCToken);
4401+
P.parseDeclAttributeList(Attributes);
44074402

44084403
// Parse the contextual keywords for 'mutating' and 'nonmutating' before
44094404
// get and set.

0 commit comments

Comments
 (0)