Skip to content

Commit

Permalink
[clang][Syntax] syntax::Arena doesnt own TokenBuffer
Browse files Browse the repository at this point in the history
Currently an Arena can only be built while consuming a TokenBuffer,
some users (like clangd) might want to share a TokenBuffer with multiple
compenents. This patch changes Arena's TokenBuffer member to be a reference so
that it can be created with read-only token buffers.

Differential Revision: https://reviews.llvm.org/D84973
  • Loading branch information
kadircet committed Jul 31, 2020
1 parent fb5588b commit 1618828
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 11 deletions.
4 changes: 2 additions & 2 deletions clang/include/clang/Tooling/Syntax/Tree.h
Expand Up @@ -39,7 +39,7 @@ namespace syntax {
class Arena {
public:
Arena(SourceManager &SourceMgr, const LangOptions &LangOpts,
TokenBuffer Tokens);
const TokenBuffer &Tokens);

const SourceManager &sourceManager() const { return SourceMgr; }
const LangOptions &langOptions() const { return LangOpts; }
Expand All @@ -56,7 +56,7 @@ class Arena {
private:
SourceManager &SourceMgr;
const LangOptions &LangOpts;
TokenBuffer Tokens;
const TokenBuffer &Tokens;
/// IDs and storage for additional tokenized files.
llvm::DenseMap<FileID, std::vector<syntax::Token>> ExtraTokens;
/// Keeps all the allocated nodes and their intermediate data structures.
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Tooling/Syntax/Tree.cpp
Expand Up @@ -33,8 +33,8 @@ static void traverse(syntax::Node *N,
} // namespace

syntax::Arena::Arena(SourceManager &SourceMgr, const LangOptions &LangOpts,
TokenBuffer Tokens)
: SourceMgr(SourceMgr), LangOpts(LangOpts), Tokens(std::move(Tokens)) {}
const TokenBuffer &Tokens)
: SourceMgr(SourceMgr), LangOpts(LangOpts), Tokens(Tokens) {}

const clang::syntax::TokenBuffer &syntax::Arena::tokenBuffer() const {
return Tokens;
Expand Down
21 changes: 14 additions & 7 deletions clang/unittests/Tooling/Syntax/TreeTest.cpp
Expand Up @@ -35,6 +35,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <cstdlib>
#include <memory>

using namespace clang;

Expand All @@ -59,43 +60,48 @@ class SyntaxTreeTest : public ::testing::Test,
class BuildSyntaxTree : public ASTConsumer {
public:
BuildSyntaxTree(syntax::TranslationUnit *&Root,
std::unique_ptr<syntax::TokenBuffer> &TB,
std::unique_ptr<syntax::Arena> &Arena,
std::unique_ptr<syntax::TokenCollector> Tokens)
: Root(Root), Arena(Arena), Tokens(std::move(Tokens)) {
: Root(Root), TB(TB), Arena(Arena), Tokens(std::move(Tokens)) {
assert(this->Tokens);
}

void HandleTranslationUnit(ASTContext &Ctx) override {
Arena = std::make_unique<syntax::Arena>(Ctx.getSourceManager(),
Ctx.getLangOpts(),
std::move(*Tokens).consume());
TB =
std::make_unique<syntax::TokenBuffer>(std::move(*Tokens).consume());
Tokens = nullptr; // make sure we fail if this gets called twice.
Arena = std::make_unique<syntax::Arena>(Ctx.getSourceManager(),
Ctx.getLangOpts(), *TB);
Root = syntax::buildSyntaxTree(*Arena, *Ctx.getTranslationUnitDecl());
}

private:
syntax::TranslationUnit *&Root;
std::unique_ptr<syntax::TokenBuffer> &TB;
std::unique_ptr<syntax::Arena> &Arena;
std::unique_ptr<syntax::TokenCollector> Tokens;
};

class BuildSyntaxTreeAction : public ASTFrontendAction {
public:
BuildSyntaxTreeAction(syntax::TranslationUnit *&Root,
std::unique_ptr<syntax::TokenBuffer> &TB,
std::unique_ptr<syntax::Arena> &Arena)
: Root(Root), Arena(Arena) {}
: Root(Root), TB(TB), Arena(Arena) {}

std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
// We start recording the tokens, ast consumer will take on the result.
auto Tokens =
std::make_unique<syntax::TokenCollector>(CI.getPreprocessor());
return std::make_unique<BuildSyntaxTree>(Root, Arena,
return std::make_unique<BuildSyntaxTree>(Root, TB, Arena,
std::move(Tokens));
}

private:
syntax::TranslationUnit *&Root;
std::unique_ptr<syntax::TokenBuffer> &TB;
std::unique_ptr<syntax::Arena> &Arena;
};

Expand Down Expand Up @@ -132,7 +138,7 @@ class SyntaxTreeTest : public ::testing::Test,
Compiler.setSourceManager(SourceMgr.get());

syntax::TranslationUnit *Root = nullptr;
BuildSyntaxTreeAction Recorder(Root, this->Arena);
BuildSyntaxTreeAction Recorder(Root, this->TB, this->Arena);

// Action could not be executed but the frontend didn't identify any errors
// in the code ==> problem in setting up the action.
Expand Down Expand Up @@ -204,6 +210,7 @@ class SyntaxTreeTest : public ::testing::Test,
new SourceManager(*Diags, *FileMgr);
std::shared_ptr<CompilerInvocation> Invocation;
// Set after calling buildTree().
std::unique_ptr<syntax::TokenBuffer> TB;
std::unique_ptr<syntax::Arena> Arena;
};

Expand Down

0 comments on commit 1618828

Please sign in to comment.