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