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 <cstring> 10 #include <string> 11 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" 20 21 namespace { 22 23 const char* const kTypedefName = "Typedef"; 24 const char* const kDelim = ","; 25 const char* const kArchDependent = "ArchDependentSize"; 26 const char* const kNotArchDependent = "NotArchDependentSize"; 27 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" 32 // Where: 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 { 42 public: 43 explicit PrintNamesAndSizesConsumer(clang::SourceManager* source_mgr) 44 : source_manager_(source_mgr) {} 45 46 private: 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 49 // delete it. 50 clang::SourceManager* source_manager_; 51 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()) { 63 return true; 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)) { 68 return true; 69 } 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 73 // do. 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()))) { 87 return true; 88 } 89 } 90 // It's a struct or union, but contains no architecture-dependent members. 91 return false; 92 } 93 return false; 94 } 95 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", 104 kind.c_str(), 105 name.c_str(), 106 size.getQuantity(), 107 HasArchDependentSize(type) ? kArchDependent : kNotArchDependent, 108 presumed_begin.getFilename(), 109 presumed_begin.getLine(), 110 presumed_end.getLine()); 111 } 112 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 115 // it. 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 128 // references. 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, 134 start_loc, end_loc); 135 } 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); 141 } 142 } 143 } 144 } 145 }; 146 147 class PrintNamesAndSizesAction : public clang::PluginASTAction { 148 public: 149 PrintNamesAndSizesAction() {} 150 151 private: 152 virtual clang::ASTConsumer *CreateASTConsumer( 153 clang::CompilerInstance &instance, llvm::StringRef /*input_file*/) { 154 return new PrintNamesAndSizesConsumer( 155 &(instance.getDiagnostics().getSourceManager())); 156 } 157 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*/) { 161 return true; 162 } 163 }; 164 165 } // namespace 166 167 static clang::FrontendPluginRegistry::Add<PrintNamesAndSizesAction> 168 X("PrintNamesAndSizes", 169 "Print the names and sizes of classes, enums, and typedefs."); 170 171