Coverage Report

Created: 2020-02-18 08:44

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/utils/TableGen/ClangTypeNodesEmitter.cpp
Line
Count
Source (jump to first uncovered line)
1
//=== ClangTypeNodesEmitter.cpp - Generate type node tables -----*- 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-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This tblgen backend emits the node table (the .def file) for Clang
10
// type nodes.
11
//
12
// This file defines the AST type info database. Each type node is
13
// enumerated by providing its name (e.g., "Builtin" or "Enum") and
14
// base class (e.g., "Type" or "TagType"). Depending on where in the
15
// abstract syntax tree the type will show up, the enumeration uses
16
// one of five different macros:
17
//
18
//    TYPE(Class, Base) - A type that can show up anywhere in the AST,
19
//    and might be dependent, canonical, or non-canonical. All clients
20
//    will need to understand these types.
21
//
22
//    ABSTRACT_TYPE(Class, Base) - An abstract class that shows up in
23
//    the type hierarchy but has no concrete instances.
24
//
25
//    NON_CANONICAL_TYPE(Class, Base) - A type that can show up
26
//    anywhere in the AST but will never be a part of a canonical
27
//    type. Clients that only need to deal with canonical types
28
//    (ignoring, e.g., typedefs and other type aliases used for
29
//    pretty-printing) can ignore these types.
30
//
31
//    DEPENDENT_TYPE(Class, Base) - A type that will only show up
32
//    within a C++ template that has not been instantiated, e.g., a
33
//    type that is always dependent. Clients that do not need to deal
34
//    with uninstantiated C++ templates can ignore these types.
35
//
36
//    NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) - A type that
37
//    is non-canonical unless it is dependent.  Defaults to TYPE because
38
//    it is neither reliably dependent nor reliably non-canonical.
39
//
40
// There is a sixth macro, independent of the others.  Most clients
41
// will not need to use it.
42
//
43
//    LEAF_TYPE(Class) - A type that never has inner types.  Clients
44
//    which can operate on such types more efficiently may wish to do so.
45
//
46
//===----------------------------------------------------------------------===//
47
48
#include "ASTTableGen.h"
49
#include "TableGenBackends.h"
50
51
#include "llvm/ADT/StringRef.h"
52
#include "llvm/TableGen/Error.h"
53
#include "llvm/TableGen/Record.h"
54
#include "llvm/TableGen/TableGenBackend.h"
55
#include <set>
56
#include <string>
57
#include <vector>
58
59
using namespace llvm;
60
using namespace clang;
61
using namespace clang::tblgen;
62
63
// These are spellings in the generated output.
64
0
#define TypeMacroName "TYPE"
65
0
#define AbstractTypeMacroName "ABSTRACT_TYPE"
66
0
#define DependentTypeMacroName "DEPENDENT_TYPE"
67
0
#define NonCanonicalTypeMacroName "NON_CANONICAL_TYPE"
68
0
#define NonCanonicalUnlessDependentTypeMacroName "NON_CANONICAL_UNLESS_DEPENDENT_TYPE"
69
0
#define TypeMacroArgs "(Class, Base)"
70
#define LastTypeMacroName "LAST_TYPE"
71
0
#define LeafTypeMacroName "LEAF_TYPE"
72
73
#define TypeClassName "Type"
74
75
namespace {
76
class TypeNodeEmitter {
77
  RecordKeeper &Records;
78
  raw_ostream &Out;
79
  const std::vector<Record*> Types;
80
  std::vector<StringRef> MacrosToUndef;
81
82
public:
83
  TypeNodeEmitter(RecordKeeper &records, raw_ostream &out)
84
    : Records(records), Out(out),
85
0
      Types(Records.getAllDerivedDefinitions(TypeNodeClassName)) {
86
0
  }
87
88
  void emit();
89
90
private:
91
  void emitFallbackDefine(StringRef macroName, StringRef fallbackMacroName,
92
                          StringRef args);
93
94
  void emitNodeInvocations();
95
  void emitLastNodeInvocation(TypeNode lastType);
96
  void emitLeafNodeInvocations();
97
98
  void addMacroToUndef(StringRef macroName);
99
  void emitUndefs();
100
};
101
}
102
103
0
void TypeNodeEmitter::emit() {
104
0
  if (Types.empty())
105
0
    PrintFatalError("no Type records in input!");
106
0
107
0
  emitSourceFileHeader("An x-macro database of Clang type nodes", Out);
108
0
109
0
  // Preamble
110
0
  addMacroToUndef(TypeMacroName);
111
0
  addMacroToUndef(AbstractTypeMacroName);
112
0
  emitFallbackDefine(AbstractTypeMacroName, TypeMacroName, TypeMacroArgs);
113
0
  emitFallbackDefine(NonCanonicalTypeMacroName, TypeMacroName, TypeMacroArgs);
114
0
  emitFallbackDefine(DependentTypeMacroName, TypeMacroName, TypeMacroArgs);
115
0
  emitFallbackDefine(NonCanonicalUnlessDependentTypeMacroName, TypeMacroName, 
116
0
                     TypeMacroArgs);
117
0
118
0
  // Invocations.
119
0
  emitNodeInvocations();
120
0
  emitLeafNodeInvocations();
121
0
122
0
  // Postmatter
123
0
  emitUndefs();
124
0
}
125
126
void TypeNodeEmitter::emitFallbackDefine(StringRef macroName,
127
                                         StringRef fallbackMacroName,
128
0
                                         StringRef args) {
129
0
  Out << "#ifndef " << macroName << "\n";
130
0
  Out << "#  define " << macroName << args
131
0
      << " " << fallbackMacroName << args << "\n";
132
0
  Out << "#endif\n";
133
0
134
0
  addMacroToUndef(macroName);
135
0
}
136
137
0
void TypeNodeEmitter::emitNodeInvocations() {
138
0
  TypeNode lastType;
139
0
140
0
  visitASTNodeHierarchy<TypeNode>(Records, [&](TypeNode type, TypeNode base) {
141
0
    // If this is the Type node itself, skip it; it can't be handled
142
0
    // uniformly by metaprograms because it doesn't have a base.
143
0
    if (!base) return;
144
0
145
0
    // Figure out which macro to use.
146
0
    StringRef macroName;
147
0
    auto setMacroName = [&](StringRef newName) {
148
0
      if (!macroName.empty())
149
0
        PrintFatalError(type.getLoc(),
150
0
                        Twine("conflict when computing macro name for "
151
0
                              "Type node: trying to use both \"")
152
0
                          + macroName + "\" and \"" + newName + "\"");
153
0
      macroName = newName;
154
0
    };
155
0
    if (type.isSubClassOf(AlwaysDependentClassName))
156
0
      setMacroName(DependentTypeMacroName);
157
0
    if (type.isSubClassOf(NeverCanonicalClassName))
158
0
      setMacroName(NonCanonicalTypeMacroName);
159
0
    if (type.isSubClassOf(NeverCanonicalUnlessDependentClassName))
160
0
      setMacroName(NonCanonicalUnlessDependentTypeMacroName);
161
0
    if (type.isAbstract())
162
0
      setMacroName(AbstractTypeMacroName);
163
0
    if (macroName.empty())
164
0
      macroName = TypeMacroName;
165
0
166
0
    // Generate the invocation line.
167
0
    Out << macroName << "(" << type.getId() << ", "
168
0
        << base.getClassName() << ")\n";
169
0
170
0
    lastType = type;
171
0
  });
172
0
173
0
  emitLastNodeInvocation(lastType);
174
0
}
175
176
0
void TypeNodeEmitter::emitLastNodeInvocation(TypeNode type) {
177
0
  // We check that this is non-empty earlier.
178
0
  Out << "#ifdef " LastTypeMacroName "\n"
179
0
         LastTypeMacroName "(" << type.getId() << ")\n"
180
0
         "#undef " LastTypeMacroName "\n"
181
0
         "#endif\n";
182
0
}
183
184
0
void TypeNodeEmitter::emitLeafNodeInvocations() {
185
0
  Out << "#ifdef " LeafTypeMacroName "\n";
186
0
187
0
  for (TypeNode type : Types) {
188
0
    if (!type.isSubClassOf(LeafTypeClassName)) continue;
189
0
    Out << LeafTypeMacroName "(" << type.getId() << ")\n";
190
0
  }
191
0
192
0
  Out << "#undef " LeafTypeMacroName "\n"
193
0
         "#endif\n";
194
0
}
195
196
0
void TypeNodeEmitter::addMacroToUndef(StringRef macroName) {
197
0
  MacrosToUndef.push_back(macroName);
198
0
}
199
200
0
void TypeNodeEmitter::emitUndefs() {
201
0
  for (auto &macroName : MacrosToUndef) {
202
0
    Out << "#undef " << macroName << "\n";
203
0
  }
204
0
}
205
206
0
void clang::EmitClangTypeNodes(RecordKeeper &records, raw_ostream &out) {
207
0
  TypeNodeEmitter(records, out).emit();
208
0
}