2019-09-16 19:29:35 +08:00
|
|
|
//===--- 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"
|
[clangd] Implement textDocument/foldingRange
Summary:
This patch introduces basic textDocument/foldingRange support. It relies on
textDocument/documentSymbols to collect all symbols and uses takes ranges
to create folds.
The next steps for textDocument/foldingRange support would be:
* Implementing FoldingRangeClientCapabilities and respecting respect client
preferences
* Specifying folding range kind
* Migrating from DocumentSymbol implementation to custom RecursiveASTVisitor flow that will allow more flexibility
* Supporting more folding range types: comments, PP conditional regions, includes and other code regions (e.g. public/private/protected sections of classes, control flow statement bodies)
Tested: (Neo)Vim (coc-clangd) and VSCode.
Related issue: https://github.com/clangd/clangd/issues/310
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: nridge, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D82436
2020-07-14 15:28:38 +08:00
|
|
|
#include "FindSymbols.h"
|
2019-09-16 19:29:35 +08:00
|
|
|
#include "ParsedAST.h"
|
|
|
|
#include "Protocol.h"
|
|
|
|
#include "Selection.h"
|
|
|
|
#include "SourceCode.h"
|
|
|
|
#include "clang/AST/DeclBase.h"
|
|
|
|
#include "clang/Basic/SourceLocation.h"
|
2020-03-25 07:51:50 +08:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
2019-09-16 19:29:35 +08:00
|
|
|
#include "llvm/Support/Error.h"
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
namespace {
|
[clangd] Implement textDocument/foldingRange
Summary:
This patch introduces basic textDocument/foldingRange support. It relies on
textDocument/documentSymbols to collect all symbols and uses takes ranges
to create folds.
The next steps for textDocument/foldingRange support would be:
* Implementing FoldingRangeClientCapabilities and respecting respect client
preferences
* Specifying folding range kind
* Migrating from DocumentSymbol implementation to custom RecursiveASTVisitor flow that will allow more flexibility
* Supporting more folding range types: comments, PP conditional regions, includes and other code regions (e.g. public/private/protected sections of classes, control flow statement bodies)
Tested: (Neo)Vim (coc-clangd) and VSCode.
Related issue: https://github.com/clangd/clangd/issues/310
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: nridge, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D82436
2020-07-14 15:28:38 +08:00
|
|
|
|
2019-09-16 19:29:35 +08:00
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
}
|
[clangd] Implement textDocument/foldingRange
Summary:
This patch introduces basic textDocument/foldingRange support. It relies on
textDocument/documentSymbols to collect all symbols and uses takes ranges
to create folds.
The next steps for textDocument/foldingRange support would be:
* Implementing FoldingRangeClientCapabilities and respecting respect client
preferences
* Specifying folding range kind
* Migrating from DocumentSymbol implementation to custom RecursiveASTVisitor flow that will allow more flexibility
* Supporting more folding range types: comments, PP conditional regions, includes and other code regions (e.g. public/private/protected sections of classes, control flow statement bodies)
Tested: (Neo)Vim (coc-clangd) and VSCode.
Related issue: https://github.com/clangd/clangd/issues/310
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: nridge, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D82436
2020-07-14 15:28:38 +08:00
|
|
|
|
|
|
|
// Recursively collects FoldingRange from a symbol and its children.
|
|
|
|
void collectFoldingRanges(DocumentSymbol Symbol,
|
|
|
|
std::vector<FoldingRange> &Result) {
|
|
|
|
FoldingRange Range;
|
|
|
|
Range.startLine = Symbol.range.start.line;
|
|
|
|
Range.startCharacter = Symbol.range.start.character;
|
|
|
|
Range.endLine = Symbol.range.end.line;
|
|
|
|
Range.endCharacter = Symbol.range.end.character;
|
|
|
|
Result.push_back(Range);
|
|
|
|
for (const auto &Child : Symbol.children)
|
|
|
|
collectFoldingRanges(Child, Result);
|
|
|
|
}
|
|
|
|
|
2019-09-16 19:29:35 +08:00
|
|
|
} // namespace
|
|
|
|
|
2020-03-25 07:51:50 +08:00
|
|
|
llvm::Expected<SelectionRange> getSemanticRanges(ParsedAST &AST, Position Pos) {
|
|
|
|
std::vector<Range> Ranges;
|
2019-09-16 19:29:35 +08:00
|
|
|
const auto &SM = AST.getSourceManager();
|
2019-12-05 07:09:35 +08:00
|
|
|
const auto &LangOpts = AST.getLangOpts();
|
2019-09-16 19:29:35 +08:00
|
|
|
|
|
|
|
auto FID = SM.getMainFileID();
|
|
|
|
auto Offset = positionToOffset(SM.getBufferData(FID), Pos);
|
|
|
|
if (!Offset) {
|
|
|
|
return Offset.takeError();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get node under the cursor.
|
2020-02-24 03:03:00 +08:00
|
|
|
SelectionTree ST = SelectionTree::createRight(
|
|
|
|
AST.getASTContext(), AST.getTokens(), *Offset, *Offset);
|
2019-09-16 19:29:35 +08:00
|
|
|
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());
|
2020-03-25 07:51:50 +08:00
|
|
|
addIfDistinct(R, Ranges);
|
2019-09-16 19:29:35 +08:00
|
|
|
}
|
2020-03-25 07:51:50 +08:00
|
|
|
|
|
|
|
if (Ranges.empty()) {
|
|
|
|
// LSP provides no way to signal "the point is not within a semantic range".
|
|
|
|
// Return an empty range at the point.
|
|
|
|
SelectionRange Empty;
|
|
|
|
Empty.range.start = Empty.range.end = Pos;
|
2020-03-26 07:06:54 +08:00
|
|
|
return std::move(Empty);
|
2020-03-25 07:51:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Convert to the LSP linked-list representation.
|
|
|
|
SelectionRange Head;
|
|
|
|
Head.range = std::move(Ranges.front());
|
|
|
|
SelectionRange *Tail = &Head;
|
|
|
|
for (auto &Range :
|
|
|
|
llvm::makeMutableArrayRef(Ranges.data(), Ranges.size()).drop_front()) {
|
|
|
|
Tail->parent = std::make_unique<SelectionRange>();
|
|
|
|
Tail = Tail->parent.get();
|
|
|
|
Tail->range = std::move(Range);
|
|
|
|
}
|
|
|
|
|
2020-03-26 07:06:54 +08:00
|
|
|
return std::move(Head);
|
2019-09-16 19:29:35 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Implement textDocument/foldingRange
Summary:
This patch introduces basic textDocument/foldingRange support. It relies on
textDocument/documentSymbols to collect all symbols and uses takes ranges
to create folds.
The next steps for textDocument/foldingRange support would be:
* Implementing FoldingRangeClientCapabilities and respecting respect client
preferences
* Specifying folding range kind
* Migrating from DocumentSymbol implementation to custom RecursiveASTVisitor flow that will allow more flexibility
* Supporting more folding range types: comments, PP conditional regions, includes and other code regions (e.g. public/private/protected sections of classes, control flow statement bodies)
Tested: (Neo)Vim (coc-clangd) and VSCode.
Related issue: https://github.com/clangd/clangd/issues/310
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: nridge, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D82436
2020-07-14 15:28:38 +08:00
|
|
|
// FIXME(kirillbobyrev): Collect comments, PP conditional regions, includes and
|
|
|
|
// other code regions (e.g. public/private/protected sections of classes,
|
|
|
|
// control flow statement bodies).
|
|
|
|
// Related issue:
|
|
|
|
// https://github.com/clangd/clangd/issues/310
|
|
|
|
llvm::Expected<std::vector<FoldingRange>> getFoldingRanges(ParsedAST &AST) {
|
|
|
|
// FIXME(kirillbobyrev): getDocumentSymbols() is conveniently available but
|
|
|
|
// limited (e.g. doesn't yield blocks inside functions and provides ranges for
|
|
|
|
// nodes themselves instead of their contents which is less useful). Replace
|
|
|
|
// this with a more general RecursiveASTVisitor implementation instead.
|
|
|
|
auto DocumentSymbols = getDocumentSymbols(AST);
|
|
|
|
if (!DocumentSymbols)
|
|
|
|
return DocumentSymbols.takeError();
|
|
|
|
std::vector<FoldingRange> Result;
|
|
|
|
for (const auto &Symbol : *DocumentSymbols)
|
|
|
|
collectFoldingRanges(Symbol, Result);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2019-09-16 19:29:35 +08:00
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|