@@ -320,6 +320,11 @@ static bool hasUnhandledError(ArrayRef<ASTNode> Nodes) {
320
320
});
321
321
}
322
322
323
+ static bool
324
+ hasNodeThat (ArrayRef<ASTNode> Nodes, llvm::function_ref<bool (ASTNode)> Pred) {
325
+ return std::any_of (Nodes.begin (), Nodes.end (), Pred);
326
+ }
327
+
323
328
struct RangeResolver ::Implementation {
324
329
SourceFile &File;
325
330
ASTContext &Ctx;
@@ -342,37 +347,22 @@ struct RangeResolver::Implementation {
342
347
std::vector<ASTNode> EndMatches;
343
348
ContextInfo (ASTNode Parent, bool ContainedInRange) : Parent(Parent),
344
349
ContainedInRange (ContainedInRange) {}
345
- private:
346
- bool hasStmtlikeNode (ArrayRef<ASTNode> Nodes) {
347
- for (auto N : Nodes) {
348
- if (N.is <Stmt*>())
349
- return true ;
350
- // Expression with void type is statement-like.
351
- else if (N.is <Expr*>()) {
352
- auto *E = N.get <Expr*>();
353
- if (auto T = E->getType ()) {
354
- if (T->isVoid ())
355
- return true ;
356
- }
357
- } else {
358
- // Decls are statement like.
359
- return true ;
360
- }
361
- }
350
+
351
+ bool isMultiStatment () {
352
+ if (StartMatches.empty () || EndMatches.empty ())
353
+ return false ;
354
+
355
+ // Multi-statement should have a common parent of brace statement, this
356
+ // can be implicit brace statement, e.g. in case statement.
357
+ if (Parent.isStmt (StmtKind::Brace))
358
+ return true ;
359
+
360
+ // Explicitly allow the selection of multiple case statments.
361
+ auto IsCase = [](ASTNode N) { return N.isStmt (StmtKind::Case); };
362
+ if (hasNodeThat (StartMatches, IsCase) && hasNodeThat (EndMatches, IsCase))
363
+ return true ;
362
364
return false ;
363
365
}
364
- public:
365
- bool hasStmtMatch (RangeMatchKind Kind) {
366
- switch (Kind) {
367
- case RangeMatchKind::NoneMatch:
368
- case RangeMatchKind::RangeMatch:
369
- llvm_unreachable (" cannot answer these." );
370
- case RangeMatchKind::StartMatch:
371
- return hasStmtlikeNode (StartMatches);
372
- case RangeMatchKind::EndMatch:
373
- return hasStmtlikeNode (EndMatches);
374
- }
375
- }
376
366
};
377
367
378
368
std::vector<Token> AllTokens;
@@ -395,17 +385,28 @@ struct RangeResolver::Implementation {
395
385
std::vector<ASTNode> ContainedASTNodes;
396
386
397
387
// / Collect the type that an ASTNode should be evaluated to.
398
- Type resolveNodeType (ASTNode N) {
399
- if (N.is <Stmt*>()) {
400
- if (auto RS = dyn_cast<ReturnStmt>(N.get <Stmt*>())) {
401
- return resolveNodeType (RS->getResult ());
388
+ Type resolveNodeType (ASTNode N, RangeKind Kind) {
389
+ switch (Kind) {
390
+ case RangeKind::Invalid:
391
+ case RangeKind::SingleDecl:
392
+ llvm_unreachable (" cannot get type." );
393
+
394
+ // For a single expression, its type is apparent.
395
+ case RangeKind::SingleExpression:
396
+ return N.get <Expr*>()->getType ();
397
+
398
+ // For statements, we either resolve to the returning type or Void.
399
+ case RangeKind::SingleStatement:
400
+ case RangeKind::MultiStatement: {
401
+ if (N.is <Stmt*>()) {
402
+ if (auto RS = dyn_cast<ReturnStmt>(N.get <Stmt*>())) {
403
+ return resolveNodeType (RS->getResult (), RangeKind::SingleExpression);
404
+ }
402
405
}
403
406
// For other statements, the type should be void.
404
407
return Ctx.getVoidDecl ()->getDeclaredInterfaceType ();
405
- } else if (N.is <Expr*>()) {
406
- return N.get <Expr*>()->getType ();
407
408
}
408
- return Type ();
409
+ }
409
410
}
410
411
411
412
ResolvedRangeInfo getSingleNodeKind (ASTNode Node) {
@@ -417,14 +418,16 @@ struct RangeResolver::Implementation {
417
418
OrphanKind Kind = getOrphanKind (ContainedASTNodes);
418
419
if (Node.is <Expr*>())
419
420
return ResolvedRangeInfo (RangeKind::SingleExpression,
420
- resolveNodeType (Node), Content,
421
+ resolveNodeType (Node, RangeKind::SingleExpression),
422
+ Content,
421
423
getImmediateContext (), SingleEntry,
422
424
UnhandledError, Kind,
423
425
llvm::makeArrayRef (ContainedASTNodes),
424
426
llvm::makeArrayRef (DeclaredDecls),
425
427
llvm::makeArrayRef (ReferencedDecls));
426
428
else if (Node.is <Stmt*>())
427
- return ResolvedRangeInfo (RangeKind::SingleStatement, resolveNodeType (Node),
429
+ return ResolvedRangeInfo (RangeKind::SingleStatement,
430
+ resolveNodeType (Node, RangeKind::SingleStatement),
428
431
Content, getImmediateContext (), SingleEntry,
429
432
UnhandledError, Kind,
430
433
llvm::makeArrayRef (ContainedASTNodes),
@@ -685,15 +688,12 @@ struct RangeResolver::Implementation {
685
688
}
686
689
}
687
690
688
- // Check if the start and end matches have statement-like entities; this
689
- // can avoid picking expressions like "a == b" in a list of selected
690
- // multi-statement at the start (or the end).
691
- if (DCInfo.hasStmtMatch (RangeMatchKind::StartMatch) &&
692
- DCInfo.hasStmtMatch (RangeMatchKind::EndMatch)) {
691
+ if (DCInfo.isMultiStatment ()) {
693
692
postAnalysis (DCInfo.EndMatches .back ());
694
693
Result = {RangeKind::MultiStatement,
695
694
/* Last node has the type */
696
- resolveNodeType (DCInfo.EndMatches .back ()), Content,
695
+ resolveNodeType (DCInfo.EndMatches .back (),
696
+ RangeKind::MultiStatement), Content,
697
697
getImmediateContext (), hasSingleEntryPoint (ContainedASTNodes),
698
698
hasUnhandledError (ContainedASTNodes),
699
699
getOrphanKind (ContainedASTNodes),
0 commit comments