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 |