Chromium Code Reviews| Index: ppapi/tests/clang/print_names_and_sizes.cc |
| =================================================================== |
| --- ppapi/tests/clang/print_names_and_sizes.cc (revision 0) |
| +++ ppapi/tests/clang/print_names_and_sizes.cc (revision 0) |
| @@ -0,0 +1,150 @@ |
| +// 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 <string> |
| + |
| +#include "clang/AST/AST.h" |
| +#include "clang/AST/ASTConsumer.h" |
| +#include "clang/AST/CharUnits.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 kHasPointer = "HasPointer"; |
| +const char* const kNoPointer = "NoPointer"; |
| + |
| +// 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,has_pointer,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. |
| +// - has_pointer: 'HasPointer' if the type is or has a pointer. Otherwise, |
| +// 'NoPointer'. |
| +// - source_file: The source file in which the type is defined. |
|
David Springer
2010/12/13 21:23:08
Is this a full POSIX path? An OS-specific path? O
|
| +// - first_line: The first line of the definition (counting from 0). |
|
David Springer
2010/12/13 21:23:08
"first line number" - just to be clear that you wa
|
| +// - 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 iff the type is a pointer or contains a pointer. This is |
|
David Springer
2010/12/13 21:23:08
"or contains a pointer" - as in:
struct PP_Var {
|
| + // important because these types may be different sizes on 32-bit vs 64-bit |
| + // platforms. Structs, enums, and unions that do NOT contain pointers are |
| + // crafted to be the same size on 32-bit and 64-bit platforms by convention. |
| + bool HasPointer(const clang::Type& type) { |
| + if (type.isPointerType()) { |
| + return true; |
| + } 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 |
| + // contain is or has a pointer, then we have one too. |
|
David Springer
2010/12/13 21:23:08
"...contain is or has a pointer..." -- ?
|
| + 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 (HasPointer(*(iter->getType().getTypePtr()))) { |
| + return true; |
| + } |
| + } |
| + // It's a struct or union, but contains no pointers. |
| + return false; |
| + } |
| + // It's not a pointer, a struct, or a union. |
| + 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(), |
| + HasPointer(type) ? kHasPointer : kNoPointer, |
| + 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."); |
| + |
| Property changes on: ppapi/tests/clang/print_names_and_sizes.cc |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |