clang-tools  11.0.0
SemanticSelection.cpp
Go to the documentation of this file.
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 "FindSymbols.h"
10 #include "ParsedAST.h"
11 #include "Protocol.h"
12 #include "Selection.h"
13 #include "SourceCode.h"
14 #include "clang/AST/DeclBase.h"
15 #include "clang/Basic/SourceLocation.h"
16 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/Support/Error.h"
18 
19 namespace clang {
20 namespace clangd {
21 namespace {
22 
23 // Adds Range \p R to the Result if it is distinct from the last added Range.
24 // Assumes that only consecutive ranges can coincide.
25 void addIfDistinct(const Range &R, std::vector<Range> &Result) {
26  if (Result.empty() || Result.back() != R) {
27  Result.push_back(R);
28  }
29 }
30 
31 // Recursively collects FoldingRange from a symbol and its children.
32 void collectFoldingRanges(DocumentSymbol Symbol,
33  std::vector<FoldingRange> &Result) {
34  FoldingRange Range;
35  Range.startLine = Symbol.range.start.line;
36  Range.startCharacter = Symbol.range.start.character;
37  Range.endLine = Symbol.range.end.line;
38  Range.endCharacter = Symbol.range.end.character;
39  Result.push_back(Range);
40  for (const auto &Child : Symbol.children)
41  collectFoldingRanges(Child, Result);
42 }
43 
44 } // namespace
45 
46 llvm::Expected<SelectionRange> getSemanticRanges(ParsedAST &AST, Position Pos) {
47  std::vector<Range> Ranges;
48  const auto &SM = AST.getSourceManager();
49  const auto &LangOpts = AST.getLangOpts();
50 
51  auto FID = SM.getMainFileID();
52  auto Offset = positionToOffset(SM.getBufferData(FID), Pos);
53  if (!Offset) {
54  return Offset.takeError();
55  }
56 
57  // Get node under the cursor.
59  AST.getASTContext(), AST.getTokens(), *Offset, *Offset);
60  for (const auto *Node = ST.commonAncestor(); Node != nullptr;
61  Node = Node->Parent) {
62  if (const Decl *D = Node->ASTNode.get<Decl>()) {
63  if (llvm::isa<TranslationUnitDecl>(D)) {
64  break;
65  }
66  }
67 
68  auto SR = toHalfOpenFileRange(SM, LangOpts, Node->ASTNode.getSourceRange());
69  if (!SR.hasValue() || SM.getFileID(SR->getBegin()) != SM.getMainFileID()) {
70  continue;
71  }
72  Range R;
73  R.start = sourceLocToPosition(SM, SR->getBegin());
74  R.end = sourceLocToPosition(SM, SR->getEnd());
75  addIfDistinct(R, Ranges);
76  }
77 
78  if (Ranges.empty()) {
79  // LSP provides no way to signal "the point is not within a semantic range".
80  // Return an empty range at the point.
82  Empty.range.start = Empty.range.end = Pos;
83  return std::move(Empty);
84  }
85 
86  // Convert to the LSP linked-list representation.
88  Head.range = std::move(Ranges.front());
90  for (auto &Range :
91  llvm::makeMutableArrayRef(Ranges.data(), Ranges.size()).drop_front()) {
92  Tail->parent = std::make_unique<SelectionRange>();
93  Tail = Tail->parent.get();
94  Tail->range = std::move(Range);
95  }
96 
97  return std::move(Head);
98 }
99 
100 // FIXME(kirillbobyrev): Collect comments, PP conditional regions, includes and
101 // other code regions (e.g. public/private/protected sections of classes,
102 // control flow statement bodies).
103 // Related issue:
104 // https://github.com/clangd/clangd/issues/310
105 llvm::Expected<std::vector<FoldingRange>> getFoldingRanges(ParsedAST &AST) {
106  // FIXME(kirillbobyrev): getDocumentSymbols() is conveniently available but
107  // limited (e.g. doesn't yield blocks inside functions and provides ranges for
108  // nodes themselves instead of their contents which is less useful). Replace
109  // this with a more general RecursiveASTVisitor implementation instead.
110  auto DocumentSymbols = getDocumentSymbols(AST);
111  if (!DocumentSymbols)
112  return DocumentSymbols.takeError();
113  std::vector<FoldingRange> Result;
114  for (const auto &Symbol : *DocumentSymbols)
115  collectFoldingRanges(Symbol, Result);
116  return Result;
117 }
118 
119 } // namespace clangd
120 } // namespace clang
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:38
clang::clangd::Head
Definition: FuzzyMatch.h:58
clang::clangd::getFoldingRanges
llvm::Expected< std::vector< FoldingRange > > getFoldingRanges(ParsedAST &AST)
Returns a list of ranges whose contents might be collapsible in an editor.
Definition: SemanticSelection.cpp:105
Selection.h
clang::clangd::toHalfOpenFileRange
llvm::Optional< SourceRange > toHalfOpenFileRange(const SourceManager &SM, const LangOptions &LangOpts, SourceRange R)
Turns a token range into a half-open range and checks its correctness.
Definition: SourceCode.cpp:428
clang::clangd::ParsedAST::getASTContext
ASTContext & getASTContext()
Note that the returned ast will not contain decls from the preamble that were not deserialized during...
Definition: ParsedAST.cpp:471
clang::clangd::Range::start
Position start
The range's start position.
Definition: Protocol.h:175
FindSymbols.h
clang::clangd::getSemanticRanges
llvm::Expected< SelectionRange > getSemanticRanges(ParsedAST &AST, Position Pos)
Returns the list of all interesting ranges around the Position Pos.
Definition: SemanticSelection.cpp:46
clang::clangd::sourceLocToPosition
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
Definition: SourceCode.cpp:220
clang::clangd::Tail
Definition: FuzzyMatch.h:57
clang::clangd::ParsedAST::getLangOpts
const LangOptions & getLangOpts() const
Definition: ParsedAST.h:81
Protocol.h
Offset
size_t Offset
Definition: CodeComplete.cpp:1044
clang::clangd::Position
Definition: Protocol.h:144
Decl
const FunctionDecl * Decl
Definition: AvoidBindCheck.cpp:100
clang::clangd::SelectionTree::createRight
static SelectionTree createRight(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End)
Definition: Selection.cpp:787
SemanticSelection.h
clang::clangd::Symbol
The class presents a C++ symbol, e.g.
Definition: Symbol.h:36
clang::clangd::positionToOffset
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
Definition: SourceCode.cpp:175
clang::clangd::Range::end
Position end
The range's end position.
Definition: Protocol.h:178
clang::clangd::SelectionTree
Definition: Selection.h:76
clang::clangd::SelectionRange
Definition: Protocol.h:1467
clang::clangd::getDocumentSymbols
llvm::Expected< std::vector< DocumentSymbol > > getDocumentSymbols(ParsedAST &AST)
Retrieves the symbols contained in the "main file" section of an AST in the same order that they appe...
Definition: FindSymbols.cpp:270
clang::clangd::SelectionTree::commonAncestor
const Node * commonAncestor() const
Definition: Selection.cpp:817
SourceCode.h
clang::clangd::Empty
Definition: FuzzyMatch.h:42
clang::clangd::Range
Definition: Protocol.h:173
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::clangd::ParsedAST::getTokens
const syntax::TokenBuffer & getTokens() const
Tokens recorded while parsing the main file.
Definition: ParsedAST.h:103
clang::clangd::ParsedAST
Stores and provides access to parsed AST.
Definition: ParsedAST.h:48
Pos
Position Pos
Definition: SourceCode.cpp:649
clang::clangd::ParsedAST::getSourceManager
SourceManager & getSourceManager()
Definition: ParsedAST.h:74
ParsedAST.h