[clang-tools-extra] r371976 - Implement semantic selections.

Utkarsh Saxena via cfe-commits cfe-commits at lists.llvm.org
Mon Sep 16 04:29:35 PDT 2019


Author: usaxena95
Date: Mon Sep 16 04:29:35 2019
New Revision: 371976

URL: http://llvm.org/viewvc/llvm-project?rev=371976&view=rev
Log:
Implement semantic selections.

Summary:
For a given cursor position, it returns ranges that are interesting to the user.
Currently the semantic ranges correspond to the nodes of the syntax trees.

Subscribers: mgorny, jkorous, arphaman, kadircet, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D67358

Added:
    clang-tools-extra/trunk/clangd/SemanticSelection.cpp
    clang-tools-extra/trunk/clangd/SemanticSelection.h
    clang-tools-extra/trunk/clangd/unittests/SemanticSelectionTests.cpp
Modified:
    clang-tools-extra/trunk/clangd/CMakeLists.txt
    clang-tools-extra/trunk/clangd/unittests/CMakeLists.txt

Modified: clang-tools-extra/trunk/clangd/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/CMakeLists.txt?rev=371976&r1=371975&r2=371976&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clangd/CMakeLists.txt Mon Sep 16 04:29:35 2019
@@ -66,6 +66,7 @@ add_clang_library(clangDaemon
   RIFF.cpp
   Selection.cpp
   SemanticHighlighting.cpp
+  SemanticSelection.cpp
   SourceCode.cpp
   QueryDriverDatabase.cpp
   Threading.cpp

Added: clang-tools-extra/trunk/clangd/SemanticSelection.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/SemanticSelection.cpp?rev=371976&view=auto
==============================================================================
--- clang-tools-extra/trunk/clangd/SemanticSelection.cpp (added)
+++ clang-tools-extra/trunk/clangd/SemanticSelection.cpp Mon Sep 16 04:29:35 2019
@@ -0,0 +1,64 @@
+//===--- SemanticSelection.cpp -----------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "SemanticSelection.h"
+#include "ParsedAST.h"
+#include "Protocol.h"
+#include "Selection.h"
+#include "SourceCode.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+// Adds Range \p R to the Result if it is distinct from the last added Range.
+// Assumes that only consecutive ranges can coincide.
+void addIfDistinct(const Range &R, std::vector<Range> &Result) {
+  if (Result.empty() || Result.back() != R) {
+    Result.push_back(R);
+  }
+}
+} // namespace
+
+llvm::Expected<std::vector<Range>> getSemanticRanges(ParsedAST &AST,
+                                                     Position Pos) {
+  std::vector<Range> Result;
+  const auto &SM = AST.getSourceManager();
+  const auto &LangOpts = AST.getASTContext().getLangOpts();
+
+  auto FID = SM.getMainFileID();
+  auto Offset = positionToOffset(SM.getBufferData(FID), Pos);
+  if (!Offset) {
+    return Offset.takeError();
+  }
+
+  // Get node under the cursor.
+  SelectionTree ST(AST.getASTContext(), AST.getTokens(), *Offset);
+  for (const auto *Node = ST.commonAncestor(); Node != nullptr;
+       Node = Node->Parent) {
+    if (const Decl *D = Node->ASTNode.get<Decl>()) {
+      if (llvm::isa<TranslationUnitDecl>(D)) {
+        break;
+      }
+    }
+
+    auto SR = toHalfOpenFileRange(SM, LangOpts, Node->ASTNode.getSourceRange());
+    if (!SR.hasValue() || SM.getFileID(SR->getBegin()) != SM.getMainFileID()) {
+      continue;
+    }
+    Range R;
+    R.start = sourceLocToPosition(SM, SR->getBegin());
+    R.end = sourceLocToPosition(SM, SR->getEnd());
+    addIfDistinct(R, Result);
+  }
+  return Result;
+}
+
+} // namespace clangd
+} // namespace clang

Added: clang-tools-extra/trunk/clangd/SemanticSelection.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/SemanticSelection.h?rev=371976&view=auto
==============================================================================
--- clang-tools-extra/trunk/clangd/SemanticSelection.h (added)
+++ clang-tools-extra/trunk/clangd/SemanticSelection.h Mon Sep 16 04:29:35 2019
@@ -0,0 +1,32 @@
+//===--- SemanticSelection.h -------------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Features for giving interesting semantic ranges around the cursor.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SEMANTICSELECTION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SEMANTICSELECTION_H
+#include "ParsedAST.h"
+#include "Protocol.h"
+#include "llvm/Support/Error.h"
+#include <vector>
+namespace clang {
+namespace clangd {
+
+/// Returns the list of all interesting ranges around the Position \p Pos.
+/// The interesting ranges corresponds to the AST nodes in the SelectionTree
+/// containing \p Pos.
+/// Any range in the result strictly contains all the previous ranges in the
+/// result. front() is the inner most range. back() is the outermost range.
+llvm::Expected<std::vector<Range>> getSemanticRanges(ParsedAST &AST,
+                                                     Position Pos);
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_SEMANTICSELECTION_H

Modified: clang-tools-extra/trunk/clangd/unittests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/unittests/CMakeLists.txt?rev=371976&r1=371975&r2=371976&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/unittests/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clangd/unittests/CMakeLists.txt Mon Sep 16 04:29:35 2019
@@ -56,6 +56,7 @@ add_unittest(ClangdUnitTests ClangdTests
   RIFFTests.cpp
   SelectionTests.cpp
   SemanticHighlightingTests.cpp
+  SemanticSelectionTests.cpp
   SerializationTests.cpp
   SourceCodeTests.cpp
   SymbolCollectorTests.cpp

Added: clang-tools-extra/trunk/clangd/unittests/SemanticSelectionTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/unittests/SemanticSelectionTests.cpp?rev=371976&view=auto
==============================================================================
--- clang-tools-extra/trunk/clangd/unittests/SemanticSelectionTests.cpp (added)
+++ clang-tools-extra/trunk/clangd/unittests/SemanticSelectionTests.cpp Mon Sep 16 04:29:35 2019
@@ -0,0 +1,143 @@
+//===-- SemanticSelectionTests.cpp  ----------------*- C++ -*--------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Annotations.h"
+#include "Matchers.h"
+#include "Protocol.h"
+#include "SemanticSelection.h"
+#include "SourceCode.h"
+#include "TestTU.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/Error.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <vector>
+namespace clang {
+namespace clangd {
+namespace {
+using ::testing::ElementsAreArray;
+
+TEST(SemanticSelection, All) {
+  const char *Tests[] = {
+      R"cpp( // Single statement in a function body.
+        [[void func() [[{
+          [[[[int v = [[1^00]]]];]]
+        }]]]]
+      )cpp",
+      R"cpp( // Expression
+        [[void func() [[{
+          int a = 1;
+          // int v = (10 + 2) * (a + a);
+          [[[[int v = [[[[([[[[10^]] + 2]])]] * (a + a)]]]];]]
+        }]]]]
+      )cpp",
+      R"cpp( // Function call.
+        int add(int x, int y) { return x + y; }
+        [[void callee() [[{
+          // int res = add(11, 22);
+          [[[[int res = [[add([[1^1]], 22)]]]];]]
+        }]]]]
+      )cpp",
+      R"cpp( // Tricky macros.
+        #define MUL ) * (
+        [[void func() [[{
+          // int var = (4 + 15 MUL 6 + 10);
+          [[[[int var = [[[[([[4 + [[1^5]]]] MUL]] 6 + 10)]]]];]]
+        }]]]]
+       )cpp",
+      R"cpp( // Cursor inside a macro.
+        #define HASH(x) ((x) % 10)
+        [[void func() [[{
+          [[[[int a = [[HASH([[[[2^3]] + 34]])]]]];]]
+        }]]]]
+       )cpp",
+      R"cpp( // Cursor on a macro.
+        #define HASH(x) ((x) % 10)
+        [[void func() [[{
+          [[[[int a = [[HA^SH(23)]]]];]]
+        }]]]]
+       )cpp",
+      R"cpp( // Multiple declaration.
+        [[void func() [[{
+          [[[[int var1, var^2]], var3;]]
+        }]]]]
+       )cpp",
+      R"cpp( // Before comment.
+        [[void func() [[{
+          int var1 = 1;
+          [[[[int var2 = [[[[var1]]^ /*some comment*/ + 41]]]];]]
+        }]]]]
+       )cpp",
+      // Empty file.
+      "^",
+      // FIXME: We should get the whole DeclStmt as a range.
+      R"cpp( // Single statement in TU.
+        [[int v = [[1^00]]]];
+      )cpp",
+      // FIXME: No node found associated to the position.
+      R"cpp( // Cursor at end of VarDecl.
+        void func() {
+          int v = 100 + 100^;
+        }
+      )cpp",
+      // FIXME: No node found associated to the position.
+      R"cpp( // Cursor in between spaces.
+        void func() {
+          int v = 100 + ^  100;
+        }
+      )cpp",
+      // Structs.
+      R"cpp(
+        struct AAA { struct BBB { static int ccc(); };};
+        [[void func() [[{
+          // int x = AAA::BBB::ccc();
+          [[[[int x = [[[[AAA::BBB::c^cc]]()]]]];]]
+        }]]]]
+      )cpp",
+      R"cpp(
+        struct AAA { struct BBB { static int ccc(); };};
+        [[void func() [[{
+          // int x = AAA::BBB::ccc();
+          [[[[int x = [[[[[[[[[[AA^A]]::]]BBB::]]ccc]]()]]]];]]
+        }]]]]
+      )cpp",
+      R"cpp( // Inside struct.
+        struct A { static int a(); };
+        [[struct B { 
+          [[static int b() [[{
+            [[return [[[[1^1]] + 2]]]];
+          }]]]]
+        }]];
+      )cpp",
+      // Namespaces.
+      R"cpp( 
+        [[namespace nsa { 
+          [[namespace nsb { 
+            static int ccc();
+            [[void func() [[{
+              // int x = nsa::nsb::ccc();
+              [[[[int x = [[[[nsa::nsb::cc^c]]()]]]];]]
+            }]]]]
+          }]]
+        }]]
+      )cpp",
+
+  };
+
+  for (const char *Test : Tests) {
+    auto T = Annotations(Test);
+    auto AST = TestTU::withCode(T.code()).build();
+    EXPECT_THAT(llvm::cantFail(getSemanticRanges(AST, T.point())),
+                ElementsAreArray(T.ranges()))
+        << Test;
+  }
+}
+} // namespace
+} // namespace clangd
+} // namespace clang




More information about the cfe-commits mailing list