17#include "clang/AST/DeclBase.h"
18#include "clang/Basic/SourceLocation.h"
19#include "clang/Basic/SourceManager.h"
20#include "clang/Basic/TokenKinds.h"
21#include "clang/Tooling/Syntax/BuildTree.h"
22#include "clang/Tooling/Syntax/Nodes.h"
23#include "clang/Tooling/Syntax/TokenBufferTokenManager.h"
24#include "clang/Tooling/Syntax/Tree.h"
25#include "llvm/ADT/ArrayRef.h"
26#include "llvm/ADT/StringRef.h"
27#include "llvm/Support/Casting.h"
28#include "llvm/Support/Error.h"
39void addIfDistinct(
const Range &R, std::vector<Range> &Result) {
40 if (Result.empty() || Result.back() != R) {
48 std::vector<Range> Ranges;
49 const auto &SM =
AST.getSourceManager();
50 const auto &LangOpts =
AST.getLangOpts();
52 auto FID = SM.getMainFileID();
55 return Offset.takeError();
60 AST.getASTContext(),
AST.getTokens(), *Offset, *Offset);
63 if (
const Decl *D = Node->ASTNode.get<Decl>()) {
64 if (llvm::isa<TranslationUnitDecl>(D)) {
70 if (!SR || SM.getFileID(SR->getBegin()) != SM.getMainFileID()) {
76 addIfDistinct(R, Ranges);
84 return std::move(
Empty);
89 Head.range = std::move(Ranges.front());
92 llvm::MutableArrayRef(Ranges.data(), Ranges.size()).drop_front()) {
93 Tail->parent = std::make_unique<SelectionRange>();
98 return std::move(
Head);
107 std::vector<Token::Range> &Ranges;
111 std::vector<unsigned> Stack;
115 : Ranges(Ranges), Code(Code) {}
117 void walk(
const DirectiveTree &T) {
118 for (
const auto &C : T.Chunks)
119 std::visit(*
this, C);
126 auto Tokens = Code.tokens(D.Tokens);
129 const Token &HashToken = Tokens.front();
130 assert(HashToken.
Kind == tok::hash);
132 if (Pragma.
text() !=
"pragma")
137 if (
Value.text() ==
"region") {
140 while (T < Tokens.end() && T->Line == Pragma.
Line)
143 Stack.push_back(T->OriginalIndex);
148 if (
Value.text() ==
"endregion") {
152 unsigned StartIdx = Stack.back();
161 [[maybe_unused]] DirectiveTree Dummy;
162 for (
const auto &[_, SubTree] : C.Branches)
170llvm::Expected<std::vector<FoldingRange>>
174 auto DirectiveStructure = DirectiveTree::parse(OrigStream);
177 std::vector<FoldingRange> Result;
179 llvm::StringLiteral Kind) {
180 if (Start.
line >= End.line)
187 FR.
kind = Kind.str();
188 Result.push_back(FR);
190 auto OriginalToken = [&](
const Token &T) {
191 return OrigStream.tokens()[T.OriginalIndex];
193 auto StartOffset = [&](
const Token &T) {
194 return OriginalToken(T).text().data() - Code.data();
196 auto StartPosition = [&](
const Token &T) {
199 auto EndOffset = [&](
const Token &T) {
200 return StartOffset(T) + OriginalToken(T).Length;
202 auto EndPosition = [&](
const Token &T) {
208 for (
const auto &R : PPRanges) {
209 auto BTok = OrigStream.tokens()[R.Begin];
210 auto ETok = OrigStream.tokens()[R.End];
211 if (ETok.Kind == tok::eof)
213 if (BTok.Line >= ETok.Line)
224 auto Preprocessed = DirectiveStructure.stripDirectives(OrigStream);
229 auto Tokens = ParseableStream.tokens();
232 for (
const auto &Tok : Tokens) {
233 if (
auto *Paired = Tok.pair()) {
236 if (Tok.Line < Paired->Line) {
238 Position End = StartPosition(*Paired);
245 auto IsBlockComment = [&](
const Token &T) {
246 assert(T.Kind == tok::comment);
247 return OriginalToken(T).Length >= 2 &&
248 Code.substr(StartOffset(T), 2) ==
"/*";
252 for (
auto *T = Tokens.begin(); T != Tokens.end();) {
253 if (T->Kind != tok::comment) {
257 Token *FirstComment = T;
260 Token *LastComment = T;
262 while (T != Tokens.end() && T->Kind == tok::comment &&
263 StartPosition(*T).line <= End.
line + 1) {
264 End = EndPosition(*T);
268 if (IsBlockComment(*FirstComment)) {
272 if (IsBlockComment(*LastComment))
280 std::vector<Token::Range> Ranges;
282 auto Ts = OrigStream.tokens();
283 for (
const auto &R : Ranges) {
284 auto End = StartPosition(Ts[R.End]);
Stores and provides access to parsed AST.
PragmaRegionFinder(std::vector< Token::Range > &Ranges, const TokenStream &Code)
void walk(const DirectiveTree &T)
void operator()(const DirectiveTree::Directive &D)
void operator()(const DirectiveTree::Code &C)
void operator()(const DirectiveTree::Conditional &C)
static SelectionTree createRight(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End)
const Node * commonAncestor() const
A complete sequence of Tokens representing a source file.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
std::optional< SourceRange > toHalfOpenFileRange(const SourceManager &SM, const LangOptions &LangOpts, SourceRange R)
Turns a token range into a half-open range and checks its correctness.
Position offsetToPosition(llvm::StringRef Code, size_t Offset)
Turn an offset in Code into a [line, column] pair.
static void lex(llvm::StringRef Code, const LangOptions &LangOpts, llvm::function_ref< void(const syntax::Token &, const SourceManager &SM)> Action)
std::vector< Token::Range > pairDirectiveRanges(const DirectiveTree &Tree, const TokenStream &Code)
Pairs preprocessor conditional directives and computes their token ranges.
llvm::Expected< std::vector< FoldingRange > > getFoldingRanges(const std::string &Code, bool LineFoldingOnly)
Returns a list of ranges whose contents might be collapsible in an editor.
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
llvm::Expected< SelectionRange > getSemanticRanges(ParsedAST &AST, Position Pos)
Returns the list of all interesting ranges around the Position Pos.
clang::LangOptions genericLangOpts(clang::Language Lang, clang::LangStandard::Kind Standard)
A generic lang options suitable for lexing/parsing a langage.
void chooseConditionalBranches(DirectiveTree &Tree, const TokenStream &Code)
Describes the structure of a source file, as seen by the preprocessor.
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
TokenStream cook(const TokenStream &Code, const LangOptions &LangOpts)
void pairBrackets(TokenStream &Stream)
Identifies bracket token in the stream which should be paired.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Stores information about a region of code that can be folded.
static const llvm::StringLiteral REGION_KIND
static const llvm::StringLiteral COMMENT_KIND
int line
Line position in a document (zero-based).
int character
Character offset on a line in a document (zero-based).
Position start
The range's start position.
Position end
The range's end position.
A half-open range of tokens within a stream.
A single C++ or preprocessor token.
Index OriginalIndex
Index into the original token stream (as raw-lexed from the source code).
StringRef text() const
The token text.
uint32_t Line
Zero-based line number for the start of the token.
clang::tok::TokenKind Kind
The type of token as determined by clang's lexer.
const Token & nextNC() const
Returns the next token in the stream, skipping over comments.