232 lines
10 KiB
C++
232 lines
10 KiB
C++
//===- Synthesis.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 "clang/Basic/TokenKinds.h"
|
|
#include "clang/Tooling/Syntax/BuildTree.h"
|
|
#include "clang/Tooling/Syntax/Tree.h"
|
|
|
|
using namespace clang;
|
|
|
|
/// Exposes private syntax tree APIs required to implement node synthesis.
|
|
/// Should not be used for anything else.
|
|
class clang::syntax::FactoryImpl {
|
|
public:
|
|
static void setCanModify(syntax::Node *N) { N->CanModify = true; }
|
|
|
|
static void prependChildLowLevel(syntax::Tree *T, syntax::Node *Child,
|
|
syntax::NodeRole R) {
|
|
T->prependChildLowLevel(Child, R);
|
|
}
|
|
static void appendChildLowLevel(syntax::Tree *T, syntax::Node *Child,
|
|
syntax::NodeRole R) {
|
|
T->appendChildLowLevel(Child, R);
|
|
}
|
|
|
|
static std::pair<FileID, ArrayRef<Token>>
|
|
lexBuffer(syntax::Arena &A, std::unique_ptr<llvm::MemoryBuffer> Buffer) {
|
|
return A.lexBuffer(std::move(Buffer));
|
|
}
|
|
};
|
|
|
|
// FIXME: `createLeaf` is based on `syntax::tokenize` internally, as such it
|
|
// doesn't support digraphs or line continuations.
|
|
syntax::Leaf *clang::syntax::createLeaf(syntax::Arena &A, tok::TokenKind K,
|
|
StringRef Spelling) {
|
|
auto Tokens =
|
|
FactoryImpl::lexBuffer(A, llvm::MemoryBuffer::getMemBufferCopy(Spelling))
|
|
.second;
|
|
assert(Tokens.size() == 1);
|
|
assert(Tokens.front().kind() == K &&
|
|
"spelling is not lexed into the expected kind of token");
|
|
|
|
auto *Leaf = new (A.getAllocator()) syntax::Leaf(Tokens.begin());
|
|
syntax::FactoryImpl::setCanModify(Leaf);
|
|
Leaf->assertInvariants();
|
|
return Leaf;
|
|
}
|
|
|
|
syntax::Leaf *clang::syntax::createLeaf(syntax::Arena &A, tok::TokenKind K) {
|
|
const auto *Spelling = tok::getPunctuatorSpelling(K);
|
|
if (!Spelling)
|
|
Spelling = tok::getKeywordSpelling(K);
|
|
assert(Spelling &&
|
|
"Cannot infer the spelling of the token from its token kind.");
|
|
return createLeaf(A, K, Spelling);
|
|
}
|
|
|
|
namespace {
|
|
// Allocates the concrete syntax `Tree` according to its `NodeKind`.
|
|
syntax::Tree *allocateTree(syntax::Arena &A, syntax::NodeKind Kind) {
|
|
switch (Kind) {
|
|
case syntax::NodeKind::Leaf:
|
|
assert(false);
|
|
break;
|
|
case syntax::NodeKind::TranslationUnit:
|
|
return new (A.getAllocator()) syntax::TranslationUnit;
|
|
case syntax::NodeKind::UnknownExpression:
|
|
return new (A.getAllocator()) syntax::UnknownExpression;
|
|
case syntax::NodeKind::ParenExpression:
|
|
return new (A.getAllocator()) syntax::ParenExpression;
|
|
case syntax::NodeKind::ThisExpression:
|
|
return new (A.getAllocator()) syntax::ThisExpression;
|
|
case syntax::NodeKind::IntegerLiteralExpression:
|
|
return new (A.getAllocator()) syntax::IntegerLiteralExpression;
|
|
case syntax::NodeKind::CharacterLiteralExpression:
|
|
return new (A.getAllocator()) syntax::CharacterLiteralExpression;
|
|
case syntax::NodeKind::FloatingLiteralExpression:
|
|
return new (A.getAllocator()) syntax::FloatingLiteralExpression;
|
|
case syntax::NodeKind::StringLiteralExpression:
|
|
return new (A.getAllocator()) syntax::StringLiteralExpression;
|
|
case syntax::NodeKind::BoolLiteralExpression:
|
|
return new (A.getAllocator()) syntax::BoolLiteralExpression;
|
|
case syntax::NodeKind::CxxNullPtrExpression:
|
|
return new (A.getAllocator()) syntax::CxxNullPtrExpression;
|
|
case syntax::NodeKind::IntegerUserDefinedLiteralExpression:
|
|
return new (A.getAllocator()) syntax::IntegerUserDefinedLiteralExpression;
|
|
case syntax::NodeKind::FloatUserDefinedLiteralExpression:
|
|
return new (A.getAllocator()) syntax::FloatUserDefinedLiteralExpression;
|
|
case syntax::NodeKind::CharUserDefinedLiteralExpression:
|
|
return new (A.getAllocator()) syntax::CharUserDefinedLiteralExpression;
|
|
case syntax::NodeKind::StringUserDefinedLiteralExpression:
|
|
return new (A.getAllocator()) syntax::StringUserDefinedLiteralExpression;
|
|
case syntax::NodeKind::PrefixUnaryOperatorExpression:
|
|
return new (A.getAllocator()) syntax::PrefixUnaryOperatorExpression;
|
|
case syntax::NodeKind::PostfixUnaryOperatorExpression:
|
|
return new (A.getAllocator()) syntax::PostfixUnaryOperatorExpression;
|
|
case syntax::NodeKind::BinaryOperatorExpression:
|
|
return new (A.getAllocator()) syntax::BinaryOperatorExpression;
|
|
case syntax::NodeKind::UnqualifiedId:
|
|
return new (A.getAllocator()) syntax::UnqualifiedId;
|
|
case syntax::NodeKind::IdExpression:
|
|
return new (A.getAllocator()) syntax::IdExpression;
|
|
case syntax::NodeKind::CallExpression:
|
|
return new (A.getAllocator()) syntax::CallExpression;
|
|
case syntax::NodeKind::UnknownStatement:
|
|
return new (A.getAllocator()) syntax::UnknownStatement;
|
|
case syntax::NodeKind::DeclarationStatement:
|
|
return new (A.getAllocator()) syntax::DeclarationStatement;
|
|
case syntax::NodeKind::EmptyStatement:
|
|
return new (A.getAllocator()) syntax::EmptyStatement;
|
|
case syntax::NodeKind::SwitchStatement:
|
|
return new (A.getAllocator()) syntax::SwitchStatement;
|
|
case syntax::NodeKind::CaseStatement:
|
|
return new (A.getAllocator()) syntax::CaseStatement;
|
|
case syntax::NodeKind::DefaultStatement:
|
|
return new (A.getAllocator()) syntax::DefaultStatement;
|
|
case syntax::NodeKind::IfStatement:
|
|
return new (A.getAllocator()) syntax::IfStatement;
|
|
case syntax::NodeKind::ForStatement:
|
|
return new (A.getAllocator()) syntax::ForStatement;
|
|
case syntax::NodeKind::WhileStatement:
|
|
return new (A.getAllocator()) syntax::WhileStatement;
|
|
case syntax::NodeKind::ContinueStatement:
|
|
return new (A.getAllocator()) syntax::ContinueStatement;
|
|
case syntax::NodeKind::BreakStatement:
|
|
return new (A.getAllocator()) syntax::BreakStatement;
|
|
case syntax::NodeKind::ReturnStatement:
|
|
return new (A.getAllocator()) syntax::ReturnStatement;
|
|
case syntax::NodeKind::RangeBasedForStatement:
|
|
return new (A.getAllocator()) syntax::RangeBasedForStatement;
|
|
case syntax::NodeKind::ExpressionStatement:
|
|
return new (A.getAllocator()) syntax::ExpressionStatement;
|
|
case syntax::NodeKind::CompoundStatement:
|
|
return new (A.getAllocator()) syntax::CompoundStatement;
|
|
case syntax::NodeKind::UnknownDeclaration:
|
|
return new (A.getAllocator()) syntax::UnknownDeclaration;
|
|
case syntax::NodeKind::EmptyDeclaration:
|
|
return new (A.getAllocator()) syntax::EmptyDeclaration;
|
|
case syntax::NodeKind::StaticAssertDeclaration:
|
|
return new (A.getAllocator()) syntax::StaticAssertDeclaration;
|
|
case syntax::NodeKind::LinkageSpecificationDeclaration:
|
|
return new (A.getAllocator()) syntax::LinkageSpecificationDeclaration;
|
|
case syntax::NodeKind::SimpleDeclaration:
|
|
return new (A.getAllocator()) syntax::SimpleDeclaration;
|
|
case syntax::NodeKind::TemplateDeclaration:
|
|
return new (A.getAllocator()) syntax::TemplateDeclaration;
|
|
case syntax::NodeKind::ExplicitTemplateInstantiation:
|
|
return new (A.getAllocator()) syntax::ExplicitTemplateInstantiation;
|
|
case syntax::NodeKind::NamespaceDefinition:
|
|
return new (A.getAllocator()) syntax::NamespaceDefinition;
|
|
case syntax::NodeKind::NamespaceAliasDefinition:
|
|
return new (A.getAllocator()) syntax::NamespaceAliasDefinition;
|
|
case syntax::NodeKind::UsingNamespaceDirective:
|
|
return new (A.getAllocator()) syntax::UsingNamespaceDirective;
|
|
case syntax::NodeKind::UsingDeclaration:
|
|
return new (A.getAllocator()) syntax::UsingDeclaration;
|
|
case syntax::NodeKind::TypeAliasDeclaration:
|
|
return new (A.getAllocator()) syntax::TypeAliasDeclaration;
|
|
case syntax::NodeKind::SimpleDeclarator:
|
|
return new (A.getAllocator()) syntax::SimpleDeclarator;
|
|
case syntax::NodeKind::ParenDeclarator:
|
|
return new (A.getAllocator()) syntax::ParenDeclarator;
|
|
case syntax::NodeKind::ArraySubscript:
|
|
return new (A.getAllocator()) syntax::ArraySubscript;
|
|
case syntax::NodeKind::TrailingReturnType:
|
|
return new (A.getAllocator()) syntax::TrailingReturnType;
|
|
case syntax::NodeKind::ParametersAndQualifiers:
|
|
return new (A.getAllocator()) syntax::ParametersAndQualifiers;
|
|
case syntax::NodeKind::MemberPointer:
|
|
return new (A.getAllocator()) syntax::MemberPointer;
|
|
case syntax::NodeKind::GlobalNameSpecifier:
|
|
return new (A.getAllocator()) syntax::GlobalNameSpecifier;
|
|
case syntax::NodeKind::DecltypeNameSpecifier:
|
|
return new (A.getAllocator()) syntax::DecltypeNameSpecifier;
|
|
case syntax::NodeKind::IdentifierNameSpecifier:
|
|
return new (A.getAllocator()) syntax::IdentifierNameSpecifier;
|
|
case syntax::NodeKind::SimpleTemplateNameSpecifier:
|
|
return new (A.getAllocator()) syntax::SimpleTemplateNameSpecifier;
|
|
case syntax::NodeKind::NestedNameSpecifier:
|
|
return new (A.getAllocator()) syntax::NestedNameSpecifier;
|
|
case syntax::NodeKind::MemberExpression:
|
|
return new (A.getAllocator()) syntax::MemberExpression;
|
|
case syntax::NodeKind::CallArguments:
|
|
return new (A.getAllocator()) syntax::CallArguments;
|
|
case syntax::NodeKind::ParameterDeclarationList:
|
|
return new (A.getAllocator()) syntax::ParameterDeclarationList;
|
|
case syntax::NodeKind::DeclaratorList:
|
|
return new (A.getAllocator()) syntax::DeclaratorList;
|
|
}
|
|
llvm_unreachable("unknown node kind");
|
|
}
|
|
} // namespace
|
|
|
|
syntax::Tree *clang::syntax::createTree(
|
|
syntax::Arena &A,
|
|
ArrayRef<std::pair<syntax::Node *, syntax::NodeRole>> Children,
|
|
syntax::NodeKind K) {
|
|
auto *T = allocateTree(A, K);
|
|
FactoryImpl::setCanModify(T);
|
|
for (const auto &Child : Children)
|
|
FactoryImpl::appendChildLowLevel(T, Child.first, Child.second);
|
|
|
|
T->assertInvariants();
|
|
return T;
|
|
}
|
|
|
|
syntax::Node *clang::syntax::deepCopyExpandingMacros(syntax::Arena &A,
|
|
const syntax::Node *N) {
|
|
if (const auto *L = dyn_cast<syntax::Leaf>(N))
|
|
// `L->getToken()` gives us the expanded token, thus we implicitly expand
|
|
// any macros here.
|
|
return createLeaf(A, L->getToken()->kind(),
|
|
L->getToken()->text(A.getSourceManager()));
|
|
|
|
const auto *T = cast<syntax::Tree>(N);
|
|
std::vector<std::pair<syntax::Node *, syntax::NodeRole>> Children;
|
|
for (const auto *Child = T->getFirstChild(); Child;
|
|
Child = Child->getNextSibling())
|
|
Children.push_back({deepCopyExpandingMacros(A, Child), Child->getRole()});
|
|
|
|
return createTree(A, Children, N->getKind());
|
|
}
|
|
|
|
syntax::EmptyStatement *clang::syntax::createEmptyStatement(syntax::Arena &A) {
|
|
return cast<EmptyStatement>(
|
|
createTree(A, {{createLeaf(A, tok::semi), NodeRole::Unknown}},
|
|
NodeKind::EmptyStatement));
|
|
}
|