From 774acdfb8c46de9b4f8a92d80bbbd96e4d467682 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Mon, 11 May 2020 11:02:34 +0200 Subject: [PATCH] [clangd] Add metrics for selection tree and recovery expressions. Reviewers: sammccall Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D79701 --- clang-tools-extra/clangd/Selection.cpp | 17 +++++++++++++++++ clang-tools-extra/clangd/unittests/SelectionTests.cpp | 19 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/clang-tools-extra/clangd/Selection.cpp b/clang-tools-extra/clangd/Selection.cpp index 7d52714..df7e82c 100644 --- a/clang-tools-extra/clangd/Selection.cpp +++ b/clang-tools-extra/clangd/Selection.cpp @@ -9,6 +9,7 @@ #include "Selection.h" #include "SourceCode.h" #include "support/Logger.h" +#include "support/Trace.h" #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" @@ -35,6 +36,21 @@ 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) { + static constexpr trace::Metric SelectionUsedRecovery( + "selection_recovery", trace::Metric::Distribution); + const auto *Common = S.commonAncestor(); + for (const auto *N = Common; N; N = N->Parent) { + if (N->ASTNode.get()) { + SelectionUsedRecovery.record(1); // used recovery ast. + return; + } + } + if (Common) + SelectionUsedRecovery.record(0); // unused. +} + // An IntervalSet maintains a set of disjoint subranges of an array. // // Initially, it contains the entire array. @@ -774,6 +790,7 @@ SelectionTree::SelectionTree(ASTContext &AST, const syntax::TokenBuffer &Tokens, .printToString(SM)); Nodes = SelectionVisitor::collect(AST, Tokens, PrintPolicy, Begin, End, FID); Root = Nodes.empty() ? nullptr : &Nodes.front(); + recordMetrics(*this); dlog("Built selection tree\n{0}", *this); } diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp index e1c873a..6f8c10e 100644 --- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp @@ -9,6 +9,7 @@ #include "Selection.h" #include "SourceCode.h" #include "TestTU.h" +#include "support/TestTracer.h" #include "clang/AST/Decl.h" #include "llvm/Support/Casting.h" #include "gmock/gmock.h" @@ -390,6 +391,7 @@ TEST(SelectionTest, CommonAncestor) { )cpp", "DeclRefExpr"} // DeclRefExpr to the "operator->" method. }; for (const Case &C : Cases) { + trace::TestTracer Tracer; Annotations Test(C.Code); TestTU TU; @@ -407,6 +409,7 @@ TEST(SelectionTest, CommonAncestor) { if (Test.ranges().empty()) { // If no [[range]] is marked in the example, there should be no selection. EXPECT_FALSE(T.commonAncestor()) << C.Code << "\n" << T; + EXPECT_THAT(Tracer.takeMetric("selection_recovery"), testing::IsEmpty()); } else { // If there is an expected selection, common ancestor should exist // with the appropriate node type. @@ -422,6 +425,8 @@ TEST(SelectionTest, CommonAncestor) { // and no nodes outside it are selected. EXPECT_TRUE(verifyCommonAncestor(T.root(), T.commonAncestor(), C.Code)) << C.Code; + EXPECT_THAT(Tracer.takeMetric("selection_recovery"), + testing::ElementsAreArray({0})); } } } @@ -436,6 +441,20 @@ TEST(SelectionTest, InjectedClassName) { EXPECT_FALSE(D->isInjectedClassName()); } +TEST(SelectionTree, Metrics) { + const char *Code = R"cpp( + // error-ok: testing behavior on recovery expression + int foo(); + int foo(int, int); + int x = fo^o(42); + )cpp"; + auto AST = TestTU::withCode(Annotations(Code).code()).build(); + trace::TestTracer Tracer; + auto T = makeSelectionTree(Code, AST); + EXPECT_THAT(Tracer.takeMetric("selection_recovery"), + testing::ElementsAreArray({1})); +} + // FIXME: Doesn't select the binary operator node in // #define FOO(X) X + 1 // int a, b = [[FOO(a)]]; -- 2.7.4