150
|
1 //===--- SemanticSelection.cpp -----------------------------------*- C++-*-===//
|
|
2 //
|
|
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
4 // See https://llvm.org/LICENSE.txt for license information.
|
|
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
6 //
|
|
7 //===----------------------------------------------------------------------===//
|
|
8 #include "SemanticSelection.h"
|
|
9 #include "ParsedAST.h"
|
|
10 #include "Protocol.h"
|
|
11 #include "Selection.h"
|
|
12 #include "SourceCode.h"
|
|
13 #include "clang/AST/DeclBase.h"
|
|
14 #include "clang/Basic/SourceLocation.h"
|
173
|
15 #include "llvm/ADT/ArrayRef.h"
|
150
|
16 #include "llvm/Support/Error.h"
|
|
17
|
|
18 namespace clang {
|
|
19 namespace clangd {
|
|
20 namespace {
|
|
21 // Adds Range \p R to the Result if it is distinct from the last added Range.
|
|
22 // Assumes that only consecutive ranges can coincide.
|
|
23 void addIfDistinct(const Range &R, std::vector<Range> &Result) {
|
|
24 if (Result.empty() || Result.back() != R) {
|
|
25 Result.push_back(R);
|
|
26 }
|
|
27 }
|
|
28 } // namespace
|
|
29
|
173
|
30 llvm::Expected<SelectionRange> getSemanticRanges(ParsedAST &AST, Position Pos) {
|
|
31 std::vector<Range> Ranges;
|
150
|
32 const auto &SM = AST.getSourceManager();
|
|
33 const auto &LangOpts = AST.getLangOpts();
|
|
34
|
|
35 auto FID = SM.getMainFileID();
|
|
36 auto Offset = positionToOffset(SM.getBufferData(FID), Pos);
|
|
37 if (!Offset) {
|
|
38 return Offset.takeError();
|
|
39 }
|
|
40
|
|
41 // Get node under the cursor.
|
173
|
42 SelectionTree ST = SelectionTree::createRight(
|
|
43 AST.getASTContext(), AST.getTokens(), *Offset, *Offset);
|
150
|
44 for (const auto *Node = ST.commonAncestor(); Node != nullptr;
|
|
45 Node = Node->Parent) {
|
|
46 if (const Decl *D = Node->ASTNode.get<Decl>()) {
|
|
47 if (llvm::isa<TranslationUnitDecl>(D)) {
|
|
48 break;
|
|
49 }
|
|
50 }
|
|
51
|
|
52 auto SR = toHalfOpenFileRange(SM, LangOpts, Node->ASTNode.getSourceRange());
|
|
53 if (!SR.hasValue() || SM.getFileID(SR->getBegin()) != SM.getMainFileID()) {
|
|
54 continue;
|
|
55 }
|
|
56 Range R;
|
|
57 R.start = sourceLocToPosition(SM, SR->getBegin());
|
|
58 R.end = sourceLocToPosition(SM, SR->getEnd());
|
173
|
59 addIfDistinct(R, Ranges);
|
|
60 }
|
|
61
|
|
62 if (Ranges.empty()) {
|
|
63 // LSP provides no way to signal "the point is not within a semantic range".
|
|
64 // Return an empty range at the point.
|
|
65 SelectionRange Empty;
|
|
66 Empty.range.start = Empty.range.end = Pos;
|
|
67 return std::move(Empty);
|
150
|
68 }
|
173
|
69
|
|
70 // Convert to the LSP linked-list representation.
|
|
71 SelectionRange Head;
|
|
72 Head.range = std::move(Ranges.front());
|
|
73 SelectionRange *Tail = &Head;
|
|
74 for (auto &Range :
|
|
75 llvm::makeMutableArrayRef(Ranges.data(), Ranges.size()).drop_front()) {
|
|
76 Tail->parent = std::make_unique<SelectionRange>();
|
|
77 Tail = Tail->parent.get();
|
|
78 Tail->range = std::move(Range);
|
|
79 }
|
|
80
|
|
81 return std::move(Head);
|
150
|
82 }
|
|
83
|
|
84 } // namespace clangd
|
|
85 } // namespace clang
|