• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2016 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "dumper/ast_processing.h"
16 
17 #include "dumper/abi_wrappers.h"
18 #include "repr/ir_dumper.h"
19 #include "utils/header_abi_util.h"
20 
21 #include <clang/AST/PrettyPrinter.h>
22 #include <clang/AST/QualTypeNames.h>
23 #include <clang/Lex/Token.h>
24 
25 #include <fstream>
26 #include <iostream>
27 #include <string>
28 
29 
30 namespace header_checker {
31 namespace dumper {
32 
33 
34 class PrintNormalizedPath : public clang::PrintingCallbacks {
35  public:
PrintNormalizedPath(const std::string root_dir)36   PrintNormalizedPath(const std::string root_dir) : root_dir_(root_dir) {}
37 
remapPath(llvm::StringRef path) const38   std::string remapPath(llvm::StringRef path) const {
39     return utils::NormalizePath(path.str(), root_dir_);
40   }
41 
42  private:
43   const std::string root_dir_;
44 };
45 
HeaderASTVisitor(const HeaderCheckerOptions & options,clang::MangleContext * mangle_contextp,clang::ASTContext * ast_contextp,const clang::CompilerInstance * compiler_instance_p,const clang::Decl * tu_decl,repr::ModuleIR * module,ASTCaches * ast_caches)46 HeaderASTVisitor::HeaderASTVisitor(
47     const HeaderCheckerOptions &options, clang::MangleContext *mangle_contextp,
48     clang::ASTContext *ast_contextp,
49     const clang::CompilerInstance *compiler_instance_p,
50     const clang::Decl *tu_decl, repr::ModuleIR *module,
51     ASTCaches *ast_caches)
52     : options_(options), mangle_contextp_(mangle_contextp),
53       ast_contextp_(ast_contextp), cip_(compiler_instance_p), tu_decl_(tu_decl),
54       module_(module), ast_caches_(ast_caches) {}
55 
VisitRecordDecl(const clang::RecordDecl * decl)56 bool HeaderASTVisitor::VisitRecordDecl(const clang::RecordDecl *decl) {
57   // Avoid segmentation fault in getASTRecordLayout.
58   if (decl->isInvalidDecl()) {
59     return true;
60   }
61   // Skip forward declarations, dependent records. Also skip anonymous records
62   // as they will be traversed through record fields.
63   if (!decl->isThisDeclarationADefinition() ||
64       decl->getTypeForDecl()->isDependentType() ||
65       decl->isAnonymousStructOrUnion() ||
66       !decl->hasNameForLinkage() ||
67       !decl->isExternallyVisible()) {
68     return true;
69   }
70   RecordDeclWrapper record_decl_wrapper(
71       mangle_contextp_, ast_contextp_, cip_, decl, module_, ast_caches_);
72   return record_decl_wrapper.GetRecordDecl();
73 }
74 
VisitEnumDecl(const clang::EnumDecl * decl)75 bool HeaderASTVisitor::VisitEnumDecl(const clang::EnumDecl *decl) {
76   if (!decl->isThisDeclarationADefinition() ||
77       decl->getTypeForDecl()->isDependentType()) {
78     return true;
79   }
80   EnumDeclWrapper enum_decl_wrapper(
81       mangle_contextp_, ast_contextp_, cip_, decl, module_, ast_caches_);
82   return enum_decl_wrapper.GetEnumDecl();
83 }
84 
MutateFunctionWithLinkageName(const repr::FunctionIR * function,repr::ModuleIR * module,std::string & linkage_name)85 static bool MutateFunctionWithLinkageName(const repr::FunctionIR *function,
86                                           repr::ModuleIR *module,
87                                           std::string &linkage_name) {
88   auto added_function = std::make_unique<repr::FunctionIR>();
89   *added_function = *function;
90   added_function->SetLinkerSetKey(linkage_name);
91   return module->AddLinkableMessage(*added_function);
92 }
93 
AddMangledFunctions(const repr::FunctionIR * function,repr::ModuleIR * module,std::vector<std::string> & manglings)94 static bool AddMangledFunctions(const repr::FunctionIR *function,
95                                 repr:: ModuleIR *module,
96                                 std::vector<std::string> &manglings) {
97   for (auto &&mangling : manglings) {
98     if (!MutateFunctionWithLinkageName(function, module, mangling)) {
99       return false;
100     }
101   }
102   return true;
103 }
104 
ShouldSkipFunctionDecl(const clang::FunctionDecl * decl)105 bool HeaderASTVisitor::ShouldSkipFunctionDecl(const clang::FunctionDecl *decl) {
106   if (!decl->getDefinition()) {
107     if (!options_.dump_function_declarations_ ||
108         options_.source_file_ !=
109             ABIWrapper::GetDeclSourceFile(decl, cip_, options_.root_dir_)) {
110       return true;
111     }
112   }
113   // Skip explicitly deleted functions such as `Foo operator=(Foo) = delete;`.
114   if (decl->isDeleted()) {
115     return true;
116   }
117   if (decl->getLinkageAndVisibility().getLinkage() !=
118       clang::Linkage::ExternalLinkage) {
119     return true;
120   }
121   if (const clang::CXXMethodDecl *method_decl =
122       llvm::dyn_cast<clang::CXXMethodDecl>(decl)) {
123     const clang::CXXRecordDecl *record_decl = method_decl->getParent();
124     // Avoid segmentation fault in getThunkInfo in getAllManglings.
125     if (method_decl->isVirtual() && record_decl->isInvalidDecl()) {
126       return true;
127     }
128     if (record_decl->getTypeForDecl()->isDependentType()) {
129       return true;
130     }
131   }
132   clang::FunctionDecl::TemplatedKind tkind = decl->getTemplatedKind();
133   switch (tkind) {
134     case clang::FunctionDecl::TK_NonTemplate:
135     case clang::FunctionDecl::TK_FunctionTemplateSpecialization:
136     case clang::FunctionDecl::TK_MemberSpecialization:
137       return false;
138     default:
139       return true;
140   }
141 }
142 
VisitFunctionDecl(const clang::FunctionDecl * decl)143 bool HeaderASTVisitor::VisitFunctionDecl(const clang::FunctionDecl *decl) {
144   if (ShouldSkipFunctionDecl(decl)) {
145     return true;
146   }
147   FunctionDeclWrapper function_decl_wrapper(
148       mangle_contextp_, ast_contextp_, cip_, decl, module_, ast_caches_);
149   auto function_wrapper = function_decl_wrapper.GetFunctionDecl();
150   // Destructors and Constructors can have more than 1 symbol generated from the
151   // same Decl.
152   clang::ASTNameGenerator cg(*ast_contextp_);
153   std::vector<std::string> manglings = cg.getAllManglings(decl);
154   if (!manglings.empty()) {
155     return AddMangledFunctions(function_wrapper.get(), module_, manglings);
156   }
157   std::string linkage_name =
158       ABIWrapper::GetMangledNameDecl(decl, mangle_contextp_);
159   return MutateFunctionWithLinkageName(function_wrapper.get(), module_,
160                                        linkage_name);
161 }
162 
VisitVarDecl(const clang::VarDecl * decl)163 bool HeaderASTVisitor::VisitVarDecl(const clang::VarDecl *decl) {
164   if (!decl->hasGlobalStorage() ||
165       decl->getType().getTypePtr()->isDependentType()) {
166     // Non global / static variable declarations don't need to be dumped.
167     return true;
168   }
169   GlobalVarDeclWrapper global_var_decl_wrapper(
170       mangle_contextp_, ast_contextp_, cip_, decl, module_, ast_caches_);
171   return global_var_decl_wrapper.GetGlobalVarDecl();
172 }
173 
174 // We don't need to recurse into Declarations which are not exported.
TraverseDecl(clang::Decl * decl)175 bool HeaderASTVisitor::TraverseDecl(clang::Decl *decl) {
176   if (!decl) {
177     return true;
178   }
179   std::string source_file =
180       ABIWrapper::GetDeclSourceFile(decl, cip_, options_.root_dir_);
181   ast_caches_->decl_to_source_file_cache_.insert(
182       std::make_pair(decl, source_file));
183   // If no exported headers are specified we assume the whole AST is exported.
184   const auto &exported_headers = options_.exported_headers_;
185   if ((decl != tu_decl_) && options_.dump_exported_only_ &&
186       source_file != ast_caches_->translation_unit_source_ &&
187       (exported_headers.find(source_file) == exported_headers.end())) {
188     return true;
189   }
190   // If at all we're looking at the source file's AST decl node, it should be a
191   // function decl node.
192   if ((decl != tu_decl_) &&
193       (source_file == ast_caches_->translation_unit_source_) &&
194       !decl->isFunctionOrFunctionTemplate()) {
195     return true;
196   }
197   return RecursiveASTVisitor<HeaderASTVisitor>::TraverseDecl(decl);
198 }
199 
HeaderASTConsumer(clang::CompilerInstance * compiler_instancep,HeaderCheckerOptions & options)200 HeaderASTConsumer::HeaderASTConsumer(
201     clang::CompilerInstance *compiler_instancep, HeaderCheckerOptions &options)
202     : cip_(compiler_instancep), options_(options) {}
203 
HandleTranslationUnit(clang::ASTContext & ctx)204 void HeaderASTConsumer::HandleTranslationUnit(clang::ASTContext &ctx) {
205   clang::PrintingPolicy old_policy(ctx.getPrintingPolicy());
206   clang::PrintingPolicy policy(old_policy);
207   // Suppress 'struct' keyword for C source files while getting QualType string
208   // names to avoid inconsistency between C and C++ (for C++ files, this is true
209   // by default)
210   policy.SuppressTagKeyword = true;
211   PrintNormalizedPath callbacks(options_.root_dir_);
212   policy.Callbacks = &callbacks;
213   ctx.setPrintingPolicy(policy);
214   clang::TranslationUnitDecl *translation_unit = ctx.getTranslationUnitDecl();
215   std::unique_ptr<clang::MangleContext> mangle_contextp(
216       ctx.createMangleContext());
217   ASTCaches ast_caches(
218       ABIWrapper::GetDeclSourceFile(translation_unit, cip_, options_.root_dir_),
219       options_.root_dir_);
220 
221   std::unique_ptr<repr::ModuleIR> module(
222       new repr::ModuleIR(nullptr /*FIXME*/));
223 
224   HeaderASTVisitor v(options_, mangle_contextp.get(), &ctx, cip_,
225                      translation_unit, module.get(), &ast_caches);
226   if (!v.TraverseDecl(translation_unit)) {
227     llvm::errs() << "ABI extraction failed\n";
228     ::exit(1);
229   }
230 
231   std::unique_ptr<repr::IRDumper> ir_dumper =
232       repr::IRDumper::CreateIRDumper(options_.text_format_,
233                                      options_.dump_name_);
234   if (!ir_dumper->Dump(*module)) {
235     llvm::errs() << "Serialization failed\n";
236     ::exit(1);
237   }
238 
239   ctx.setPrintingPolicy(old_policy);
240 }
241 
242 
243 }  // dumper
244 }  // header_checker
245