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