• 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/abi_wrappers.h"
16 
17 #include "repr/ir_reader.h"
18 #include "utils/header_abi_util.h"
19 
20 #include <clang/AST/QualTypeNames.h>
21 
22 #include <regex>
23 #include <string>
24 
25 #include <assert.h>
26 #include <limits.h>
27 #include <stdlib.h>
28 
29 
30 namespace header_checker {
31 namespace dumper {
32 
33 
34 //------------------------------------------------------------------------------
35 // Helper Function
36 //------------------------------------------------------------------------------
37 
AccessClangToIR(const clang::AccessSpecifier sp)38 static repr::AccessSpecifierIR AccessClangToIR(
39     const clang::AccessSpecifier sp) {
40   switch (sp) {
41     case clang::AS_private: {
42       return repr::AccessSpecifierIR::PrivateAccess;
43     }
44     case clang::AS_protected: {
45       return repr::AccessSpecifierIR::ProtectedAccess;
46     }
47     default: {
48       return repr::AccessSpecifierIR::PublicAccess;
49     }
50   }
51 }
52 
53 
54 //------------------------------------------------------------------------------
55 // ABI Wrapper
56 //------------------------------------------------------------------------------
57 
ABIWrapper(clang::MangleContext * mangle_contextp,clang::ASTContext * ast_contextp,const clang::CompilerInstance * cip,repr::ModuleIR * module,ASTCaches * ast_caches)58 ABIWrapper::ABIWrapper(
59     clang::MangleContext *mangle_contextp,
60     clang::ASTContext *ast_contextp,
61     const clang::CompilerInstance *cip,
62     repr::ModuleIR *module,
63     ASTCaches *ast_caches)
64     : cip_(cip),
65       mangle_contextp_(mangle_contextp),
66       ast_contextp_(ast_contextp),
67       module_(module),
68       ast_caches_(ast_caches) {}
69 
GetDeclSourceFile(const clang::Decl * decl,const clang::CompilerInstance * cip,const utils::RootDirs & root_dirs)70 std::string ABIWrapper::GetDeclSourceFile(const clang::Decl *decl,
71                                           const clang::CompilerInstance *cip,
72                                           const utils::RootDirs &root_dirs) {
73   clang::SourceManager &sm = cip->getSourceManager();
74   clang::SourceLocation location = decl->getLocation();
75   // We need to use the expansion location to identify whether we should recurse
76   // into the AST Node or not. For eg: macros specifying LinkageSpecDecl can
77   // have their spelling location defined somewhere outside a source / header
78   // file belonging to a library. This should not allow the AST node to be
79   // skipped. Its expansion location will still be the source-file / header
80   // belonging to the library.
81   clang::SourceLocation expansion_location = sm.getExpansionLoc(location);
82   return utils::NormalizePath(sm.getFilename(expansion_location).str(),
83                               root_dirs);
84 }
85 
GetCachedDeclSourceFile(const clang::Decl * decl,const clang::CompilerInstance * cip)86 std::string ABIWrapper::GetCachedDeclSourceFile(
87     const clang::Decl *decl, const clang::CompilerInstance *cip) {
88   assert(decl != nullptr);
89   auto result = ast_caches_->decl_to_source_file_cache_.find(decl);
90   if (result == ast_caches_->decl_to_source_file_cache_.end()) {
91     return GetDeclSourceFile(decl, cip, ast_caches_->root_dirs_);
92   }
93   return result->second;
94 }
95 
GetMangledNameDecl(const clang::NamedDecl * decl,clang::MangleContext * mangle_contextp)96 std::string ABIWrapper::GetMangledNameDecl(
97     const clang::NamedDecl *decl, clang::MangleContext *mangle_contextp) {
98   if (!mangle_contextp->shouldMangleDeclName(decl)) {
99     clang::IdentifierInfo *identifier = decl->getIdentifier();
100     return identifier ? identifier->getName().str() : "";
101   }
102   std::string mangled_name;
103   llvm::raw_string_ostream ostream(mangled_name);
104   mangle_contextp->mangleName(decl, ostream);
105   ostream.flush();
106   return mangled_name;
107 }
108 
SetupTemplateArguments(const clang::TemplateArgumentList * tl,repr::TemplatedArtifactIR * ta,const std::string & source_file)109 bool ABIWrapper::SetupTemplateArguments(const clang::TemplateArgumentList *tl,
110                                         repr::TemplatedArtifactIR *ta,
111                                         const std::string &source_file) {
112   repr::TemplateInfoIR template_info;
113   for (int i = 0; i < tl->size(); i++) {
114     const clang::TemplateArgument &arg = (*tl)[i];
115     // TODO: More comprehensive checking needed.
116     if (arg.getKind() != clang::TemplateArgument::Type) {
117       continue;
118     }
119     clang::QualType type = arg.getAsType();
120     template_info.AddTemplateElement(
121         repr::TemplateElementIR(GetTypeUniqueId(type)));
122     if (!CreateBasicNamedAndTypedDecl(type, source_file)) {
123       llvm::errs() << "Setting up template arguments failed\n";
124       return false;
125     }
126   }
127   ta->SetTemplateInfo(std::move(template_info));
128   return true;
129 }
130 
SetupFunctionParameter(repr::CFunctionLikeIR * functionp,const clang::QualType qual_type,bool has_default_arg,const std::string & source_file,bool is_this_ptr)131 bool ABIWrapper::SetupFunctionParameter(
132     repr::CFunctionLikeIR *functionp, const clang::QualType qual_type,
133     bool has_default_arg, const std::string &source_file, bool is_this_ptr) {
134   if (!CreateBasicNamedAndTypedDecl(qual_type, source_file)) {
135     llvm::errs() << "Setting up function parameter failed\n";
136     return false;
137   }
138   functionp->AddParameter(repr::ParamIR(
139       GetTypeUniqueId(qual_type), has_default_arg, is_this_ptr));
140   return true;
141 }
142 
GetAnonymousRecord(clang::QualType type)143 static const clang::RecordDecl *GetAnonymousRecord(clang::QualType type) {
144   const clang::Type *type_ptr = type.getTypePtr();
145   assert(type_ptr != nullptr);
146   if (!type_ptr->isRecordType()) {
147     return nullptr;
148   }
149   const clang::TagDecl *tag_decl = type_ptr->getAsTagDecl();
150   if (!tag_decl) {
151     return nullptr;
152   }
153   const clang::RecordDecl *record_decl =
154       llvm::dyn_cast<clang::RecordDecl>(tag_decl);
155 
156   if (record_decl != nullptr &&
157       (!record_decl->hasNameForLinkage() ||
158        record_decl->isAnonymousStructOrUnion())) {
159     return record_decl;
160   }
161   return nullptr;
162 }
163 
GetAnonymousEnum(const clang::QualType qual_type)164 static const clang::EnumDecl *GetAnonymousEnum(
165     const clang::QualType qual_type) {
166   const clang::Type *type_ptr = qual_type.getTypePtr();
167   assert(type_ptr != nullptr);
168   const clang::TagDecl *tag_decl = type_ptr->getAsTagDecl();
169   if (!tag_decl) {
170     return nullptr;
171   }
172   const clang::EnumDecl *enum_decl = llvm::dyn_cast<clang::EnumDecl>(tag_decl);
173   if (!enum_decl || enum_decl->hasNameForLinkage()) {
174     return nullptr;
175   }
176   return enum_decl;
177 }
178 
IsReferencingType(clang::QualType qual_type)179 static bool IsReferencingType(clang::QualType qual_type) {
180   const clang::QualType canonical_type = qual_type.getCanonicalType();
181   const clang::Type *base_type = canonical_type.getTypePtr();
182   bool is_ptr = base_type->isPointerType();
183   bool is_reference = base_type->isReferenceType();
184   bool is_array = base_type->isArrayType();
185   return is_array || is_ptr || is_reference || qual_type.hasLocalQualifiers();
186 }
187 
188 // Get type 'referenced' by qual_type. Referenced type implies, in order:
189 // 1) Strip off all qualifiers if qual_type has CVR qualifiers.
190 // 2) Strip off a pointer level if qual_type is a pointer.
191 // 3) Strip off the reference if qual_type is a reference.
192 // Note: qual_type is expected to be a canonical type.
GetReferencedType(const clang::QualType qual_type)193 static clang::QualType GetReferencedType(const clang::QualType qual_type) {
194   const clang::Type *type_ptr = qual_type.getTypePtr();
195   if (qual_type.hasLocalQualifiers()) {
196     return qual_type.getLocalUnqualifiedType();
197   }
198   if (type_ptr->isPointerType()) {
199     return type_ptr->getPointeeType();
200   }
201   if (type_ptr->isArrayType()) {
202     return
203         type_ptr->getArrayElementTypeNoTypeQual()->getCanonicalTypeInternal();
204   }
205   return qual_type.getNonReferenceType();
206 }
207 
CreateAnonymousRecord(const clang::RecordDecl * record_decl)208 bool ABIWrapper::CreateAnonymousRecord(const clang::RecordDecl *record_decl) {
209   RecordDeclWrapper record_decl_wrapper(mangle_contextp_, ast_contextp_, cip_,
210                                         record_decl, module_, ast_caches_);
211   return record_decl_wrapper.GetRecordDecl();
212 }
213 
CreateExtendedType(clang::QualType qual_type,repr::TypeIR * typep)214 bool ABIWrapper::CreateExtendedType(clang::QualType qual_type,
215                                     repr::TypeIR *typep) {
216   const clang::QualType canonical_type = qual_type.getCanonicalType();
217   // The source file is going to be set later anyway.
218   return CreateBasicNamedAndTypedDecl(canonical_type, typep, "");
219 }
220 
221 // A mangled anonymous enum name ends with $_<number> or Ut<number>_ where the
222 // number may be inconsistent between translation units. This function replaces
223 // the name with $ followed by the lexicographically smallest field name.
GetAnonymousEnumUniqueId(llvm::StringRef mangled_name,const clang::EnumDecl * enum_decl)224 static std::string GetAnonymousEnumUniqueId(llvm::StringRef mangled_name,
225                                             const clang::EnumDecl *enum_decl) {
226   // Get the type name from the mangled name.
227   const std::string mangled_name_str(mangled_name);
228   std::smatch match_result;
229   std::string old_suffix;
230   std::string nested_name_suffix;
231   if (std::regex_search(mangled_name_str, match_result,
232                         std::regex(R"((\$_\d+)(E?)$)"))) {
233     const std::ssub_match &old_name = match_result[1];
234     old_suffix = std::to_string(old_name.length()) + match_result[0].str();
235     nested_name_suffix = match_result[2].str();
236     if (!mangled_name.endswith(old_suffix)) {
237       llvm::errs() << "Unexpected length of anonymous enum type name: "
238                    << mangled_name << "\n";
239       ::exit(1);
240     }
241   } else if (std::regex_search(mangled_name_str, match_result,
242                                std::regex(R"(Ut\d*_(E?)$)"))) {
243     old_suffix = match_result[0].str();
244     nested_name_suffix = match_result[1].str();
245   } else {
246     llvm::errs() << "Cannot parse anonymous enum name: " << mangled_name
247                  << "\n";
248     ::exit(1);
249   }
250 
251   // Find the smallest enumerator name.
252   std::string smallest_enum_name;
253   for (auto enum_it : enum_decl->enumerators()) {
254     std::string enum_name = enum_it->getNameAsString();
255     if (smallest_enum_name.empty() || smallest_enum_name > enum_name) {
256       smallest_enum_name = enum_name;
257     }
258   }
259   smallest_enum_name = "$" + smallest_enum_name;
260   std::string new_suffix = std::to_string(smallest_enum_name.length()) +
261                            smallest_enum_name + nested_name_suffix;
262 
263   return mangled_name.drop_back(old_suffix.length()).str() + new_suffix;
264 }
265 
GetTypeUniqueId(clang::QualType qual_type)266 std::string ABIWrapper::GetTypeUniqueId(clang::QualType qual_type) {
267   const clang::Type *canonical_type = qual_type.getCanonicalType().getTypePtr();
268   assert(canonical_type != nullptr);
269 
270   llvm::SmallString<256> uid;
271   llvm::raw_svector_ostream out(uid);
272   mangle_contextp_->mangleCXXRTTI(qual_type, out);
273 
274   if (const clang::EnumDecl *enum_decl = GetAnonymousEnum(qual_type)) {
275     return GetAnonymousEnumUniqueId(uid.str(), enum_decl);
276   }
277 
278   return std::string(uid);
279 }
280 
281 // CreateBasicNamedAndTypedDecl creates a BasicNamedAndTypedDecl which will
282 // include all the generic information of a basic type. Other methods will
283 // create more specific information, e.g. RecordDecl, EnumDecl.
CreateBasicNamedAndTypedDecl(clang::QualType canonical_type,repr::TypeIR * typep,const std::string & source_file)284 bool ABIWrapper::CreateBasicNamedAndTypedDecl(
285     clang::QualType canonical_type, repr::TypeIR *typep,
286     const std::string &source_file) {
287   // Cannot determine the size and alignment for template parameter dependent
288   // types as well as incomplete types.
289   const clang::Type *base_type = canonical_type.getTypePtr();
290   assert(base_type != nullptr);
291   clang::Type::TypeClass type_class = base_type->getTypeClass();
292 
293   // Set the size and alignment of the type.
294   // Temporary hack: Skip the auto types, incomplete types and dependent types.
295   if (type_class != clang::Type::Auto && !base_type->isIncompleteType() &&
296       !base_type->isDependentType()) {
297     auto type_info_chars = ast_contextp_->getTypeInfoInChars(canonical_type);
298     typep->SetSize(type_info_chars.Width.getQuantity());
299     typep->SetAlignment(type_info_chars.Align.getQuantity());
300   }
301 
302   std::string human_name = QualTypeToString(canonical_type);
303   std::string mangled_name = GetTypeUniqueId(canonical_type);
304   typep->SetName(human_name);
305   typep->SetLinkerSetKey(mangled_name);
306 
307   // This type has a reference type if its a pointer / reference OR it has CVR
308   // qualifiers.
309   clang::QualType referenced_type = GetReferencedType(canonical_type);
310   typep->SetReferencedType(GetTypeUniqueId(referenced_type));
311 
312   typep->SetSelfType(mangled_name);
313 
314   // Create the type for referenced type.
315   return CreateBasicNamedAndTypedDecl(referenced_type, source_file);
316 }
317 
318 // This overload takes in a qualtype and adds its information to the abi-dump on
319 // its own.
CreateBasicNamedAndTypedDecl(clang::QualType qual_type,const std::string & source_file)320 bool ABIWrapper::CreateBasicNamedAndTypedDecl(clang::QualType qual_type,
321                                               const std::string &source_file) {
322   const clang::QualType canonical_type = qual_type.getCanonicalType();
323   const clang::Type *base_type = canonical_type.getTypePtr();
324   bool is_builtin = base_type->isBuiltinType();
325   bool should_continue_with_recursive_type_creation =
326       IsReferencingType(canonical_type) || is_builtin ||
327       base_type->isFunctionType() ||
328       (GetAnonymousRecord(canonical_type) != nullptr);
329   if (!should_continue_with_recursive_type_creation ||
330       !ast_caches_->converted_qual_types_.insert(qual_type).second) {
331     return true;
332   }
333 
334   // Do something similar to what is being done right now. Create an object
335   // extending Type and return a pointer to that and pass it to CreateBasic...
336   // CreateBasic...(qualtype, Type *) fills in size, alignemnt etc.
337   auto type_and_status = SetTypeKind(canonical_type, source_file);
338   std::unique_ptr<repr::TypeIR> typep = std::move(type_and_status.typep_);
339   if (!base_type->isVoidType() && type_and_status.should_create_type_ &&
340       !typep) {
341     llvm::errs() << "nullptr with valid type while creating basic type\n";
342     return false;
343   }
344 
345   if (!type_and_status.should_create_type_) {
346     return true;
347   }
348 
349   return (CreateBasicNamedAndTypedDecl(
350               canonical_type, typep.get(), source_file) &&
351           module_->AddLinkableMessage(*typep));
352 }
353 
354 // This method returns a TypeAndCreationStatus object. This object contains a
355 // type and information to tell the clients of this method whether the caller
356 // should continue creating the type.
SetTypeKind(const clang::QualType canonical_type,const std::string & source_file)357 TypeAndCreationStatus ABIWrapper::SetTypeKind(
358     const clang::QualType canonical_type, const std::string &source_file) {
359   if (canonical_type.hasLocalQualifiers()) {
360     auto qual_type_ir =
361         std::make_unique<repr::QualifiedTypeIR>();
362     qual_type_ir->SetConstness(canonical_type.isConstQualified());
363     qual_type_ir->SetRestrictedness(canonical_type.isRestrictQualified());
364     qual_type_ir->SetVolatility(canonical_type.isVolatileQualified());
365     qual_type_ir->SetSourceFile(source_file);
366     return TypeAndCreationStatus(std::move(qual_type_ir));
367   }
368   const clang::Type *type_ptr = canonical_type.getTypePtr();
369   if (type_ptr->isPointerType()) {
370     auto pointer_type_ir = std::make_unique<repr::PointerTypeIR>();
371     pointer_type_ir->SetSourceFile(source_file);
372     return TypeAndCreationStatus(std::move(pointer_type_ir));
373   }
374   if (type_ptr->isLValueReferenceType()) {
375     auto lvalue_reference_type_ir =
376         std::make_unique<repr::LvalueReferenceTypeIR>();
377     lvalue_reference_type_ir->SetSourceFile(source_file);
378     return TypeAndCreationStatus(std::move(lvalue_reference_type_ir));
379   }
380   if (type_ptr->isRValueReferenceType()) {
381     auto rvalue_reference_type_ir =
382         std::make_unique<repr::RvalueReferenceTypeIR>();
383     rvalue_reference_type_ir->SetSourceFile(source_file);
384     return TypeAndCreationStatus(std::move(rvalue_reference_type_ir));
385   }
386   if (type_ptr->isArrayType()) {
387     auto array_type_ir = std::make_unique<repr::ArrayTypeIR>();
388     array_type_ir->SetUnknownBound(type_ptr->isIncompleteArrayType());
389     array_type_ir->SetSourceFile(source_file);
390     return TypeAndCreationStatus(std::move(array_type_ir));
391   }
392   if (type_ptr->isEnumeralType()) {
393     return TypeAndCreationStatus(std::make_unique<repr::EnumTypeIR>());
394   }
395   if (type_ptr->isBuiltinType()) {
396     auto builtin_type_ir = std::make_unique<repr::BuiltinTypeIR>();
397     builtin_type_ir->SetSignedness(type_ptr->isUnsignedIntegerType());
398     builtin_type_ir->SetIntegralType(type_ptr->isIntegralType(*ast_contextp_));
399     return TypeAndCreationStatus(std::move(builtin_type_ir));
400   }
401   if (auto &&func_type_ptr =
402           llvm::dyn_cast<const clang::FunctionType>(type_ptr)) {
403     FunctionTypeWrapper function_type_wrapper(mangle_contextp_, ast_contextp_,
404                                               cip_, func_type_ptr, module_,
405                                               ast_caches_, source_file);
406     if (!function_type_wrapper.GetFunctionType()) {
407       llvm::errs() << "FunctionType could not be created\n";
408       ::exit(1);
409     }
410   }
411   if (type_ptr->isRecordType()) {
412     // If this record is anonymous, create it.
413     const clang::RecordDecl *anon_record = GetAnonymousRecord(canonical_type);
414     // Avoid constructing RecordDeclWrapper with invalid record, which results
415     // in segmentation fault.
416     if (anon_record && !anon_record->isInvalidDecl() &&
417         !CreateAnonymousRecord(anon_record)) {
418       llvm::errs() << "Anonymous record could not be created\n";
419       ::exit(1);
420     }
421   }
422   return TypeAndCreationStatus(nullptr, false);
423 }
424 
QualTypeToString(const clang::QualType & sweet_qt)425 std::string ABIWrapper::QualTypeToString(const clang::QualType &sweet_qt) {
426   const clang::QualType salty_qt = sweet_qt.getCanonicalType();
427   // clang::TypeName::getFullyQualifiedName removes the part of the type related
428   // to it being a template parameter. Don't use it for dependent types.
429   if (salty_qt.getTypePtr()->isDependentType()) {
430     return salty_qt.getAsString();
431   }
432   return clang::TypeName::getFullyQualifiedName(
433       salty_qt, *ast_contextp_, ast_contextp_->getPrintingPolicy());
434 }
435 
436 
437 //------------------------------------------------------------------------------
438 // Function Type Wrapper
439 //------------------------------------------------------------------------------
440 
FunctionTypeWrapper(clang::MangleContext * mangle_contextp,clang::ASTContext * ast_contextp,const clang::CompilerInstance * compiler_instance_p,const clang::FunctionType * function_type,repr::ModuleIR * module,ASTCaches * ast_caches,const std::string & source_file)441 FunctionTypeWrapper::FunctionTypeWrapper(
442     clang::MangleContext *mangle_contextp, clang::ASTContext *ast_contextp,
443     const clang::CompilerInstance *compiler_instance_p,
444     const clang::FunctionType *function_type, repr::ModuleIR *module,
445     ASTCaches *ast_caches, const std::string &source_file)
446     : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p, module,
447                  ast_caches),
448       function_type_(function_type),
449       source_file_(source_file) {}
450 
SetupFunctionType(repr::FunctionTypeIR * function_type_ir)451 bool FunctionTypeWrapper::SetupFunctionType(
452     repr::FunctionTypeIR *function_type_ir) {
453   // Add ReturnType
454   function_type_ir->SetReturnType(
455       GetTypeUniqueId(function_type_->getReturnType()));
456   function_type_ir->SetSourceFile(source_file_);
457   const clang::FunctionProtoType *function_pt =
458       llvm::dyn_cast<clang::FunctionProtoType>(function_type_);
459   if (!function_pt) {
460     return true;
461   }
462   for (unsigned i = 0, e = function_pt->getNumParams(); i != e; ++i) {
463     clang::QualType param_type = function_pt->getParamType(i);
464     if (!SetupFunctionParameter(function_type_ir, param_type, false,
465                                 source_file_)) {
466       return false;
467     }
468   }
469   return true;
470 }
471 
GetFunctionType()472 bool FunctionTypeWrapper::GetFunctionType() {
473   auto abi_decl = std::make_unique<repr::FunctionTypeIR>();
474   clang::QualType canonical_type = function_type_->getCanonicalTypeInternal();
475   if (!CreateBasicNamedAndTypedDecl(canonical_type, abi_decl.get(), "")) {
476     llvm::errs() << "Couldn't create (function type) extended type\n";
477     return false;
478   }
479   return SetupFunctionType(abi_decl.get()) &&
480       module_->AddLinkableMessage(*abi_decl);
481 }
482 
483 
484 //------------------------------------------------------------------------------
485 // Function Decl Wrapper
486 //------------------------------------------------------------------------------
487 
FunctionDeclWrapper(clang::MangleContext * mangle_contextp,clang::ASTContext * ast_contextp,const clang::CompilerInstance * compiler_instance_p,const clang::FunctionDecl * decl,repr::ModuleIR * module,ASTCaches * ast_caches)488 FunctionDeclWrapper::FunctionDeclWrapper(
489     clang::MangleContext *mangle_contextp,
490     clang::ASTContext *ast_contextp,
491     const clang::CompilerInstance *compiler_instance_p,
492     const clang::FunctionDecl *decl,
493     repr::ModuleIR *module,
494     ASTCaches *ast_caches)
495     : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p, module,
496                  ast_caches),
497       function_decl_(decl) {}
498 
SetupThisParameter(repr::FunctionIR * functionp,const std::string & source_file)499 bool FunctionDeclWrapper::SetupThisParameter(repr::FunctionIR *functionp,
500                                              const std::string &source_file) {
501   const clang::CXXMethodDecl *cxx_method_decl =
502       llvm::dyn_cast<clang::CXXMethodDecl>(function_decl_);
503   // No this pointer for static methods.
504   if (!cxx_method_decl || cxx_method_decl->isStatic()) {
505     return true;
506   }
507   clang::QualType this_type = cxx_method_decl->getThisType();
508   return SetupFunctionParameter(functionp, this_type, false, source_file, true);
509 }
510 
SetupFunctionParameters(repr::FunctionIR * functionp,const std::string & source_file)511 bool FunctionDeclWrapper::SetupFunctionParameters(
512     repr::FunctionIR *functionp,
513     const std::string &source_file) {
514   clang::FunctionDecl::param_const_iterator param_it =
515       function_decl_->param_begin();
516   // If this is a CXXMethodDecl, we need to add the "this" pointer.
517   if (!SetupThisParameter(functionp, source_file)) {
518     llvm::errs() << "Setting up 'this' parameter failed\n";
519     return false;
520   }
521 
522   while (param_it != function_decl_->param_end()) {
523     // The linker set key is blank since that shows up in the mangled name.
524     bool has_default_arg = (*param_it)->hasDefaultArg();
525     clang::QualType param_qt = (*param_it)->getType();
526     if (!SetupFunctionParameter(functionp, param_qt, has_default_arg,
527                                 source_file)) {
528       return false;
529     }
530     param_it++;
531   }
532   return true;
533 }
534 
SetupFunction(repr::FunctionIR * functionp,const std::string & source_file)535 bool FunctionDeclWrapper::SetupFunction(repr::FunctionIR *functionp,
536                                         const std::string &source_file) {
537   // Go through all the parameters in the method and add them to the fields.
538   // Also get the fully qualfied name.
539   // TODO: Change this to get the complete function signature
540   functionp->SetName(function_decl_->getQualifiedNameAsString());
541   functionp->SetSourceFile(source_file);
542   clang::QualType return_type = function_decl_->getReturnType();
543 
544   functionp->SetReturnType(GetTypeUniqueId(return_type));
545   functionp->SetAccess(AccessClangToIR(function_decl_->getAccess()));
546   return CreateBasicNamedAndTypedDecl(return_type, source_file) &&
547       SetupFunctionParameters(functionp, source_file) &&
548       SetupTemplateInfo(functionp, source_file);
549 }
550 
SetupTemplateInfo(repr::FunctionIR * functionp,const std::string & source_file)551 bool FunctionDeclWrapper::SetupTemplateInfo(repr::FunctionIR *functionp,
552                                             const std::string &source_file) {
553   switch (function_decl_->getTemplatedKind()) {
554     case clang::FunctionDecl::TK_FunctionTemplateSpecialization: {
555       const clang::TemplateArgumentList *arg_list =
556           function_decl_->getTemplateSpecializationArgs();
557       if (arg_list && !SetupTemplateArguments(arg_list, functionp,
558                                               source_file)) {
559         return false;
560       }
561       break;
562     }
563     default: {
564       break;
565     }
566   }
567   return true;
568 }
569 
GetFunctionDecl()570 std::unique_ptr<repr::FunctionIR> FunctionDeclWrapper::GetFunctionDecl() {
571   auto abi_decl = std::make_unique<repr::FunctionIR>();
572   std::string source_file = GetCachedDeclSourceFile(function_decl_, cip_);
573   if (!SetupFunction(abi_decl.get(), source_file)) {
574     return nullptr;
575   }
576   return abi_decl;
577 }
578 
579 
580 //------------------------------------------------------------------------------
581 // Record Decl Wrapper
582 //------------------------------------------------------------------------------
583 
RecordDeclWrapper(clang::MangleContext * mangle_contextp,clang::ASTContext * ast_contextp,const clang::CompilerInstance * compiler_instance_p,const clang::RecordDecl * decl,repr::ModuleIR * module,ASTCaches * ast_caches)584 RecordDeclWrapper::RecordDeclWrapper(
585     clang::MangleContext *mangle_contextp,
586     clang::ASTContext *ast_contextp,
587     const clang::CompilerInstance *compiler_instance_p,
588     const clang::RecordDecl *decl, repr::ModuleIR *module,
589     ASTCaches *ast_caches)
590     : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p, module,
591                  ast_caches),
592       record_decl_(decl) {}
593 
SetupRecordFields(repr::RecordTypeIR * recordp,const std::string & source_file)594 bool RecordDeclWrapper::SetupRecordFields(repr::RecordTypeIR *recordp,
595                                           const std::string &source_file) {
596   clang::RecordDecl::field_iterator field = record_decl_->field_begin();
597   uint32_t field_index = 0;
598   const clang::ASTRecordLayout &record_layout =
599       ast_contextp_->getASTRecordLayout(record_decl_);
600   while (field != record_decl_->field_end()) {
601     clang::QualType field_type = field->getType();
602     if (!CreateBasicNamedAndTypedDecl(field_type, source_file)) {
603       llvm::errs() << "Creation of Type failed\n";
604       return false;
605     }
606     std::string field_name(field->getName());
607     uint64_t field_offset = record_layout.getFieldOffset(field_index);
608     recordp->AddRecordField(repr::RecordFieldIR(
609         field_name, GetTypeUniqueId(field_type), field_offset,
610         AccessClangToIR(field->getAccess())));
611     field++;
612     field_index++;
613   }
614   return true;
615 }
616 
SetupCXXBases(repr::RecordTypeIR * cxxp,const clang::CXXRecordDecl * cxx_record_decl)617 bool RecordDeclWrapper::SetupCXXBases(
618     repr::RecordTypeIR *cxxp, const clang::CXXRecordDecl *cxx_record_decl) {
619   if (!cxx_record_decl || !cxxp) {
620     return false;
621   }
622   clang::CXXRecordDecl::base_class_const_iterator base_class =
623       cxx_record_decl->bases_begin();
624   while (base_class != cxx_record_decl->bases_end()) {
625     bool is_virtual = base_class->isVirtual();
626     repr::AccessSpecifierIR access =
627         AccessClangToIR(base_class->getAccessSpecifier());
628     cxxp->AddCXXBaseSpecifier(repr::CXXBaseSpecifierIR(
629         GetTypeUniqueId(base_class->getType()), is_virtual, access));
630     base_class++;
631   }
632   return true;
633 }
634 
635 typedef std::map<uint64_t, clang::ThunkInfo> ThunkMap;
636 
SetupRecordVTable(repr::RecordTypeIR * record_declp,const clang::CXXRecordDecl * cxx_record_decl)637 bool RecordDeclWrapper::SetupRecordVTable(
638     repr::RecordTypeIR *record_declp,
639     const clang::CXXRecordDecl *cxx_record_decl) {
640   if (!cxx_record_decl || !record_declp) {
641     return false;
642   }
643   clang::VTableContextBase *base_vtable_contextp =
644       ast_contextp_->getVTableContext();
645   const clang::Type *typep = cxx_record_decl->getTypeForDecl();
646   if (!base_vtable_contextp || !typep) {
647     return false;
648   }
649   // Skip Microsoft ABI.
650   clang::ItaniumVTableContext *itanium_vtable_contextp =
651         llvm::dyn_cast<clang::ItaniumVTableContext>(base_vtable_contextp);
652   if (!itanium_vtable_contextp || !cxx_record_decl->isPolymorphic() ||
653       typep->isDependentType() || typep->isIncompleteType()) {
654     return true;
655   }
656   const clang::VTableLayout &vtable_layout =
657       itanium_vtable_contextp->getVTableLayout(cxx_record_decl);
658   llvm::ArrayRef<clang::VTableLayout::VTableThunkTy> thunks =
659       vtable_layout.vtable_thunks();
660   ThunkMap thunk_map(thunks.begin(), thunks.end());
661   repr::VTableLayoutIR vtable_ir_layout;
662 
663   uint64_t index = 0;
664   for (auto vtable_component : vtable_layout.vtable_components()) {
665     clang::ThunkInfo thunk_info;
666     ThunkMap::iterator it = thunk_map.find(index);
667     if (it != thunk_map.end()) {
668       thunk_info = it->second;
669     }
670     repr::VTableComponentIR added_component =
671         SetupRecordVTableComponent(vtable_component, thunk_info);
672     vtable_ir_layout.AddVTableComponent(std::move(added_component));
673     index++;
674   }
675   record_declp->SetVTableLayout(std::move(vtable_ir_layout));
676   return true;
677 }
678 
SetupRecordVTableComponent(const clang::VTableComponent & vtable_component,const clang::ThunkInfo & thunk_info)679 repr::VTableComponentIR RecordDeclWrapper::SetupRecordVTableComponent(
680     const clang::VTableComponent &vtable_component,
681     const clang::ThunkInfo &thunk_info) {
682   repr::VTableComponentIR::Kind kind =
683       repr::VTableComponentIR::Kind::RTTI;
684   std::string mangled_component_name = "";
685   llvm::raw_string_ostream ostream(mangled_component_name);
686   int64_t value = 0;
687   clang::VTableComponent::Kind clang_component_kind =
688       vtable_component.getKind();
689   bool is_pure = false;
690 
691   switch (clang_component_kind) {
692     case clang::VTableComponent::CK_VCallOffset:
693       kind = repr::VTableComponentIR::Kind::VCallOffset;
694       value = vtable_component.getVCallOffset().getQuantity();
695       break;
696     case clang::VTableComponent::CK_VBaseOffset:
697       kind = repr::VTableComponentIR::Kind::VBaseOffset;
698       value = vtable_component.getVBaseOffset().getQuantity();
699       break;
700     case clang::VTableComponent::CK_OffsetToTop:
701       kind = repr::VTableComponentIR::Kind::OffsetToTop;
702       value = vtable_component.getOffsetToTop().getQuantity();
703       break;
704     case clang::VTableComponent::CK_RTTI:
705       {
706         kind = repr::VTableComponentIR::Kind::RTTI;
707         const clang::CXXRecordDecl *rtti_decl =
708             vtable_component.getRTTIDecl();
709         assert(rtti_decl != nullptr);
710         mangled_component_name = GetMangledRTTI(rtti_decl);
711       }
712       break;
713     case clang::VTableComponent::CK_FunctionPointer:
714     case clang::VTableComponent::CK_CompleteDtorPointer:
715     case clang::VTableComponent::CK_DeletingDtorPointer:
716     case clang::VTableComponent::CK_UnusedFunctionPointer:
717       {
718         const clang::CXXMethodDecl *method_decl =
719             vtable_component.getFunctionDecl();
720         assert(method_decl != nullptr);
721         is_pure = method_decl->isPure();
722         switch (clang_component_kind) {
723           case clang::VTableComponent::CK_FunctionPointer:
724             kind = repr::VTableComponentIR::Kind::FunctionPointer;
725             if (thunk_info.isEmpty()) {
726               mangle_contextp_->mangleName(method_decl, ostream);
727             } else {
728               mangle_contextp_->mangleThunk(method_decl, thunk_info, ostream);
729             }
730             ostream.flush();
731             break;
732           case clang::VTableComponent::CK_CompleteDtorPointer:
733           case clang::VTableComponent::CK_DeletingDtorPointer:
734             {
735               clang::CXXDtorType dtor_type;
736               if (clang_component_kind ==
737                   clang::VTableComponent::CK_CompleteDtorPointer) {
738                 dtor_type = clang::CXXDtorType::Dtor_Complete;
739                 kind = repr::VTableComponentIR::Kind::CompleteDtorPointer;
740               } else {
741                 dtor_type = clang::CXXDtorType::Dtor_Deleting;
742                 kind = repr::VTableComponentIR::Kind::DeletingDtorPointer;
743               }
744 
745               if (thunk_info.isEmpty()) {
746                 auto GD = clang::GlobalDecl(
747                     vtable_component.getDestructorDecl(), dtor_type);
748                 mangle_contextp_->mangleName(GD, ostream);
749               } else {
750                 mangle_contextp_->mangleCXXDtorThunk(
751                     vtable_component.getDestructorDecl(), dtor_type,
752                     thunk_info.This, ostream);
753               }
754               ostream.flush();
755             }
756             break;
757           case clang::VTableComponent::CK_UnusedFunctionPointer:
758             kind = repr::VTableComponentIR::Kind::UnusedFunctionPointer;
759             break;
760           default:
761             break;
762         }
763       }
764       break;
765     default:
766       break;
767   }
768   return repr::VTableComponentIR(mangled_component_name, kind, value,
769                                      is_pure);
770 }
771 
SetupTemplateInfo(repr::RecordTypeIR * record_declp,const clang::CXXRecordDecl * cxx_record_decl,const std::string & source_file)772 bool RecordDeclWrapper::SetupTemplateInfo(
773     repr::RecordTypeIR *record_declp,
774     const clang::CXXRecordDecl *cxx_record_decl,
775     const std::string &source_file) {
776   assert(cxx_record_decl != nullptr);
777   const clang::ClassTemplateSpecializationDecl *specialization_decl =
778       clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(cxx_record_decl);
779   if (specialization_decl) {
780     const clang::TemplateArgumentList *arg_list =
781         &specialization_decl->getTemplateArgs();
782     if (arg_list &&
783         !SetupTemplateArguments(arg_list, record_declp, source_file)) {
784       return false;
785     }
786   }
787   return true;
788 }
789 
SetupRecordInfo(repr::RecordTypeIR * record_declp,const std::string & source_file)790 bool RecordDeclWrapper::SetupRecordInfo(repr::RecordTypeIR *record_declp,
791                                         const std::string &source_file) {
792   if (!record_declp) {
793     return false;
794   }
795   if (record_decl_->isStruct()) {
796     record_declp->SetRecordKind(
797         repr::RecordTypeIR::RecordKind::struct_kind);
798   } else if (record_decl_->isClass()) {
799     record_declp->SetRecordKind(
800         repr::RecordTypeIR::RecordKind::class_kind);
801   } else {
802     record_declp->SetRecordKind(
803         repr::RecordTypeIR::RecordKind::union_kind);
804   }
805 
806   const clang::Type *basic_type = nullptr;
807   if (!(basic_type = record_decl_->getTypeForDecl())) {
808     return false;
809   }
810   clang::QualType qual_type = basic_type->getCanonicalTypeInternal();
811   if (!CreateExtendedType(qual_type, record_declp)) {
812     return false;
813   }
814   record_declp->SetSourceFile(source_file);
815   if (!record_decl_->hasNameForLinkage() ||
816       record_decl_->isAnonymousStructOrUnion()) {
817     record_declp->SetAnonymity(true);
818   }
819   record_declp->SetAccess(AccessClangToIR(record_decl_->getAccess()));
820   return SetupRecordFields(record_declp, source_file) &&
821       SetupCXXRecordInfo(record_declp, source_file);
822 }
823 
SetupCXXRecordInfo(repr::RecordTypeIR * record_declp,const std::string & source_file)824 bool RecordDeclWrapper::SetupCXXRecordInfo(repr::RecordTypeIR *record_declp,
825                                            const std::string &source_file) {
826   const clang::CXXRecordDecl *cxx_record_decl =
827       clang::dyn_cast<clang::CXXRecordDecl>(record_decl_);
828   if (!cxx_record_decl) {
829     return true;
830   }
831   return SetupTemplateInfo(record_declp, cxx_record_decl, source_file) &&
832       SetupCXXBases(record_declp, cxx_record_decl) &&
833       SetupRecordVTable(record_declp, cxx_record_decl);
834 }
835 
836 // TODO: Can we use clang's ODR hash to do faster ODR checking?
GetRecordDecl()837 bool RecordDeclWrapper::GetRecordDecl() {
838   auto abi_decl = std::make_unique<repr::RecordTypeIR>();
839   std::string source_file = GetCachedDeclSourceFile(record_decl_, cip_);
840   if (!SetupRecordInfo(abi_decl.get(), source_file)) {
841     llvm::errs() << "Setting up CXX Bases / Template Info failed\n";
842     return false;
843   }
844   if ((abi_decl->GetReferencedType() == "") ||
845       (abi_decl->GetSelfType() == "")) {
846     // The only way to have an empty referenced / self type is when the type was
847     // cached, don't add the record.
848     return true;
849   }
850   return module_->AddLinkableMessage(*abi_decl);
851 }
852 
GetMangledRTTI(const clang::CXXRecordDecl * cxx_record_decl)853 std::string RecordDeclWrapper::GetMangledRTTI(
854     const clang::CXXRecordDecl *cxx_record_decl) {
855   clang::QualType qual_type =
856       cxx_record_decl->getTypeForDecl()->getCanonicalTypeInternal();
857   llvm::SmallString<256> uid;
858   llvm::raw_svector_ostream out(uid);
859   mangle_contextp_->mangleCXXRTTI(qual_type, out);
860   return std::string(uid);
861 }
862 
863 
864 //------------------------------------------------------------------------------
865 // Enum Decl Wrapper
866 //------------------------------------------------------------------------------
867 
EnumDeclWrapper(clang::MangleContext * mangle_contextp,clang::ASTContext * ast_contextp,const clang::CompilerInstance * compiler_instance_p,const clang::EnumDecl * decl,repr::ModuleIR * module,ASTCaches * ast_caches)868 EnumDeclWrapper::EnumDeclWrapper(
869     clang::MangleContext *mangle_contextp,
870     clang::ASTContext *ast_contextp,
871     const clang::CompilerInstance *compiler_instance_p,
872     const clang::EnumDecl *decl, repr::ModuleIR *module,
873     ASTCaches *ast_caches)
874     : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p, module,
875                  ast_caches),
876       enum_decl_(decl) {}
877 
SetupEnumFields(repr::EnumTypeIR * enump)878 bool EnumDeclWrapper::SetupEnumFields(repr::EnumTypeIR *enump) {
879   if (!enump) {
880     return false;
881   }
882   clang::EnumDecl::enumerator_iterator enum_it = enum_decl_->enumerator_begin();
883   while (enum_it != enum_decl_->enumerator_end()) {
884     std::string name = enum_it->getQualifiedNameAsString();
885     const llvm::APSInt &value = enum_it->getInitVal();
886     if (value.isUnsigned()) {
887       enump->AddEnumField(repr::EnumFieldIR(name, value.getZExtValue()));
888     } else {
889       enump->AddEnumField(repr::EnumFieldIR(name, value.getSExtValue()));
890     }
891     enum_it++;
892   }
893   return true;
894 }
895 
SetupEnum(repr::EnumTypeIR * enum_type,const std::string & source_file)896 bool EnumDeclWrapper::SetupEnum(repr::EnumTypeIR *enum_type,
897                                 const std::string &source_file) {
898   clang::QualType enum_qual_type =
899       enum_decl_->getTypeForDecl()->getCanonicalTypeInternal();
900   if (!CreateExtendedType(enum_qual_type, enum_type)) {
901     return false;
902   }
903   enum_type->SetSourceFile(source_file);
904   enum_type->SetUnderlyingType(GetTypeUniqueId(enum_decl_->getIntegerType()));
905   enum_type->SetAccess(AccessClangToIR(enum_decl_->getAccess()));
906   return SetupEnumFields(enum_type) &&
907       CreateBasicNamedAndTypedDecl(enum_decl_->getIntegerType(), "");
908 }
909 
GetEnumDecl()910 bool EnumDeclWrapper::GetEnumDecl() {
911   auto abi_decl = std::make_unique<repr::EnumTypeIR>();
912   std::string source_file = GetCachedDeclSourceFile(enum_decl_, cip_);
913 
914   if (!SetupEnum(abi_decl.get(), source_file)) {
915     llvm::errs() << "Setting up Enum failed\n";
916     return false;
917   }
918   return module_->AddLinkableMessage(*abi_decl);
919 }
920 
921 
922 //------------------------------------------------------------------------------
923 // Global Decl Wrapper
924 //------------------------------------------------------------------------------
925 
GlobalVarDeclWrapper(clang::MangleContext * mangle_contextp,clang::ASTContext * ast_contextp,const clang::CompilerInstance * compiler_instance_p,const clang::VarDecl * decl,repr::ModuleIR * module,ASTCaches * ast_caches)926 GlobalVarDeclWrapper::GlobalVarDeclWrapper(
927     clang::MangleContext *mangle_contextp,
928     clang::ASTContext *ast_contextp,
929     const clang::CompilerInstance *compiler_instance_p,
930     const clang::VarDecl *decl, repr::ModuleIR *module,
931     ASTCaches *ast_caches)
932     : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p, module,
933                  ast_caches),
934       global_var_decl_(decl) {}
935 
SetupGlobalVar(repr::GlobalVarIR * global_varp,const std::string & source_file)936 bool GlobalVarDeclWrapper::SetupGlobalVar(repr::GlobalVarIR *global_varp,
937                                           const std::string &source_file) {
938   // Temporary fix: clang segfaults on trying to mangle global variable which
939   // is a dependent sized array type.
940   std::string mangled_name =
941       GetMangledNameDecl(global_var_decl_, mangle_contextp_);
942   if (!CreateBasicNamedAndTypedDecl(global_var_decl_->getType(), source_file)) {
943     return false;
944   }
945   global_varp->SetSourceFile(source_file);
946   global_varp->SetName(global_var_decl_->getQualifiedNameAsString());
947   global_varp->SetLinkerSetKey(mangled_name);
948   global_varp->SetAccess(AccessClangToIR(global_var_decl_->getAccess()));
949   global_varp->SetReferencedType(GetTypeUniqueId(global_var_decl_->getType()));
950   return true;
951 }
952 
GetGlobalVarDecl()953 bool GlobalVarDeclWrapper::GetGlobalVarDecl() {
954   auto abi_decl = std::make_unique<repr::GlobalVarIR>();
955   std::string source_file = GetCachedDeclSourceFile(global_var_decl_, cip_);
956   return SetupGlobalVar(abi_decl.get(), source_file) &&
957       module_->AddLinkableMessage(*abi_decl);
958 }
959 
960 
961 }  // dumper
962 }  // header_checker
963