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