1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Clang plugin which prints the names and sizes of all the top-level
// structs, enums, and typedefs in the input file.
#include <cstdio>
#include <cstring>
#include <string>
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
namespace {
const char* const kTypedefName = "Typedef";
const char* const kDelim = ",";
const char* const kArchDependent = "ArchDependentSize";
const char* const kNotArchDependent = "NotArchDependentSize";
// This class consumes a Clang-parsed AST and prints out information about types
// defined in the global namespace. Specifically, for each type definition
// encountered, it prints:
// "kind,name,size,arch_dependent,source_file,first_line,last_line\n"
// Where:
// - kind: The Clang TypeClassName (Record, Enum, Typedef, Union, etc)
// - name: The unmangled string name of the type.
// - size: The size in bytes of the type.
// - arch_dependent: 'ArchDependentSize' if the type has architecture-dependent
// size, NotArchDependentSize otherwise.
// - source_file: The source file in which the type is defined.
// - first_line: The first line of the definition (counting from 0).
// - last_line: The last line of the definition (counting from 0).
class PrintNamesAndSizesConsumer : public clang::ASTConsumer {
public:
explicit PrintNamesAndSizesConsumer(clang::SourceManager* source_mgr)
: source_manager_(source_mgr) {}
private:
// SourceManager has information about source code locations, to help us know
// where definitions appear. We do not own this pointer, so we must not
// delete it.
clang::SourceManager* source_manager_;
// Return true if the type contains types that differ in size between 32-bit
// and 64-bit architectures. This is true for types that are typedefed to a
// pointer, long, or unsigned long and also any types that contain an
// architecture-dependent type. Note that this is a bit overly restrictive;
// some unions may be consistent size on 32-bit and 64-bit architectures
// despite containing one of these types. But it's not an important enough
// issue to warrant coding the special case.
// Structs, enums, and unions that do NOT contain arch-dependent types are
// crafted to be the same size on 32-bit and 64-bit platforms by convention.
bool HasArchDependentSize(const clang::Type& type) {
if (type.isPointerType()) {
return true;
} else if (const clang::BuiltinType* builtin =
dyn_cast<clang::BuiltinType>(&type)) {
if ((builtin->getKind() == clang::BuiltinType::Long) ||
(builtin->getKind() == clang::BuiltinType::ULong)) {
return true;
}
} else if (const clang::ArrayType* array =
dyn_cast<clang::ArrayType>(&type)) {
// If it's an array, it has architecture-dependent size if its elements
// do.
return HasArchDependentSize(*(array->getElementType().getTypePtr()));
} else if (const clang::TypedefType* typedef_type =
dyn_cast<clang::TypedefType>(&type)) {
return HasArchDependentSize(*(typedef_type->desugar().getTypePtr()));
} else if (const clang::RecordType* record =
dyn_cast<clang::RecordType>(&type)) {
// If it's a struct or union, iterate through the fields. If any of them
// has architecture-dependent size, then we do too.
const clang::RecordDecl* decl = record->getDecl();
clang::RecordDecl::field_iterator iter(decl->field_begin());
clang::RecordDecl::field_iterator end(decl->field_end());
for (; iter != end; ++iter) {
if (HasArchDependentSize(*(iter->getType().getTypePtr()))) {
return true;
}
}
// It's a struct or union, but contains no architecture-dependent members.
return false;
}
return false;
}
void PrintTypeInfo(const std::string& name, const clang::Type& type,
const std::string& kind, const clang::CharUnits& size,
const clang::SourceLocation& begin_loc,
const clang::SourceLocation& end_loc) {
clang::PresumedLoc presumed_begin(
source_manager_->getPresumedLoc(begin_loc));
clang::PresumedLoc presumed_end(source_manager_->getPresumedLoc(end_loc));
std::printf("%s,%s,%lu,%s,%s,%u,%u\n",
kind.c_str(),
name.c_str(),
size.getQuantity(),
HasArchDependentSize(type) ? kArchDependent : kNotArchDependent,
presumed_begin.getFilename(),
presumed_begin.getLine(),
presumed_end.getLine());
}
// Virtual function to consume top-level declarations. For each one, we check
// to see if it is a type definition. If it is, we print information about
// it.
virtual void HandleTopLevelDecl(clang::DeclGroupRef decl_group) {
clang::DeclGroupRef::iterator iter(decl_group.begin());
clang::DeclGroupRef::iterator the_end(decl_group.end());
for (; iter != the_end; ++iter) {
const clang::Decl *decl = *iter;
if (const clang::TypeDecl* type_decl = dyn_cast<clang::TypeDecl>(decl)) {
std::string name(type_decl->getNameAsString());
clang::SourceLocation start_loc = type_decl->getLocStart();
clang::SourceLocation end_loc = type_decl->getLocEnd();
// TagDecl covers structs, enums, unions, and classes.
if (const clang::TagDecl* tag = dyn_cast<clang::TagDecl>(type_decl)) {
// Only print out info when we find the definition; ignore forward
// references.
if (tag->isDefinition()) {
clang::Type* type = type_decl->getTypeForDecl();
clang::CharUnits size =
tag->getASTContext().getTypeSizeInChars(type);
PrintTypeInfo(name, *type, type->getTypeClassName(), size,
start_loc, end_loc);
}
} else if (const clang::TypedefDecl* td =
dyn_cast<clang::TypedefDecl>(type_decl)) {
clang::Type* type = td->getUnderlyingType().getTypePtr();
clang::CharUnits size = td->getASTContext().getTypeSizeInChars(type);
PrintTypeInfo(name, *type, kTypedefName, size, start_loc, end_loc);
}
}
}
}
};
class PrintNamesAndSizesAction : public clang::PluginASTAction {
public:
PrintNamesAndSizesAction() {}
private:
virtual clang::ASTConsumer *CreateASTConsumer(
clang::CompilerInstance &instance, llvm::StringRef /*input_file*/) {
return new PrintNamesAndSizesConsumer(
&(instance.getDiagnostics().getSourceManager()));
}
// We don't accept any arguments, but ParseArgs is pure-virtual.
virtual bool ParseArgs(const clang::CompilerInstance& /*instance*/,
const std::vector<std::string>& /*args*/) {
return true;
}
};
} // namespace
static clang::FrontendPluginRegistry::Add<PrintNamesAndSizesAction>
X("PrintNamesAndSizes",
"Print the names and sizes of classes, enums, and typedefs.");
|