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
20 #include <clang/Lex/Token.h>
21 #include <clang/AST/QualTypeNames.h>
22
23 #include <fstream>
24 #include <iostream>
25 #include <string>
26
27
28 namespace header_checker {
29 namespace dumper {
30
31
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)32 HeaderASTVisitor::HeaderASTVisitor(
33 const HeaderCheckerOptions &options, clang::MangleContext *mangle_contextp,
34 clang::ASTContext *ast_contextp,
35 const clang::CompilerInstance *compiler_instance_p,
36 const clang::Decl *tu_decl, repr::ModuleIR *module,
37 ASTCaches *ast_caches)
38 : options_(options), mangle_contextp_(mangle_contextp),
39 ast_contextp_(ast_contextp), cip_(compiler_instance_p), tu_decl_(tu_decl),
40 module_(module), ast_caches_(ast_caches) {}
41
VisitRecordDecl(const clang::RecordDecl * decl)42 bool HeaderASTVisitor::VisitRecordDecl(const clang::RecordDecl *decl) {
43 // Avoid segmentation fault in getASTRecordLayout.
44 if (decl->isInvalidDecl()) {
45 return true;
46 }
47 // Skip forward declarations, dependent records. Also skip anonymous records
48 // as they will be traversed through record fields.
49 if (!decl->isThisDeclarationADefinition() ||
50 decl->getTypeForDecl()->isDependentType() ||
51 decl->isAnonymousStructOrUnion() ||
52 !decl->hasNameForLinkage() ||
53 !decl->isExternallyVisible()) {
54 return true;
55 }
56 RecordDeclWrapper record_decl_wrapper(
57 mangle_contextp_, ast_contextp_, cip_, decl, module_, ast_caches_);
58 return record_decl_wrapper.GetRecordDecl();
59 }
60
VisitEnumDecl(const clang::EnumDecl * decl)61 bool HeaderASTVisitor::VisitEnumDecl(const clang::EnumDecl *decl) {
62 if (!decl->isThisDeclarationADefinition() ||
63 decl->getTypeForDecl()->isDependentType()) {
64 return true;
65 }
66 EnumDeclWrapper enum_decl_wrapper(
67 mangle_contextp_, ast_contextp_, cip_, decl, module_, ast_caches_);
68 return enum_decl_wrapper.GetEnumDecl();
69 }
70
MutateFunctionWithLinkageName(const repr::FunctionIR * function,repr::ModuleIR * module,std::string & linkage_name)71 static bool MutateFunctionWithLinkageName(const repr::FunctionIR *function,
72 repr::ModuleIR *module,
73 std::string &linkage_name) {
74 auto added_function = std::make_unique<repr::FunctionIR>();
75 *added_function = *function;
76 added_function->SetLinkerSetKey(linkage_name);
77 return module->AddLinkableMessage(*added_function);
78 }
79
AddMangledFunctions(const repr::FunctionIR * function,repr::ModuleIR * module,std::vector<std::string> & manglings)80 static bool AddMangledFunctions(const repr::FunctionIR *function,
81 repr:: ModuleIR *module,
82 std::vector<std::string> &manglings) {
83 for (auto &&mangling : manglings) {
84 if (!MutateFunctionWithLinkageName(function, module, mangling)) {
85 return false;
86 }
87 }
88 return true;
89 }
90
ShouldSkipFunctionDecl(const clang::FunctionDecl * decl)91 bool HeaderASTVisitor::ShouldSkipFunctionDecl(const clang::FunctionDecl *decl) {
92 if (!decl->getDefinition()) {
93 if (!options_.dump_function_declarations_ ||
94 options_.source_file_ != ABIWrapper::GetDeclSourceFile(decl, cip_)) {
95 return true;
96 }
97 }
98 // Skip explicitly deleted functions such as `Foo operator=(Foo) = delete;`.
99 if (decl->isDeleted()) {
100 return true;
101 }
102 if (decl->getLinkageAndVisibility().getLinkage() !=
103 clang::Linkage::ExternalLinkage) {
104 return true;
105 }
106 if (const clang::CXXMethodDecl *method_decl =
107 llvm::dyn_cast<clang::CXXMethodDecl>(decl)) {
108 const clang::CXXRecordDecl *record_decl = method_decl->getParent();
109 // Avoid segmentation fault in getThunkInfo in getAllManglings.
110 if (method_decl->isVirtual() && record_decl->isInvalidDecl()) {
111 return true;
112 }
113 if (record_decl->getTypeForDecl()->isDependentType()) {
114 return true;
115 }
116 }
117 clang::FunctionDecl::TemplatedKind tkind = decl->getTemplatedKind();
118 switch (tkind) {
119 case clang::FunctionDecl::TK_NonTemplate:
120 case clang::FunctionDecl::TK_FunctionTemplateSpecialization:
121 case clang::FunctionDecl::TK_MemberSpecialization:
122 return false;
123 default:
124 return true;
125 }
126 }
127
VisitFunctionDecl(const clang::FunctionDecl * decl)128 bool HeaderASTVisitor::VisitFunctionDecl(const clang::FunctionDecl *decl) {
129 if (ShouldSkipFunctionDecl(decl)) {
130 return true;
131 }
132 FunctionDeclWrapper function_decl_wrapper(
133 mangle_contextp_, ast_contextp_, cip_, decl, module_, ast_caches_);
134 auto function_wrapper = function_decl_wrapper.GetFunctionDecl();
135 // Destructors and Constructors can have more than 1 symbol generated from the
136 // same Decl.
137 clang::ASTNameGenerator cg(*ast_contextp_);
138 std::vector<std::string> manglings = cg.getAllManglings(decl);
139 if (!manglings.empty()) {
140 return AddMangledFunctions(function_wrapper.get(), module_, manglings);
141 }
142 std::string linkage_name =
143 ABIWrapper::GetMangledNameDecl(decl, mangle_contextp_);
144 return MutateFunctionWithLinkageName(function_wrapper.get(), module_,
145 linkage_name);
146 }
147
VisitVarDecl(const clang::VarDecl * decl)148 bool HeaderASTVisitor::VisitVarDecl(const clang::VarDecl *decl) {
149 if (!decl->hasGlobalStorage() ||
150 decl->getType().getTypePtr()->isDependentType()) {
151 // Non global / static variable declarations don't need to be dumped.
152 return true;
153 }
154 GlobalVarDeclWrapper global_var_decl_wrapper(
155 mangle_contextp_, ast_contextp_, cip_, decl, module_, ast_caches_);
156 return global_var_decl_wrapper.GetGlobalVarDecl();
157 }
158
AreHeadersExported(const std::set<std::string> & exported_headers)159 static bool AreHeadersExported(const std::set<std::string> &exported_headers) {
160 return !exported_headers.empty();
161 }
162
163 // We don't need to recurse into Declarations which are not exported.
TraverseDecl(clang::Decl * decl)164 bool HeaderASTVisitor::TraverseDecl(clang::Decl *decl) {
165 if (!decl) {
166 return true;
167 }
168 std::string source_file = ABIWrapper::GetDeclSourceFile(decl, cip_);
169 ast_caches_->decl_to_source_file_cache_.insert(
170 std::make_pair(decl, source_file));
171 // If no exported headers are specified we assume the whole AST is exported.
172 const auto &exported_headers = options_.exported_headers_;
173 if ((decl != tu_decl_) && AreHeadersExported(exported_headers) &&
174 (exported_headers.find(source_file) == exported_headers.end())) {
175 return true;
176 }
177 // If at all we're looking at the source file's AST decl node, it should be a
178 // function decl node.
179 if ((decl != tu_decl_) &&
180 (source_file == ast_caches_->translation_unit_source_) &&
181 !decl->isFunctionOrFunctionTemplate()) {
182 return true;
183 }
184 return RecursiveASTVisitor<HeaderASTVisitor>::TraverseDecl(decl);
185 }
186
HeaderASTConsumer(clang::CompilerInstance * compiler_instancep,HeaderCheckerOptions & options)187 HeaderASTConsumer::HeaderASTConsumer(
188 clang::CompilerInstance *compiler_instancep, HeaderCheckerOptions &options)
189 : cip_(compiler_instancep), options_(options) {}
190
HandleTranslationUnit(clang::ASTContext & ctx)191 void HeaderASTConsumer::HandleTranslationUnit(clang::ASTContext &ctx) {
192 clang::PrintingPolicy policy(ctx.getPrintingPolicy());
193 // Suppress 'struct' keyword for C source files while getting QualType string
194 // names to avoid inconsistency between C and C++ (for C++ files, this is true
195 // by default)
196 policy.SuppressTagKeyword = true;
197 ctx.setPrintingPolicy(policy);
198 clang::TranslationUnitDecl *translation_unit = ctx.getTranslationUnitDecl();
199 std::unique_ptr<clang::MangleContext> mangle_contextp(
200 ctx.createMangleContext());
201 const std::string &translation_unit_source =
202 ABIWrapper::GetDeclSourceFile(translation_unit, cip_);
203 ASTCaches ast_caches(translation_unit_source);
204 if (!options_.exported_headers_.empty()) {
205 options_.exported_headers_.insert(translation_unit_source);
206 }
207
208 std::unique_ptr<repr::ModuleIR> module(
209 new repr::ModuleIR(nullptr /*FIXME*/));
210
211 HeaderASTVisitor v(options_, mangle_contextp.get(), &ctx, cip_,
212 translation_unit, module.get(), &ast_caches);
213 if (!v.TraverseDecl(translation_unit)) {
214 llvm::errs() << "ABI extraction failed\n";
215 ::exit(1);
216 }
217
218 std::unique_ptr<repr::IRDumper> ir_dumper =
219 repr::IRDumper::CreateIRDumper(options_.text_format_,
220 options_.dump_name_);
221 if (!ir_dumper->Dump(*module)) {
222 llvm::errs() << "Serialization failed\n";
223 ::exit(1);
224 }
225 }
226
227
228 } // dumper
229 } // header_checker
230