diff 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
line wrap: on
line diff
--- a/clang-tools-extra/clangd/Selection.cpp	Tue Jun 15 19:13:43 2021 +0900
+++ b/clang-tools-extra/clangd/Selection.cpp	Tue Jun 15 19:15:29 2021 +0900
@@ -35,21 +35,26 @@
 namespace clangd {
 namespace {
 using Node = SelectionTree::Node;
-using ast_type_traits::DynTypedNode;
 
 // Measure the fraction of selections that were enabled by recovery AST.
-void recordMetrics(const SelectionTree &S) {
+void recordMetrics(const SelectionTree &S, const LangOptions &Lang) {
+  if (!trace::enabled())
+    return;
+  const char *LanguageLabel = Lang.CPlusPlus ? "C++" : Lang.ObjC ? "ObjC" : "C";
   static constexpr trace::Metric SelectionUsedRecovery(
-      "selection_recovery", trace::Metric::Distribution);
+      "selection_recovery", trace::Metric::Distribution, "language");
+  static constexpr trace::Metric RecoveryType(
+      "selection_recovery_type", trace::Metric::Distribution, "language");
   const auto *Common = S.commonAncestor();
   for (const auto *N = Common; N; N = N->Parent) {
-    if (N->ASTNode.get<RecoveryExpr>()) {
-      SelectionUsedRecovery.record(1); // used recovery ast.
+    if (const auto *RE = N->ASTNode.get<RecoveryExpr>()) {
+      SelectionUsedRecovery.record(1, LanguageLabel); // used recovery ast.
+      RecoveryType.record(RE->isTypeDependent() ? 0 : 1, LanguageLabel);
       return;
     }
   }
   if (Common)
-    SelectionUsedRecovery.record(0); // unused.
+    SelectionUsedRecovery.record(0, LanguageLabel); // unused.
 }
 
 // An IntervalSet maintains a set of disjoint subranges of an array.
@@ -77,8 +82,8 @@
   // Removes the elements of Claim from the set, modifying or removing ranges
   // that overlap it.
   // Returns the continuous subranges of Claim that were actually removed.
-  llvm::SmallVector<llvm::ArrayRef<T>, 4> erase(llvm::ArrayRef<T> Claim) {
-    llvm::SmallVector<llvm::ArrayRef<T>, 4> Out;
+  llvm::SmallVector<llvm::ArrayRef<T>> erase(llvm::ArrayRef<T> Claim) {
+    llvm::SmallVector<llvm::ArrayRef<T>> Out;
     if (Claim.empty())
       return Out;
 
@@ -217,14 +222,26 @@
         SelFirst, AllSpelledTokens.end(), [&](const syntax::Token &Tok) {
           return SM.getFileOffset(Tok.location()) < SelEnd;
         });
+    auto Sel = llvm::makeArrayRef(SelFirst, SelLimit);
+    // Find which of these are preprocessed to nothing and should be ignored.
+    std::vector<bool> PPIgnored(Sel.size(), false);
+    for (const syntax::TokenBuffer::Expansion &X :
+         Buf.expansionsOverlapping(Sel)) {
+      if (X.Expanded.empty()) {
+        for (const syntax::Token &Tok : X.Spelled) {
+          if (&Tok >= SelFirst && &Tok < SelLimit)
+            PPIgnored[&Tok - SelFirst] = true;
+        }
+      }
+    }
     // Precompute selectedness and offset for selected spelled tokens.
-    for (const syntax::Token *T = SelFirst; T < SelLimit; ++T) {
-      if (shouldIgnore(*T))
+    for (unsigned I = 0; I < Sel.size(); ++I) {
+      if (shouldIgnore(Sel[I]) || PPIgnored[I])
         continue;
       SpelledTokens.emplace_back();
       Tok &S = SpelledTokens.back();
-      S.Offset = SM.getFileOffset(T->location());
-      if (S.Offset >= SelBegin && S.Offset + T->length() <= SelEnd)
+      S.Offset = SM.getFileOffset(Sel[I].location());
+      if (S.Offset >= SelBegin && S.Offset + Sel[I].length() <= SelEnd)
         S.Selected = SelectionTree::Complete;
       else
         S.Selected = SelectionTree::Partial;
@@ -464,6 +481,10 @@
   bool TraverseTypeLoc(TypeLoc X) {
     return traverseNode(&X, [&] { return Base::TraverseTypeLoc(X); });
   }
+  bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &X) {
+    return traverseNode(&X,
+                        [&] { return Base::TraverseTemplateArgumentLoc(X); });
+  }
   bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc X) {
     return traverseNode(
         &X, [&] { return Base::TraverseNestedNameSpecifierLoc(X); });
@@ -472,6 +493,9 @@
     return traverseNode(
         X, [&] { return Base::TraverseConstructorInitializer(X); });
   }
+  bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &X) {
+    return traverseNode(&X, [&] { return Base::TraverseCXXBaseSpecifier(X); });
+  }
   // Stmt is the same, but this form allows the data recursion optimization.
   bool dataTraverseStmtPre(Stmt *X) {
     if (!X || isImplicit(X))
@@ -586,6 +610,10 @@
   bool canSafelySkipNode(const DynTypedNode &N) {
     SourceRange S = N.getSourceRange();
     if (auto *TL = N.get<TypeLoc>()) {
+      // FIXME: TypeLoc::getBeginLoc()/getEndLoc() are pretty fragile
+      // heuristics. We should consider only pruning critical TypeLoc nodes, to
+      // be more robust.
+
       // DeclTypeTypeLoc::getSourceRange() is incomplete, which would lead to
       // failing
       // to descend into the child expression.
@@ -597,6 +625,10 @@
       // rid of this patch.
       if (auto DT = TL->getAs<DecltypeTypeLoc>())
         S.setEnd(DT.getUnderlyingExpr()->getEndLoc());
+      // AttributedTypeLoc may point to the attribute's range, NOT the modified
+      // type's range.
+      if (auto AT = TL->getAs<AttributedTypeLoc>())
+        S = AT.getModifiedLoc().getSourceRange();
     }
     if (!SelChecker.mayHit(S)) {
       dlog("{1}skip: {0}", printNodeToString(N, PrintPolicy), indent());
@@ -807,7 +839,7 @@
            .printToString(SM));
   Nodes = SelectionVisitor::collect(AST, Tokens, PrintPolicy, Begin, End, FID);
   Root = Nodes.empty() ? nullptr : &Nodes.front();
-  recordMetrics(*this);
+  recordMetrics(*this, AST.getLangOpts());
   dlog("Built selection tree\n{0}", *this);
 }