240 lines · cpp
1//===- Synthesis.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-exception6//7//===----------------------------------------------------------------------===//8#include "clang/Basic/TokenKinds.h"9#include "clang/Tooling/Syntax/BuildTree.h"10#include "clang/Tooling/Syntax/Tree.h"11#include "clang/Tooling/Syntax/Tokens.h"12#include "clang/Tooling/Syntax/TokenBufferTokenManager.h"13 14using namespace clang;15 16/// Exposes private syntax tree APIs required to implement node synthesis.17/// Should not be used for anything else.18class clang::syntax::FactoryImpl {19public:20 static void setCanModify(syntax::Node *N) { N->CanModify = true; }21 22 static void prependChildLowLevel(syntax::Tree *T, syntax::Node *Child,23 syntax::NodeRole R) {24 T->prependChildLowLevel(Child, R);25 }26 static void appendChildLowLevel(syntax::Tree *T, syntax::Node *Child,27 syntax::NodeRole R) {28 T->appendChildLowLevel(Child, R);29 }30 31 static std::pair<FileID, ArrayRef<Token>>32 lexBuffer(TokenBufferTokenManager &TBTM,33 std::unique_ptr<llvm::MemoryBuffer> Buffer) {34 return TBTM.lexBuffer(std::move(Buffer));35 }36};37 38// FIXME: `createLeaf` is based on `syntax::tokenize` internally, as such it39// doesn't support digraphs or line continuations.40syntax::Leaf *clang::syntax::createLeaf(syntax::Arena &A,41 TokenBufferTokenManager &TBTM,42 tok::TokenKind K, StringRef Spelling) {43 auto Tokens =44 FactoryImpl::lexBuffer(TBTM, llvm::MemoryBuffer::getMemBufferCopy(Spelling))45 .second;46 assert(Tokens.size() == 1);47 assert(Tokens.front().kind() == K &&48 "spelling is not lexed into the expected kind of token");49 50 auto *Leaf = new (A.getAllocator()) syntax::Leaf(51 reinterpret_cast<TokenManager::Key>(Tokens.begin()));52 syntax::FactoryImpl::setCanModify(Leaf);53 Leaf->assertInvariants();54 return Leaf;55}56 57syntax::Leaf *clang::syntax::createLeaf(syntax::Arena &A,58 TokenBufferTokenManager &TBTM,59 tok::TokenKind K) {60 const auto *Spelling = tok::getPunctuatorSpelling(K);61 if (!Spelling)62 Spelling = tok::getKeywordSpelling(K);63 assert(Spelling &&64 "Cannot infer the spelling of the token from its token kind.");65 return createLeaf(A, TBTM, K, Spelling);66}67 68namespace {69// Allocates the concrete syntax `Tree` according to its `NodeKind`.70syntax::Tree *allocateTree(syntax::Arena &A, syntax::NodeKind Kind) {71 switch (Kind) {72 case syntax::NodeKind::Leaf:73 assert(false);74 break;75 case syntax::NodeKind::TranslationUnit:76 return new (A.getAllocator()) syntax::TranslationUnit;77 case syntax::NodeKind::UnknownExpression:78 return new (A.getAllocator()) syntax::UnknownExpression;79 case syntax::NodeKind::ParenExpression:80 return new (A.getAllocator()) syntax::ParenExpression;81 case syntax::NodeKind::ThisExpression:82 return new (A.getAllocator()) syntax::ThisExpression;83 case syntax::NodeKind::IntegerLiteralExpression:84 return new (A.getAllocator()) syntax::IntegerLiteralExpression;85 case syntax::NodeKind::CharacterLiteralExpression:86 return new (A.getAllocator()) syntax::CharacterLiteralExpression;87 case syntax::NodeKind::FloatingLiteralExpression:88 return new (A.getAllocator()) syntax::FloatingLiteralExpression;89 case syntax::NodeKind::StringLiteralExpression:90 return new (A.getAllocator()) syntax::StringLiteralExpression;91 case syntax::NodeKind::BoolLiteralExpression:92 return new (A.getAllocator()) syntax::BoolLiteralExpression;93 case syntax::NodeKind::CxxNullPtrExpression:94 return new (A.getAllocator()) syntax::CxxNullPtrExpression;95 case syntax::NodeKind::IntegerUserDefinedLiteralExpression:96 return new (A.getAllocator()) syntax::IntegerUserDefinedLiteralExpression;97 case syntax::NodeKind::FloatUserDefinedLiteralExpression:98 return new (A.getAllocator()) syntax::FloatUserDefinedLiteralExpression;99 case syntax::NodeKind::CharUserDefinedLiteralExpression:100 return new (A.getAllocator()) syntax::CharUserDefinedLiteralExpression;101 case syntax::NodeKind::StringUserDefinedLiteralExpression:102 return new (A.getAllocator()) syntax::StringUserDefinedLiteralExpression;103 case syntax::NodeKind::PrefixUnaryOperatorExpression:104 return new (A.getAllocator()) syntax::PrefixUnaryOperatorExpression;105 case syntax::NodeKind::PostfixUnaryOperatorExpression:106 return new (A.getAllocator()) syntax::PostfixUnaryOperatorExpression;107 case syntax::NodeKind::BinaryOperatorExpression:108 return new (A.getAllocator()) syntax::BinaryOperatorExpression;109 case syntax::NodeKind::UnqualifiedId:110 return new (A.getAllocator()) syntax::UnqualifiedId;111 case syntax::NodeKind::IdExpression:112 return new (A.getAllocator()) syntax::IdExpression;113 case syntax::NodeKind::CallExpression:114 return new (A.getAllocator()) syntax::CallExpression;115 case syntax::NodeKind::UnknownStatement:116 return new (A.getAllocator()) syntax::UnknownStatement;117 case syntax::NodeKind::DeclarationStatement:118 return new (A.getAllocator()) syntax::DeclarationStatement;119 case syntax::NodeKind::EmptyStatement:120 return new (A.getAllocator()) syntax::EmptyStatement;121 case syntax::NodeKind::SwitchStatement:122 return new (A.getAllocator()) syntax::SwitchStatement;123 case syntax::NodeKind::CaseStatement:124 return new (A.getAllocator()) syntax::CaseStatement;125 case syntax::NodeKind::DefaultStatement:126 return new (A.getAllocator()) syntax::DefaultStatement;127 case syntax::NodeKind::IfStatement:128 return new (A.getAllocator()) syntax::IfStatement;129 case syntax::NodeKind::ForStatement:130 return new (A.getAllocator()) syntax::ForStatement;131 case syntax::NodeKind::WhileStatement:132 return new (A.getAllocator()) syntax::WhileStatement;133 case syntax::NodeKind::ContinueStatement:134 return new (A.getAllocator()) syntax::ContinueStatement;135 case syntax::NodeKind::BreakStatement:136 return new (A.getAllocator()) syntax::BreakStatement;137 case syntax::NodeKind::ReturnStatement:138 return new (A.getAllocator()) syntax::ReturnStatement;139 case syntax::NodeKind::RangeBasedForStatement:140 return new (A.getAllocator()) syntax::RangeBasedForStatement;141 case syntax::NodeKind::ExpressionStatement:142 return new (A.getAllocator()) syntax::ExpressionStatement;143 case syntax::NodeKind::CompoundStatement:144 return new (A.getAllocator()) syntax::CompoundStatement;145 case syntax::NodeKind::UnknownDeclaration:146 return new (A.getAllocator()) syntax::UnknownDeclaration;147 case syntax::NodeKind::EmptyDeclaration:148 return new (A.getAllocator()) syntax::EmptyDeclaration;149 case syntax::NodeKind::StaticAssertDeclaration:150 return new (A.getAllocator()) syntax::StaticAssertDeclaration;151 case syntax::NodeKind::LinkageSpecificationDeclaration:152 return new (A.getAllocator()) syntax::LinkageSpecificationDeclaration;153 case syntax::NodeKind::SimpleDeclaration:154 return new (A.getAllocator()) syntax::SimpleDeclaration;155 case syntax::NodeKind::TemplateDeclaration:156 return new (A.getAllocator()) syntax::TemplateDeclaration;157 case syntax::NodeKind::ExplicitTemplateInstantiation:158 return new (A.getAllocator()) syntax::ExplicitTemplateInstantiation;159 case syntax::NodeKind::NamespaceDefinition:160 return new (A.getAllocator()) syntax::NamespaceDefinition;161 case syntax::NodeKind::NamespaceAliasDefinition:162 return new (A.getAllocator()) syntax::NamespaceAliasDefinition;163 case syntax::NodeKind::UsingNamespaceDirective:164 return new (A.getAllocator()) syntax::UsingNamespaceDirective;165 case syntax::NodeKind::UsingDeclaration:166 return new (A.getAllocator()) syntax::UsingDeclaration;167 case syntax::NodeKind::TypeAliasDeclaration:168 return new (A.getAllocator()) syntax::TypeAliasDeclaration;169 case syntax::NodeKind::SimpleDeclarator:170 return new (A.getAllocator()) syntax::SimpleDeclarator;171 case syntax::NodeKind::ParenDeclarator:172 return new (A.getAllocator()) syntax::ParenDeclarator;173 case syntax::NodeKind::ArraySubscript:174 return new (A.getAllocator()) syntax::ArraySubscript;175 case syntax::NodeKind::TrailingReturnType:176 return new (A.getAllocator()) syntax::TrailingReturnType;177 case syntax::NodeKind::ParametersAndQualifiers:178 return new (A.getAllocator()) syntax::ParametersAndQualifiers;179 case syntax::NodeKind::MemberPointer:180 return new (A.getAllocator()) syntax::MemberPointer;181 case syntax::NodeKind::GlobalNameSpecifier:182 return new (A.getAllocator()) syntax::GlobalNameSpecifier;183 case syntax::NodeKind::DecltypeNameSpecifier:184 return new (A.getAllocator()) syntax::DecltypeNameSpecifier;185 case syntax::NodeKind::IdentifierNameSpecifier:186 return new (A.getAllocator()) syntax::IdentifierNameSpecifier;187 case syntax::NodeKind::SimpleTemplateNameSpecifier:188 return new (A.getAllocator()) syntax::SimpleTemplateNameSpecifier;189 case syntax::NodeKind::NestedNameSpecifier:190 return new (A.getAllocator()) syntax::NestedNameSpecifier;191 case syntax::NodeKind::MemberExpression:192 return new (A.getAllocator()) syntax::MemberExpression;193 case syntax::NodeKind::CallArguments:194 return new (A.getAllocator()) syntax::CallArguments;195 case syntax::NodeKind::ParameterDeclarationList:196 return new (A.getAllocator()) syntax::ParameterDeclarationList;197 case syntax::NodeKind::DeclaratorList:198 return new (A.getAllocator()) syntax::DeclaratorList;199 }200 llvm_unreachable("unknown node kind");201}202} // namespace203 204syntax::Tree *clang::syntax::createTree(205 syntax::Arena &A,206 ArrayRef<std::pair<syntax::Node *, syntax::NodeRole>> Children,207 syntax::NodeKind K) {208 auto *T = allocateTree(A, K);209 FactoryImpl::setCanModify(T);210 for (const auto &Child : Children)211 FactoryImpl::appendChildLowLevel(T, Child.first, Child.second);212 213 T->assertInvariants();214 return T;215}216 217syntax::Node *clang::syntax::deepCopyExpandingMacros(syntax::Arena &A,218 TokenBufferTokenManager &TBTM,219 const syntax::Node *N) {220 if (const auto *L = dyn_cast<syntax::Leaf>(N))221 // `L->getToken()` gives us the expanded token, thus we implicitly expand222 // any macros here.223 return createLeaf(A, TBTM, TBTM.getToken(L->getTokenKey())->kind(),224 TBTM.getText(L->getTokenKey()));225 226 const auto *T = cast<syntax::Tree>(N);227 std::vector<std::pair<syntax::Node *, syntax::NodeRole>> Children;228 for (const auto *Child = T->getFirstChild(); Child;229 Child = Child->getNextSibling())230 Children.push_back({deepCopyExpandingMacros(A, TBTM, Child), Child->getRole()});231 232 return createTree(A, Children, N->getKind());233}234 235syntax::EmptyStatement *clang::syntax::createEmptyStatement(syntax::Arena &A, TokenBufferTokenManager &TBTM) {236 return cast<EmptyStatement>(237 createTree(A, {{createLeaf(A, TBTM, tok::semi), NodeRole::Unknown}},238 NodeKind::EmptyStatement));239}240