Skip to content

Commit 4f9543b

Browse files
committedJan 31, 2019
[CodeComplete] Propagate preferred types through parser in more cases
Preferred types are used by code completion for ranking. This commit considerably increases the number of points in code where those types are propagated. In order to avoid complicating signatures of Parser's methods, a preferred type is kept as a member variable in the parser and updated during parsing. Differential revision: https://reviews.llvm.org/D56723 llvm-svn: 352788
1 parent 240a90a commit 4f9543b

File tree

9 files changed

+393
-136
lines changed

9 files changed

+393
-136
lines changed
 

Diff for: ‎clang/include/clang/Parse/Parser.h

+7
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ class Parser : public CodeCompletionHandler {
7474
// a statement).
7575
SourceLocation PrevTokLocation;
7676

77+
/// Tracks an expected type for the current token when parsing an expression.
78+
/// Used by code completion for ranking.
79+
PreferredTypeBuilder PreferredType;
80+
7781
unsigned short ParenCount = 0, BracketCount = 0, BraceCount = 0;
7882
unsigned short MisplacedModuleBeginCount = 0;
7983

@@ -840,13 +844,15 @@ class Parser : public CodeCompletionHandler {
840844
///
841845
class TentativeParsingAction {
842846
Parser &P;
847+
PreferredTypeBuilder PrevPreferredType;
843848
Token PrevTok;
844849
size_t PrevTentativelyDeclaredIdentifierCount;
845850
unsigned short PrevParenCount, PrevBracketCount, PrevBraceCount;
846851
bool isActive;
847852

848853
public:
849854
explicit TentativeParsingAction(Parser& p) : P(p) {
855+
PrevPreferredType = P.PreferredType;
850856
PrevTok = P.Tok;
851857
PrevTentativelyDeclaredIdentifierCount =
852858
P.TentativelyDeclaredIdentifiers.size();
@@ -866,6 +872,7 @@ class Parser : public CodeCompletionHandler {
866872
void Revert() {
867873
assert(isActive && "Parsing action was finished!");
868874
P.PP.Backtrack();
875+
P.PreferredType = PrevPreferredType;
869876
P.Tok = PrevTok;
870877
P.TentativelyDeclaredIdentifiers.resize(
871878
PrevTentativelyDeclaredIdentifierCount);

Diff for: ‎clang/include/clang/Sema/CodeCompleteConsumer.h

+1
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ class CodeCompletionContext {
380380
/// if the expression is a variable initializer or a function argument, the
381381
/// type of the corresponding variable or function parameter.
382382
QualType getPreferredType() const { return PreferredType; }
383+
void setPreferredType(QualType T) { PreferredType = T; }
383384

384385
/// Retrieve the type of the base object in a member-access
385386
/// expression.

Diff for: ‎clang/include/clang/Sema/Sema.h

+41-5
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,41 @@ class FileNullabilityMap {
273273
}
274274
};
275275

276+
/// Keeps track of expected type during expression parsing. The type is tied to
277+
/// a particular token, all functions that update or consume the type take a
278+
/// start location of the token they are looking at as a parameter. This allows
279+
/// to avoid updating the type on hot paths in the parser.
280+
class PreferredTypeBuilder {
281+
public:
282+
PreferredTypeBuilder() = default;
283+
explicit PreferredTypeBuilder(QualType Type) : Type(Type) {}
284+
285+
void enterCondition(Sema &S, SourceLocation Tok);
286+
void enterReturn(Sema &S, SourceLocation Tok);
287+
void enterVariableInit(SourceLocation Tok, Decl *D);
288+
289+
void enterParenExpr(SourceLocation Tok, SourceLocation LParLoc);
290+
void enterUnary(Sema &S, SourceLocation Tok, tok::TokenKind OpKind,
291+
SourceLocation OpLoc);
292+
void enterBinary(Sema &S, SourceLocation Tok, Expr *LHS, tok::TokenKind Op);
293+
void enterMemAccess(Sema &S, SourceLocation Tok, Expr *Base);
294+
void enterSubscript(Sema &S, SourceLocation Tok, Expr *LHS);
295+
/// Handles all type casts, including C-style cast, C++ casts, etc.
296+
void enterTypeCast(SourceLocation Tok, QualType CastType);
297+
298+
QualType get(SourceLocation Tok) const {
299+
if (Tok == ExpectedLoc)
300+
return Type;
301+
return QualType();
302+
}
303+
304+
private:
305+
/// Start position of a token for which we store expected type.
306+
SourceLocation ExpectedLoc;
307+
/// Expected type for a token starting at ExpectedLoc.
308+
QualType Type;
309+
};
310+
276311
/// Sema - This implements semantic analysis and AST building for C.
277312
class Sema {
278313
Sema(const Sema &) = delete;
@@ -10371,11 +10406,14 @@ class Sema {
1037110406
struct CodeCompleteExpressionData;
1037210407
void CodeCompleteExpression(Scope *S,
1037310408
const CodeCompleteExpressionData &Data);
10374-
void CodeCompleteExpression(Scope *S, QualType PreferredType);
10409+
void CodeCompleteExpression(Scope *S, QualType PreferredType,
10410+
bool IsParenthesized = false);
1037510411
void CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Expr *OtherOpBase,
1037610412
SourceLocation OpLoc, bool IsArrow,
10377-
bool IsBaseExprStatement);
10378-
void CodeCompletePostfixExpression(Scope *S, ExprResult LHS);
10413+
bool IsBaseExprStatement,
10414+
QualType PreferredType);
10415+
void CodeCompletePostfixExpression(Scope *S, ExprResult LHS,
10416+
QualType PreferredType);
1037910417
void CodeCompleteTag(Scope *S, unsigned TagSpec);
1038010418
void CodeCompleteTypeQualifiers(DeclSpec &DS);
1038110419
void CodeCompleteFunctionQualifiers(DeclSpec &DS, Declarator &D,
@@ -10397,9 +10435,7 @@ class Sema {
1039710435
IdentifierInfo *II,
1039810436
SourceLocation OpenParLoc);
1039910437
void CodeCompleteInitializer(Scope *S, Decl *D);
10400-
void CodeCompleteReturn(Scope *S);
1040110438
void CodeCompleteAfterIf(Scope *S);
10402-
void CodeCompleteBinaryRHS(Scope *S, Expr *LHS, tok::TokenKind Op);
1040310439

1040410440
void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
1040510441
bool EnteringContext, QualType BaseType);

Diff for: ‎clang/lib/Parse/ParseDecl.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -2293,7 +2293,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
22932293
return nullptr;
22942294
}
22952295

2296-
ExprResult Init(ParseInitializer());
2296+
PreferredType.enterVariableInit(Tok.getLocation(), ThisDecl);
2297+
ExprResult Init = ParseInitializer();
22972298

22982299
// If this is the only decl in (possibly) range based for statement,
22992300
// our best guess is that the user meant ':' instead of '='.

Diff for: ‎clang/lib/Parse/ParseExpr.cpp

+36-17
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
158158
/// Parse an expr that doesn't include (top-level) commas.
159159
ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) {
160160
if (Tok.is(tok::code_completion)) {
161-
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression);
161+
Actions.CodeCompleteExpression(getCurScope(),
162+
PreferredType.get(Tok.getLocation()));
162163
cutOffParsing();
163164
return ExprError();
164165
}
@@ -271,7 +272,10 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
271272
getLangOpts().CPlusPlus11);
272273
SourceLocation ColonLoc;
273274

275+
auto SavedType = PreferredType;
274276
while (1) {
277+
// Every iteration may rely on a preferred type for the whole expression.
278+
PreferredType = SavedType;
275279
// If this token has a lower precedence than we are allowed to parse (e.g.
276280
// because we are called recursively, or because the token is not a binop),
277281
// then we are done!
@@ -392,15 +396,8 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
392396
}
393397
}
394398

395-
// Code completion for the right-hand side of a binary expression goes
396-
// through a special hook that takes the left-hand side into account.
397-
if (Tok.is(tok::code_completion)) {
398-
Actions.CodeCompleteBinaryRHS(getCurScope(), LHS.get(),
399-
OpToken.getKind());
400-
cutOffParsing();
401-
return ExprError();
402-
}
403-
399+
PreferredType.enterBinary(Actions, Tok.getLocation(), LHS.get(),
400+
OpToken.getKind());
404401
// Parse another leaf here for the RHS of the operator.
405402
// ParseCastExpression works here because all RHS expressions in C have it
406403
// as a prefix, at least. However, in C++, an assignment-expression could
@@ -763,6 +760,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
763760
bool isVectorLiteral) {
764761
ExprResult Res;
765762
tok::TokenKind SavedKind = Tok.getKind();
763+
auto SavedType = PreferredType;
766764
NotCastExpr = false;
767765

768766
// This handles all of cast-expression, unary-expression, postfix-expression,
@@ -1114,6 +1112,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
11141112
// -- cast-expression
11151113
Token SavedTok = Tok;
11161114
ConsumeToken();
1115+
1116+
PreferredType.enterUnary(Actions, Tok.getLocation(), SavedTok.getKind(),
1117+
SavedTok.getLocation());
11171118
// One special case is implicitly handled here: if the preceding tokens are
11181119
// an ambiguous cast expression, such as "(T())++", then we recurse to
11191120
// determine whether the '++' is prefix or postfix.
@@ -1135,6 +1136,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
11351136
case tok::amp: { // unary-expression: '&' cast-expression
11361137
// Special treatment because of member pointers
11371138
SourceLocation SavedLoc = ConsumeToken();
1139+
PreferredType.enterUnary(Actions, Tok.getLocation(), tok::amp, SavedLoc);
11381140
Res = ParseCastExpression(false, true);
11391141
if (!Res.isInvalid())
11401142
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
@@ -1149,6 +1151,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
11491151
case tok::kw___real: // unary-expression: '__real' cast-expression [GNU]
11501152
case tok::kw___imag: { // unary-expression: '__imag' cast-expression [GNU]
11511153
SourceLocation SavedLoc = ConsumeToken();
1154+
PreferredType.enterUnary(Actions, Tok.getLocation(), SavedKind, SavedLoc);
11521155
Res = ParseCastExpression(false);
11531156
if (!Res.isInvalid())
11541157
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
@@ -1423,7 +1426,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
14231426
Res = ParseBlockLiteralExpression();
14241427
break;
14251428
case tok::code_completion: {
1426-
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression);
1429+
Actions.CodeCompleteExpression(getCurScope(),
1430+
PreferredType.get(Tok.getLocation()));
14271431
cutOffParsing();
14281432
return ExprError();
14291433
}
@@ -1458,6 +1462,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
14581462
// that the address of the function is being taken, which is illegal in CL.
14591463

14601464
// These can be followed by postfix-expr pieces.
1465+
PreferredType = SavedType;
14611466
Res = ParsePostfixExpressionSuffix(Res);
14621467
if (getLangOpts().OpenCL)
14631468
if (Expr *PostfixExpr = Res.get()) {
@@ -1497,13 +1502,17 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
14971502
// Now that the primary-expression piece of the postfix-expression has been
14981503
// parsed, see if there are any postfix-expression pieces here.
14991504
SourceLocation Loc;
1505+
auto SavedType = PreferredType;
15001506
while (1) {
1507+
// Each iteration relies on preferred type for the whole expression.
1508+
PreferredType = SavedType;
15011509
switch (Tok.getKind()) {
15021510
case tok::code_completion:
15031511
if (InMessageExpression)
15041512
return LHS;
15051513

1506-
Actions.CodeCompletePostfixExpression(getCurScope(), LHS);
1514+
Actions.CodeCompletePostfixExpression(
1515+
getCurScope(), LHS, PreferredType.get(Tok.getLocation()));
15071516
cutOffParsing();
15081517
return ExprError();
15091518

@@ -1545,6 +1554,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
15451554
Loc = T.getOpenLocation();
15461555
ExprResult Idx, Length;
15471556
SourceLocation ColonLoc;
1557+
PreferredType.enterSubscript(Actions, Tok.getLocation(), LHS.get());
15481558
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
15491559
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
15501560
Idx = ParseBraceInitializer();
@@ -1726,6 +1736,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
17261736
bool MayBePseudoDestructor = false;
17271737
Expr* OrigLHS = !LHS.isInvalid() ? LHS.get() : nullptr;
17281738

1739+
PreferredType.enterMemAccess(Actions, Tok.getLocation(), OrigLHS);
1740+
17291741
if (getLangOpts().CPlusPlus && !LHS.isInvalid()) {
17301742
Expr *Base = OrigLHS;
17311743
const Type* BaseType = Base->getType().getTypePtrOrNull();
@@ -1772,7 +1784,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
17721784
// Code completion for a member access expression.
17731785
Actions.CodeCompleteMemberReferenceExpr(
17741786
getCurScope(), Base, CorrectedBase, OpLoc, OpKind == tok::arrow,
1775-
Base && ExprStatementTokLoc == Base->getBeginLoc());
1787+
Base && ExprStatementTokLoc == Base->getBeginLoc(),
1788+
PreferredType.get(Tok.getLocation()));
17761789

17771790
cutOffParsing();
17781791
return ExprError();
@@ -2326,14 +2339,16 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
23262339
return ExprError();
23272340
SourceLocation OpenLoc = T.getOpenLocation();
23282341

2342+
PreferredType.enterParenExpr(Tok.getLocation(), OpenLoc);
2343+
23292344
ExprResult Result(true);
23302345
bool isAmbiguousTypeId;
23312346
CastTy = nullptr;
23322347

23332348
if (Tok.is(tok::code_completion)) {
2334-
Actions.CodeCompleteOrdinaryName(getCurScope(),
2335-
ExprType >= CompoundLiteral? Sema::PCC_ParenthesizedExpression
2336-
: Sema::PCC_Expression);
2349+
Actions.CodeCompleteExpression(
2350+
getCurScope(), PreferredType.get(Tok.getLocation()),
2351+
/*IsParenthesized=*/ExprType >= CompoundLiteral);
23372352
cutOffParsing();
23382353
return ExprError();
23392354
}
@@ -2414,6 +2429,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
24142429
T.consumeClose();
24152430
ColonProtection.restore();
24162431
RParenLoc = T.getCloseLocation();
2432+
2433+
PreferredType.enterTypeCast(Tok.getLocation(), Ty.get().get());
24172434
ExprResult SubExpr = ParseCastExpression(/*isUnaryExpression=*/false);
24182435

24192436
if (Ty.isInvalid() || SubExpr.isInvalid())
@@ -2544,6 +2561,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
25442561
return ExprError();
25452562
}
25462563

2564+
PreferredType.enterTypeCast(Tok.getLocation(), CastTy.get());
25472565
// Parse the cast-expression that follows it next.
25482566
// TODO: For cast expression with CastTy.
25492567
Result = ParseCastExpression(/*isUnaryExpression=*/false,
@@ -2845,7 +2863,8 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
28452863
if (Completer)
28462864
Completer();
28472865
else
2848-
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression);
2866+
Actions.CodeCompleteExpression(getCurScope(),
2867+
PreferredType.get(Tok.getLocation()));
28492868
cutOffParsing();
28502869
return true;
28512870
}

Diff for: ‎clang/lib/Parse/ParseExprCXX.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -1672,6 +1672,8 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
16721672
BalancedDelimiterTracker T(*this, tok::l_paren);
16731673
T.consumeOpen();
16741674

1675+
PreferredType.enterTypeCast(Tok.getLocation(), TypeRep.get());
1676+
16751677
ExprVector Exprs;
16761678
CommaLocsTy CommaLocs;
16771679

@@ -1739,6 +1741,7 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
17391741
Sema::ConditionKind CK,
17401742
ForRangeInfo *FRI) {
17411743
ParenBraceBracketBalancer BalancerRAIIObj(*this);
1744+
PreferredType.enterCondition(Actions, Tok.getLocation());
17421745

17431746
if (Tok.is(tok::code_completion)) {
17441747
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition);
@@ -1858,6 +1861,7 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
18581861
diag::warn_cxx98_compat_generalized_initializer_lists);
18591862
InitExpr = ParseBraceInitializer();
18601863
} else if (CopyInitialization) {
1864+
PreferredType.enterVariableInit(Tok.getLocation(), DeclOut);
18611865
InitExpr = ParseAssignmentExpression();
18621866
} else if (Tok.is(tok::l_paren)) {
18631867
// This was probably an attempt to initialize the variable.

Diff for: ‎clang/lib/Parse/ParseStmt.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -1970,9 +1970,12 @@ StmtResult Parser::ParseReturnStatement() {
19701970

19711971
ExprResult R;
19721972
if (Tok.isNot(tok::semi)) {
1973+
if (!IsCoreturn)
1974+
PreferredType.enterReturn(Actions, Tok.getLocation());
19731975
// FIXME: Code completion for co_return.
19741976
if (Tok.is(tok::code_completion) && !IsCoreturn) {
1975-
Actions.CodeCompleteReturn(getCurScope());
1977+
Actions.CodeCompleteExpression(getCurScope(),
1978+
PreferredType.get(Tok.getLocation()));
19761979
cutOffParsing();
19771980
return StmtError();
19781981
}

0 commit comments

Comments
 (0)
Please sign in to comment.