Path: blob/main/contrib/llvm-project/clang/utils/TableGen/ASTTableGen.cpp
35231 views
//=== ASTTableGen.cpp - Helper functions for working with AST records -----===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines some helper functions for working with tblegen reocrds9// for the Clang AST: that is, the contents of files such as DeclNodes.td,10// StmtNodes.td, and TypeNodes.td.11//12//===----------------------------------------------------------------------===//1314#include "ASTTableGen.h"15#include "llvm/TableGen/Record.h"16#include "llvm/TableGen/Error.h"17#include <optional>1819using namespace llvm;20using namespace clang;21using namespace clang::tblgen;2223llvm::StringRef clang::tblgen::HasProperties::getName() const {24if (auto node = getAs<ASTNode>()) {25return node.getName();26} else if (auto typeCase = getAs<TypeCase>()) {27return typeCase.getCaseName();28} else {29PrintFatalError(getLoc(), "unexpected node declaring properties");30}31}3233static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) {34StringRef nodeName = node->getName();35if (!nodeName.ends_with(suffix)) {36PrintFatalError(node->getLoc(),37Twine("name of node doesn't end in ") + suffix);38}39return nodeName.drop_back(suffix.size());40}4142// Decl node names don't end in Decl for historical reasons, and it would43// be somewhat annoying to fix now. Conveniently, this means the ID matches44// is exactly the node name, and the class name is simply that plus Decl.45std::string clang::tblgen::DeclNode::getClassName() const {46return (Twine(getName()) + "Decl").str();47}48StringRef clang::tblgen::DeclNode::getId() const {49return getName();50}5152// Type nodes are all named ending in Type, just like the corresponding53// C++ class, and the ID just strips this suffix.54StringRef clang::tblgen::TypeNode::getClassName() const {55return getName();56}57StringRef clang::tblgen::TypeNode::getId() const {58return removeExpectedNodeNameSuffix(getRecord(), "Type");59}6061// Stmt nodes are named the same as the C++ class, which has no regular62// naming convention (all the non-expression statements end in Stmt,63// and *many* expressions end in Expr, but there are also several64// core expression classes like IntegerLiteral and BinaryOperator with65// no standard suffix). The ID adds "Class" for historical reasons.66StringRef clang::tblgen::StmtNode::getClassName() const {67return getName();68}69std::string clang::tblgen::StmtNode::getId() const {70return (Twine(getName()) + "Class").str();71}7273/// Emit a string spelling out the C++ value type.74void PropertyType::emitCXXValueTypeName(bool forRead, raw_ostream &out) const {75if (!isGenericSpecialization()) {76if (!forRead && isConstWhenWriting())77out << "const ";78out << getCXXTypeName();79} else if (auto elementType = getArrayElementType()) {80out << "llvm::ArrayRef<";81elementType.emitCXXValueTypeName(forRead, out);82out << ">";83} else if (auto valueType = getOptionalElementType()) {84out << "std::optional<";85valueType.emitCXXValueTypeName(forRead, out);86out << ">";87} else {88//PrintFatalError(getLoc(), "unexpected generic property type");89abort();90}91}9293// A map from a node to each of its child nodes.94using ChildMap = std::multimap<ASTNode, ASTNode>;9596static void visitASTNodeRecursive(ASTNode node, ASTNode base,97const ChildMap &map,98ASTNodeHierarchyVisitor<ASTNode> visit) {99visit(node, base);100101auto i = map.lower_bound(node), e = map.upper_bound(node);102for (; i != e; ++i) {103visitASTNodeRecursive(i->second, node, map, visit);104}105}106107static void visitHierarchy(RecordKeeper &records,108StringRef nodeClassName,109ASTNodeHierarchyVisitor<ASTNode> visit) {110// Check for the node class, just as a basic correctness check.111if (!records.getClass(nodeClassName)) {112PrintFatalError(Twine("cannot find definition for node class ")113+ nodeClassName);114}115116// Find all the nodes in the hierarchy.117auto nodes = records.getAllDerivedDefinitions(nodeClassName);118119// Derive the child map.120ChildMap hierarchy;121ASTNode root;122for (ASTNode node : nodes) {123if (auto base = node.getBase())124hierarchy.insert(std::make_pair(base, node));125else if (root)126PrintFatalError(node.getLoc(),127"multiple root nodes in " + nodeClassName + " hierarchy");128else129root = node;130}131if (!root)132PrintFatalError(Twine("no root node in ") + nodeClassName + " hierarchy");133134// Now visit the map recursively, starting at the root node.135visitASTNodeRecursive(root, ASTNode(), hierarchy, visit);136}137138void clang::tblgen::visitASTNodeHierarchyImpl(RecordKeeper &records,139StringRef nodeClassName,140ASTNodeHierarchyVisitor<ASTNode> visit) {141visitHierarchy(records, nodeClassName, visit);142}143144145