comparison clang-tools-extra/clangd/Selection.cpp @ 221:79ff65ed7e25

LLVM12 Original
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Tue, 15 Jun 2021 19:15:29 +0900
parents 0572611fdcc8
children 5f17cb93ff66
comparison
equal deleted inserted replaced
220:42394fc6a535 221:79ff65ed7e25
33 33
34 namespace clang { 34 namespace clang {
35 namespace clangd { 35 namespace clangd {
36 namespace { 36 namespace {
37 using Node = SelectionTree::Node; 37 using Node = SelectionTree::Node;
38 using ast_type_traits::DynTypedNode;
39 38
40 // Measure the fraction of selections that were enabled by recovery AST. 39 // Measure the fraction of selections that were enabled by recovery AST.
41 void recordMetrics(const SelectionTree &S) { 40 void recordMetrics(const SelectionTree &S, const LangOptions &Lang) {
41 if (!trace::enabled())
42 return;
43 const char *LanguageLabel = Lang.CPlusPlus ? "C++" : Lang.ObjC ? "ObjC" : "C";
42 static constexpr trace::Metric SelectionUsedRecovery( 44 static constexpr trace::Metric SelectionUsedRecovery(
43 "selection_recovery", trace::Metric::Distribution); 45 "selection_recovery", trace::Metric::Distribution, "language");
46 static constexpr trace::Metric RecoveryType(
47 "selection_recovery_type", trace::Metric::Distribution, "language");
44 const auto *Common = S.commonAncestor(); 48 const auto *Common = S.commonAncestor();
45 for (const auto *N = Common; N; N = N->Parent) { 49 for (const auto *N = Common; N; N = N->Parent) {
46 if (N->ASTNode.get<RecoveryExpr>()) { 50 if (const auto *RE = N->ASTNode.get<RecoveryExpr>()) {
47 SelectionUsedRecovery.record(1); // used recovery ast. 51 SelectionUsedRecovery.record(1, LanguageLabel); // used recovery ast.
52 RecoveryType.record(RE->isTypeDependent() ? 0 : 1, LanguageLabel);
48 return; 53 return;
49 } 54 }
50 } 55 }
51 if (Common) 56 if (Common)
52 SelectionUsedRecovery.record(0); // unused. 57 SelectionUsedRecovery.record(0, LanguageLabel); // unused.
53 } 58 }
54 59
55 // An IntervalSet maintains a set of disjoint subranges of an array. 60 // An IntervalSet maintains a set of disjoint subranges of an array.
56 // 61 //
57 // Initially, it contains the entire array. 62 // Initially, it contains the entire array.
75 IntervalSet(llvm::ArrayRef<T> Range) { UnclaimedRanges.insert(Range); } 80 IntervalSet(llvm::ArrayRef<T> Range) { UnclaimedRanges.insert(Range); }
76 81
77 // Removes the elements of Claim from the set, modifying or removing ranges 82 // Removes the elements of Claim from the set, modifying or removing ranges
78 // that overlap it. 83 // that overlap it.
79 // Returns the continuous subranges of Claim that were actually removed. 84 // Returns the continuous subranges of Claim that were actually removed.
80 llvm::SmallVector<llvm::ArrayRef<T>, 4> erase(llvm::ArrayRef<T> Claim) { 85 llvm::SmallVector<llvm::ArrayRef<T>> erase(llvm::ArrayRef<T> Claim) {
81 llvm::SmallVector<llvm::ArrayRef<T>, 4> Out; 86 llvm::SmallVector<llvm::ArrayRef<T>> Out;
82 if (Claim.empty()) 87 if (Claim.empty())
83 return Out; 88 return Out;
84 89
85 // General case: 90 // General case:
86 // Claim: [-----------------] 91 // Claim: [-----------------]
215 }); 220 });
216 const syntax::Token *SelLimit = std::partition_point( 221 const syntax::Token *SelLimit = std::partition_point(
217 SelFirst, AllSpelledTokens.end(), [&](const syntax::Token &Tok) { 222 SelFirst, AllSpelledTokens.end(), [&](const syntax::Token &Tok) {
218 return SM.getFileOffset(Tok.location()) < SelEnd; 223 return SM.getFileOffset(Tok.location()) < SelEnd;
219 }); 224 });
225 auto Sel = llvm::makeArrayRef(SelFirst, SelLimit);
226 // Find which of these are preprocessed to nothing and should be ignored.
227 std::vector<bool> PPIgnored(Sel.size(), false);
228 for (const syntax::TokenBuffer::Expansion &X :
229 Buf.expansionsOverlapping(Sel)) {
230 if (X.Expanded.empty()) {
231 for (const syntax::Token &Tok : X.Spelled) {
232 if (&Tok >= SelFirst && &Tok < SelLimit)
233 PPIgnored[&Tok - SelFirst] = true;
234 }
235 }
236 }
220 // Precompute selectedness and offset for selected spelled tokens. 237 // Precompute selectedness and offset for selected spelled tokens.
221 for (const syntax::Token *T = SelFirst; T < SelLimit; ++T) { 238 for (unsigned I = 0; I < Sel.size(); ++I) {
222 if (shouldIgnore(*T)) 239 if (shouldIgnore(Sel[I]) || PPIgnored[I])
223 continue; 240 continue;
224 SpelledTokens.emplace_back(); 241 SpelledTokens.emplace_back();
225 Tok &S = SpelledTokens.back(); 242 Tok &S = SpelledTokens.back();
226 S.Offset = SM.getFileOffset(T->location()); 243 S.Offset = SM.getFileOffset(Sel[I].location());
227 if (S.Offset >= SelBegin && S.Offset + T->length() <= SelEnd) 244 if (S.Offset >= SelBegin && S.Offset + Sel[I].length() <= SelEnd)
228 S.Selected = SelectionTree::Complete; 245 S.Selected = SelectionTree::Complete;
229 else 246 else
230 S.Selected = SelectionTree::Partial; 247 S.Selected = SelectionTree::Partial;
231 } 248 }
232 } 249 }
462 return traverseNode(X, [&] { return Base::TraverseDecl(X); }); 479 return traverseNode(X, [&] { return Base::TraverseDecl(X); });
463 } 480 }
464 bool TraverseTypeLoc(TypeLoc X) { 481 bool TraverseTypeLoc(TypeLoc X) {
465 return traverseNode(&X, [&] { return Base::TraverseTypeLoc(X); }); 482 return traverseNode(&X, [&] { return Base::TraverseTypeLoc(X); });
466 } 483 }
484 bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &X) {
485 return traverseNode(&X,
486 [&] { return Base::TraverseTemplateArgumentLoc(X); });
487 }
467 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc X) { 488 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc X) {
468 return traverseNode( 489 return traverseNode(
469 &X, [&] { return Base::TraverseNestedNameSpecifierLoc(X); }); 490 &X, [&] { return Base::TraverseNestedNameSpecifierLoc(X); });
470 } 491 }
471 bool TraverseConstructorInitializer(CXXCtorInitializer *X) { 492 bool TraverseConstructorInitializer(CXXCtorInitializer *X) {
472 return traverseNode( 493 return traverseNode(
473 X, [&] { return Base::TraverseConstructorInitializer(X); }); 494 X, [&] { return Base::TraverseConstructorInitializer(X); });
495 }
496 bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &X) {
497 return traverseNode(&X, [&] { return Base::TraverseCXXBaseSpecifier(X); });
474 } 498 }
475 // Stmt is the same, but this form allows the data recursion optimization. 499 // Stmt is the same, but this form allows the data recursion optimization.
476 bool dataTraverseStmtPre(Stmt *X) { 500 bool dataTraverseStmtPre(Stmt *X) {
477 if (!X || isImplicit(X)) 501 if (!X || isImplicit(X))
478 return false; 502 return false;
584 // An optimization for a common case: nodes outside macro expansions that 608 // An optimization for a common case: nodes outside macro expansions that
585 // don't intersect the selection may be recursively skipped. 609 // don't intersect the selection may be recursively skipped.
586 bool canSafelySkipNode(const DynTypedNode &N) { 610 bool canSafelySkipNode(const DynTypedNode &N) {
587 SourceRange S = N.getSourceRange(); 611 SourceRange S = N.getSourceRange();
588 if (auto *TL = N.get<TypeLoc>()) { 612 if (auto *TL = N.get<TypeLoc>()) {
613 // FIXME: TypeLoc::getBeginLoc()/getEndLoc() are pretty fragile
614 // heuristics. We should consider only pruning critical TypeLoc nodes, to
615 // be more robust.
616
589 // DeclTypeTypeLoc::getSourceRange() is incomplete, which would lead to 617 // DeclTypeTypeLoc::getSourceRange() is incomplete, which would lead to
590 // failing 618 // failing
591 // to descend into the child expression. 619 // to descend into the child expression.
592 // decltype(2+2); 620 // decltype(2+2);
593 // ~~~~~~~~~~~~~ <-- correct range 621 // ~~~~~~~~~~~~~ <-- correct range
595 // ~~~~~~~~~~~~ <-- range with this hack(i.e, missing closing paren) 623 // ~~~~~~~~~~~~ <-- range with this hack(i.e, missing closing paren)
596 // FIXME: Alter DecltypeTypeLoc to contain parentheses locations and get 624 // FIXME: Alter DecltypeTypeLoc to contain parentheses locations and get
597 // rid of this patch. 625 // rid of this patch.
598 if (auto DT = TL->getAs<DecltypeTypeLoc>()) 626 if (auto DT = TL->getAs<DecltypeTypeLoc>())
599 S.setEnd(DT.getUnderlyingExpr()->getEndLoc()); 627 S.setEnd(DT.getUnderlyingExpr()->getEndLoc());
628 // AttributedTypeLoc may point to the attribute's range, NOT the modified
629 // type's range.
630 if (auto AT = TL->getAs<AttributedTypeLoc>())
631 S = AT.getModifiedLoc().getSourceRange();
600 } 632 }
601 if (!SelChecker.mayHit(S)) { 633 if (!SelChecker.mayHit(S)) {
602 dlog("{1}skip: {0}", printNodeToString(N, PrintPolicy), indent()); 634 dlog("{1}skip: {0}", printNodeToString(N, PrintPolicy), indent());
603 dlog("{1}skipped range = {0}", S.printToString(SM), indent(1)); 635 dlog("{1}skipped range = {0}", S.printToString(SM), indent(1));
604 return true; 636 return true;
805 dlog("Computing selection for {0}", 837 dlog("Computing selection for {0}",
806 SourceRange(SM.getComposedLoc(FID, Begin), SM.getComposedLoc(FID, End)) 838 SourceRange(SM.getComposedLoc(FID, Begin), SM.getComposedLoc(FID, End))
807 .printToString(SM)); 839 .printToString(SM));
808 Nodes = SelectionVisitor::collect(AST, Tokens, PrintPolicy, Begin, End, FID); 840 Nodes = SelectionVisitor::collect(AST, Tokens, PrintPolicy, Begin, End, FID);
809 Root = Nodes.empty() ? nullptr : &Nodes.front(); 841 Root = Nodes.empty() ? nullptr : &Nodes.front();
810 recordMetrics(*this); 842 recordMetrics(*this, AST.getLangOpts());
811 dlog("Built selection tree\n{0}", *this); 843 dlog("Built selection tree\n{0}", *this);
812 } 844 }
813 845
814 const Node *SelectionTree::commonAncestor() const { 846 const Node *SelectionTree::commonAncestor() const {
815 const Node *Ancestor = Root; 847 const Node *Ancestor = Root;