OLD | NEW |
| (Empty) |
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. | |
4 | |
5 // Clang plugin which prints the names and sizes of all the top-level | |
6 // structs, enums, and typedefs in the input file. | |
7 | |
8 #include <cstdio> | |
9 #include <string> | |
10 | |
11 #include "clang/AST/AST.h" | |
12 #include "clang/AST/ASTConsumer.h" | |
13 #include "clang/AST/CharUnits.h" | |
14 #include "clang/Basic/SourceManager.h" | |
15 #include "clang/Basic/TargetInfo.h" | |
16 #include "clang/Frontend/CompilerInstance.h" | |
17 #include "clang/Frontend/FrontendPluginRegistry.h" | |
18 | |
19 namespace { | |
20 | |
21 const char* const kTypedefName = "Typedef"; | |
22 const char* const kDelim = ","; | |
23 const char* const kHasPointer = "HasPointer"; | |
24 const char* const kNoPointer = "NoPointer"; | |
25 | |
26 // This class consumes a Clang-parsed AST and prints out information about types | |
27 // defined in the global namespace. Specifically, for each type definition | |
28 // encountered, it prints: | |
29 // "kind,name,size,has_pointer,source_file,first_line,last_line\n" | |
30 // Where: | |
31 // - kind: The Clang TypeClassName (Record, Enum, Typedef, Union, etc) | |
32 // - name: The unmangled string name of the type. | |
33 // - size: The size in bytes of the type. | |
34 // - has_pointer: 'HasPointer' if the type is or has a pointer. Otherwise, | |
35 // 'NoPointer'. | |
36 // - source_file: The source file in which the type is defined. | |
37 // - first_line: The first line of the definition (counting from 0). | |
38 // - last_line: The last line of the definition (counting from 0). | |
39 class PrintNamesAndSizesConsumer : public clang::ASTConsumer { | |
40 public: | |
41 explicit PrintNamesAndSizesConsumer(clang::SourceManager* source_mgr) | |
42 : source_manager_(source_mgr) {} | |
43 | |
44 private: | |
45 // SourceManager has information about source code locations, to help us know | |
46 // where definitions appear. We do not own this pointer, so we must not | |
47 // delete it. | |
48 clang::SourceManager* source_manager_; | |
49 | |
50 // Return true iff the type is a pointer or contains a pointer. This is | |
51 // important because these types may be different sizes on 32-bit vs 64-bit | |
52 // platforms. Structs, enums, and unions that do NOT contain pointers are | |
53 // crafted to be the same size on 32-bit and 64-bit platforms by convention. | |
54 bool HasPointer(const clang::Type& type) { | |
55 if (type.isPointerType()) { | |
56 return true; | |
57 } else if (const clang::RecordType* record = | |
58 dyn_cast<clang::RecordType>(&type)) { | |
59 // If it's a struct or union, iterate through the fields. If any of them | |
60 // contain is or has a pointer, then we have one too. | |
61 const clang::RecordDecl* decl = record->getDecl(); | |
62 clang::RecordDecl::field_iterator iter(decl->field_begin()); | |
63 clang::RecordDecl::field_iterator end(decl->field_end()); | |
64 for (; iter != end; ++iter) { | |
65 if (HasPointer(*(iter->getType().getTypePtr()))) { | |
66 return true; | |
67 } | |
68 } | |
69 // It's a struct or union, but contains no pointers. | |
70 return false; | |
71 } | |
72 // It's not a pointer, a struct, or a union. | |
73 return false; | |
74 } | |
75 | |
76 void PrintTypeInfo(const std::string& name, const clang::Type& type, | |
77 const std::string& kind, const clang::CharUnits& size, | |
78 const clang::SourceLocation& begin_loc, | |
79 const clang::SourceLocation& end_loc) { | |
80 clang::PresumedLoc presumed_begin( | |
81 source_manager_->getPresumedLoc(begin_loc)); | |
82 clang::PresumedLoc presumed_end(source_manager_->getPresumedLoc(end_loc)); | |
83 std::printf("%s,%s,%lu,%s,%s,%u,%u\n", | |
84 kind.c_str(), | |
85 name.c_str(), | |
86 size.getQuantity(), | |
87 HasPointer(type) ? kHasPointer : kNoPointer, | |
88 presumed_begin.getFilename(), | |
89 presumed_begin.getLine(), | |
90 presumed_end.getLine()); | |
91 } | |
92 | |
93 // Virtual function to consume top-level declarations. For each one, we check | |
94 // to see if it is a type definition. If it is, we print information about | |
95 // it. | |
96 virtual void HandleTopLevelDecl(clang::DeclGroupRef decl_group) { | |
97 clang::DeclGroupRef::iterator iter(decl_group.begin()); | |
98 clang::DeclGroupRef::iterator the_end(decl_group.end()); | |
99 for (; iter != the_end; ++iter) { | |
100 const clang::Decl *decl = *iter; | |
101 if (const clang::TypeDecl* type_decl = dyn_cast<clang::TypeDecl>(decl)) { | |
102 std::string name(type_decl->getNameAsString()); | |
103 clang::SourceLocation start_loc = type_decl->getLocStart(); | |
104 clang::SourceLocation end_loc = type_decl->getLocEnd(); | |
105 // TagDecl covers structs, enums, unions, and classes. | |
106 if (const clang::TagDecl* tag = dyn_cast<clang::TagDecl>(type_decl)) { | |
107 // Only print out info when we find the definition; ignore forward | |
108 // references. | |
109 if (tag->isDefinition()) { | |
110 clang::Type* type = type_decl->getTypeForDecl(); | |
111 clang::CharUnits size = | |
112 tag->getASTContext().getTypeSizeInChars(type); | |
113 PrintTypeInfo(name, *type, type->getTypeClassName(), size, | |
114 start_loc, end_loc); | |
115 } | |
116 } else if (const clang::TypedefDecl* td = | |
117 dyn_cast<clang::TypedefDecl>(type_decl)) { | |
118 clang::Type* type = td->getUnderlyingType().getTypePtr(); | |
119 clang::CharUnits size = td->getASTContext().getTypeSizeInChars(type); | |
120 PrintTypeInfo(name, *type, kTypedefName, size, start_loc, end_loc); | |
121 } | |
122 } | |
123 } | |
124 } | |
125 }; | |
126 | |
127 class PrintNamesAndSizesAction : public clang::PluginASTAction { | |
128 public: | |
129 PrintNamesAndSizesAction() {} | |
130 | |
131 private: | |
132 virtual clang::ASTConsumer *CreateASTConsumer( | |
133 clang::CompilerInstance &instance, llvm::StringRef /*input_file*/) { | |
134 return new PrintNamesAndSizesConsumer( | |
135 &(instance.getDiagnostics().getSourceManager())); | |
136 } | |
137 | |
138 // We don't accept any arguments, but ParseArgs is pure-virtual. | |
139 virtual bool ParseArgs(const clang::CompilerInstance& /*instance*/, | |
140 const std::vector<std::string>& /*args*/) { | |
141 return true; | |
142 } | |
143 }; | |
144 | |
145 } // namespace | |
146 | |
147 static clang::FrontendPluginRegistry::Add<PrintNamesAndSizesAction> | |
148 X("PrintNamesAndSizes", | |
149 "Print the names and sizes of classes, enums, and typedefs."); | |
150 | |
OLD | NEW |