static void HandleX86ForceAlignArgPointerAttr(Decl *D, const AttributeList& Attr, Sema &S) { // Check the attribute arguments. if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } // If we try to apply it to a function pointer, don't warn, but don't // do anything, either. It doesn't matter anyway, because there's nothing // special about calling a force_align_arg_pointer function. ValueDecl *VD = dyn_cast<ValueDecl>(D); if (VD && VD->getType()->isFunctionPointerType()) return; // Also don't warn on function pointer typedefs. TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D); if (TD && (TD->getUnderlyingType()->isFunctionPointerType() || TD->getUnderlyingType()->isFunctionType())) return; // Attribute can only be applied to function types. if (!isa<FunctionDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << /* function */0; return; } D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getRange(), S.Context)); }
bool ide::printDeclUSR(const ValueDecl *D, raw_ostream &OS) { using namespace Mangle; if (!isa<FuncDecl>(D) && !D->hasName()) return true; // Ignore. if (D->getModuleContext()->isBuiltinModule()) return true; // Ignore. ValueDecl *VD = const_cast<ValueDecl *>(D); if (ClangNode ClangN = VD->getClangNode()) { llvm::SmallString<128> Buf; if (auto ClangD = ClangN.getAsDecl()) { bool Ignore = clang::index::generateUSRForDecl(ClangD, Buf); if (!Ignore) OS << Buf.str(); return Ignore; } auto &Importer = *D->getASTContext().getClangModuleLoader(); auto ClangMacroInfo = ClangN.getAsMacro(); auto PPRecord = Importer.getClangPreprocessor().getPreprocessingRecord(); assert(PPRecord && "Clang importer should be created with " "-detailed-preprocessing-record option"); auto ClangMacroDef = PPRecord->findMacroDefinition(ClangMacroInfo); bool Ignore = clang::index::generateUSRForMacro( ClangMacroDef, Importer.getClangASTContext().getSourceManager(), Buf); if (!Ignore) OS << Buf.str(); return Ignore; } if (!D->hasType()) return true; // FIXME: mangling 'self' in destructors crashes in mangler. if (isa<ParamDecl>(VD) && isa<DestructorDecl>(VD->getDeclContext())) return true; OS << getUSRSpacePrefix(); Mangler Mangler; if (auto Ctor = dyn_cast<ConstructorDecl>(VD)) { Mangler.mangleConstructorEntity(Ctor, /*isAllocating=*/false, /*uncurryingLevel=*/0); } else if (auto Dtor = dyn_cast<DestructorDecl>(VD)) { Mangler.mangleDestructorEntity(Dtor, /*isDeallocating=*/false); } else if (auto NTD = dyn_cast<NominalTypeDecl>(VD)) { Mangler.mangleNominalType(NTD, Mangler::BindGenerics::None); } else if (isa<TypeAliasDecl>(VD) || isa<AssociatedTypeDecl>(VD)) { Mangler.mangleContextOf(VD, Mangler::BindGenerics::None); Mangler.mangleDeclName(VD); } else { Mangler.mangleEntity(VD, /*uncurryingLevel=*/0); } Mangler.finalize(OS); return false; }
void walkRelatedDecls(const ValueDecl *VD, const FnTy &Fn) { llvm::SmallDenseMap<DeclName, unsigned, 16> NamesSeen; ++NamesSeen[VD->getFullName()]; SmallVector<ValueDecl *, 8> RelatedDecls; // FIXME: Extract useful related declarations, overloaded functions, // if VD is an initializer, we should extract other initializers etc. // For now we use UnqualifiedLookup to fetch other declarations with the same // base name. auto TypeResolver = VD->getASTContext().getLazyResolver(); UnqualifiedLookup Lookup(VD->getName(), VD->getDeclContext(), TypeResolver); for (auto result : Lookup.Results) { ValueDecl *RelatedVD = result.getValueDecl(); if (RelatedVD->getAttrs().isUnavailable(VD->getASTContext())) continue; if (RelatedVD != VD) { ++NamesSeen[RelatedVD->getFullName()]; RelatedDecls.push_back(RelatedVD); } } // Now provide the results along with whether the name is duplicate or not. for (auto RelatedVD : RelatedDecls) { Fn(RelatedVD, NamesSeen[RelatedVD->getFullName()] > 1); } }
bool FindMethodLocalVariables::VisitDeclRefExpr(DeclRefExpr* e) { switch(_state) { case LHS: { // _os << "#######: DeclRefExpr: " << getVariableName(e) << ", lvalue: " << e->getDecl()->getDeclKindName() << "\n"; // e->dumpAll(); ValueDecl* vd = e->getDecl(); if (vd == NULL) break; QualType q = vd->getType(); const Type* t = q.getTypePtr(); Decl* d = e->getDecl(); if (d == NULL) break; string declKind(d->getDeclKindName()); if ((getDataMembertype(e) == "enum sc_core::sc_time_unit") || (declKind == "CXXMethod")) { break; } string name = getVariableName(e); if ((_inMethodVariables.find(name)) != _inMethodVariables.end()) { // Found entry. break; } // _os << "=> @@@@@@@@@@@@@@@@@@@@@@@@@@@ Insert\n"; /// Prepare variable information. VariableTypeInfo v(_os); v._name = getVariableName(e); v._expr = e; v._isArray = t->isConstantArrayType(); v._type = getDataMembertype(e); if (v._isArray) { if (const ConstantArrayType* ca = dyn_cast<ConstantArrayType>(t)) { v._arraySize = ca->getSize(); } } /// Freed in the destructor of VariableTypeInfo. FindTemplateTypes te; te.Enumerate(t); v._tempArgs = te; // v.print(); _inMethodVariables.insert(kvType(v._name, v)); break; } case RHS: { //_os << "\n=> DeclRefExpr\n"; break; } }; return true; }
void handlePrimaryAST(ASTUnitRef AstUnit) override { auto &CompInst = AstUnit->getCompilerInstance(); auto &SrcFile = AstUnit->getPrimarySourceFile(); trace::TracedOperation TracedOp; SmallVector<std::pair<unsigned, unsigned>, 8> Ranges; auto Action = [&]() { if (trace::enabled()) { trace::SwiftInvocation SwiftArgs; Invok->raw(SwiftArgs.Args.Args, SwiftArgs.Args.PrimaryFile); trace::initTraceFiles(SwiftArgs, CompInst); TracedOp.start(trace::OperationKind::RelatedIdents, SwiftArgs, {std::make_pair("Offset", std::to_string(Offset))}); } unsigned BufferID = SrcFile.getBufferID().getValue(); SourceLoc Loc = Lexer::getLocForStartOfToken(CompInst.getSourceMgr(), BufferID, Offset); if (Loc.isInvalid()) return; SemaLocResolver Resolver(SrcFile); SemaToken SemaTok = Resolver.resolve(Loc); if (SemaTok.isInvalid()) return; if (SemaTok.IsKeywordArgument) return; ValueDecl *VD = SemaTok.CtorTyRef ? SemaTok.CtorTyRef : SemaTok.ValueD; if (!VD) return; // This was a module reference. // Only accept pointing to an identifier. if (!SemaTok.IsRef && (isa<ConstructorDecl>(VD) || isa<DestructorDecl>(VD) || isa<SubscriptDecl>(VD))) return; if (VD->getName().isOperator()) return; RelatedIdScanner Scanner(SrcFile, BufferID, VD, Ranges); if (DeclContext *LocalDC = VD->getDeclContext()->getLocalContext()) { Scanner.walk(LocalDC); } else { Scanner.walk(SrcFile); } }; Action(); RelatedIdentsInfo Info; Info.Ranges = Ranges; Receiver(Info); }
SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const { // Anonymous functions have shared linkage. // FIXME: This should really be the linkage of the parent function. if (getAbstractClosureExpr()) return SILLinkage::Shared; // Native function-local declarations have shared linkage. // FIXME: @objc declarations should be too, but we currently have no way // of marking them "used" other than making them external. ValueDecl *d = getDecl(); DeclContext *moduleContext = d->getDeclContext(); while (!moduleContext->isModuleScopeContext()) { if (!isForeign && moduleContext->isLocalContext()) return SILLinkage::Shared; moduleContext = moduleContext->getParent(); } // Currying and calling convention thunks have shared linkage. if (isThunk()) // If a function declares a @_cdecl name, its native-to-foreign thunk // is exported with the visibility of the function. if (!isNativeToForeignThunk() || !d->getAttrs().hasAttribute<CDeclAttr>()) return SILLinkage::Shared; // Enum constructors are essentially the same as thunks, they are // emitted by need and have shared linkage. if (kind == Kind::EnumElement) return SILLinkage::Shared; // Declarations imported from Clang modules have shared linkage. const SILLinkage ClangLinkage = SILLinkage::Shared; if (isClangImported()) return ClangLinkage; // Declarations that were derived on behalf of types in Clang modules get // shared linkage. if (auto *FD = dyn_cast<FuncDecl>(d)) { if (auto derivedFor = FD->getDerivedForTypeDecl()) if (isa<ClangModuleUnit>(derivedFor->getModuleScopeContext())) return ClangLinkage; } // Otherwise, we have external linkage. switch (d->getEffectiveAccess()) { case Accessibility::Private: return (forDefinition ? SILLinkage::Private : SILLinkage::PrivateExternal); case Accessibility::Internal: return (forDefinition ? SILLinkage::Hidden : SILLinkage::HiddenExternal); default: return (forDefinition ? SILLinkage::Public : SILLinkage::PublicExternal); } }
Optional<SpecializedEmitter> SpecializedEmitter::forDecl(SILGenModule &SGM, SILDeclRef function) { // Only consider standalone declarations in the Builtin module. if (function.kind != SILDeclRef::Kind::Func) return None; if (!function.hasDecl()) return None; ValueDecl *decl = function.getDecl(); if (!isa<BuiltinUnit>(decl->getDeclContext())) return None; auto name = decl->getBaseName().getIdentifier(); const BuiltinInfo &builtin = SGM.M.getBuiltinInfo(name); switch (builtin.ID) { // All the non-SIL, non-type-trait builtins should use the // named-builtin logic, which just emits the builtin as a call to a // builtin function. This includes builtins that aren't even declared // in Builtins.def, i.e. all of the LLVM intrinsics. // // We do this in a separate pass over Builtins.def to avoid creating // a bunch of identical cases. #define BUILTIN(Id, Name, Attrs) \ case BuiltinValueKind::Id: #define BUILTIN_SIL_OPERATION(Id, Name, Overload) #define BUILTIN_SANITIZER_OPERATION(Id, Name, Attrs) #define BUILTIN_TYPE_TRAIT_OPERATION(Id, Name) #include "swift/AST/Builtins.def" case BuiltinValueKind::None: return SpecializedEmitter(name); // Do a second pass over Builtins.def, ignoring all the cases for // which we emitted something above. #define BUILTIN(Id, Name, Attrs) // Use specialized emitters for SIL builtins. #define BUILTIN_SIL_OPERATION(Id, Name, Overload) \ case BuiltinValueKind::Id: \ return SpecializedEmitter(&emitBuiltin##Id); // Sanitizer builtins should never directly be called; they should only // be inserted as instrumentation by SILGen. #define BUILTIN_SANITIZER_OPERATION(Id, Name, Attrs) \ case BuiltinValueKind::Id: \ llvm_unreachable("Sanitizer builtin called directly?"); // Lower away type trait builtins when they're trivially solvable. #define BUILTIN_TYPE_TRAIT_OPERATION(Id, Name) \ case BuiltinValueKind::Id: \ return SpecializedEmitter(&emitBuiltinTypeTrait<&TypeBase::Name, \ BuiltinValueKind::Id>); #include "swift/AST/Builtins.def" } llvm_unreachable("bad builtin kind"); }
SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const { // Anonymous functions have shared linkage. // FIXME: This should really be the linkage of the parent function. if (getAbstractClosureExpr()) return SILLinkage::Shared; // Native function-local declarations have shared linkage. // FIXME: @objc declarations should be too, but we currently have no way // of marking them "used" other than making them external. ValueDecl *d = getDecl(); DeclContext *moduleContext = d->getDeclContext(); while (!moduleContext->isModuleScopeContext()) { if (!isForeign && moduleContext->isLocalContext()) return SILLinkage::Shared; moduleContext = moduleContext->getParent(); } // Currying and calling convention thunks have shared linkage. if (isThunk()) // If a function declares a @_cdecl name, its native-to-foreign thunk // is exported with the visibility of the function. if (!isNativeToForeignThunk() || !d->getAttrs().hasAttribute<CDeclAttr>()) return SILLinkage::Shared; // Enum constructors are essentially the same as thunks, they are // emitted by need and have shared linkage. if (isEnumElement()) return SILLinkage::Shared; // Stored property initializers have hidden linkage, since they are // not meant to be used from outside of their module. if (isStoredPropertyInitializer()) return SILLinkage::Hidden; // Declarations imported from Clang modules have shared linkage. const SILLinkage ClangLinkage = SILLinkage::Shared; if (isClangImported()) return ClangLinkage; // Otherwise, we have external linkage. switch (d->getEffectiveAccess()) { case Accessibility::Private: case Accessibility::FilePrivate: return (forDefinition ? SILLinkage::Private : SILLinkage::PrivateExternal); case Accessibility::Internal: return (forDefinition ? SILLinkage::Hidden : SILLinkage::HiddenExternal); default: return (forDefinition ? SILLinkage::Public : SILLinkage::PublicExternal); } }
/// Compare two declarations to determine whether one is a witness of the other. static Comparison compareWitnessAndRequirement(TypeChecker &tc, DeclContext *dc, ValueDecl *decl1, ValueDecl *decl2) { // We only have a witness/requirement pair if exactly one of the declarations // comes from a protocol. auto proto1 = dyn_cast<ProtocolDecl>(decl1->getDeclContext()); auto proto2 = dyn_cast<ProtocolDecl>(decl2->getDeclContext()); if ((bool)proto1 == (bool)proto2) return Comparison::Unordered; // Figure out the protocol, requirement, and potential witness. ProtocolDecl *proto; ValueDecl *req; ValueDecl *potentialWitness; if (proto1) { proto = proto1; req = decl1; potentialWitness = decl2; } else { proto = proto2; req = decl2; potentialWitness = decl1; } // Cannot compare type declarations this way. // FIXME: Use the same type-substitution approach as lookupMemberType. if (isa<TypeDecl>(req)) return Comparison::Unordered; if (!potentialWitness->getDeclContext()->isTypeContext()) return Comparison::Unordered; // Determine whether the type of the witness's context conforms to the // protocol. auto owningType = potentialWitness->getDeclContext()->getDeclaredTypeInContext(); ProtocolConformance *conformance = nullptr; if (!tc.conformsToProtocol(owningType, proto, dc, ConformanceCheckFlags::InExpression, &conformance) || !conformance) return Comparison::Unordered; // If the witness and the potential witness are not the same, there's no // ordering here. if (conformance->getWitness(req, &tc).getDecl() != potentialWitness) return Comparison::Unordered; // We have a requirement/witness match. return proto1? Comparison::Worse : Comparison::Better; }
string NetworkDriverRewriteVisitor::GetSharedStructStr(CallExpr *callExpr) { string shared_struct_str = ""; Expr *callee = callExpr->getCallee(); if (!isa<ImplicitCastExpr>(callee)) return shared_struct_str; ImplicitCastExpr *calleeImplExpr = cast<ImplicitCastExpr>(callee); if (!isa<DeclRefExpr>(calleeImplExpr->getSubExpr())) return shared_struct_str; DeclRefExpr *calleeDeclExpr = cast<DeclRefExpr>(calleeImplExpr->getSubExpr()); Stmt *body = callExpr->getCalleeDecl()->getBody(); if (calleeDeclExpr->getNameInfo().getAsString() != "alloc_etherdev") shared_struct_str = GetSharedStructStrInFunctionBody(body, false); if (calleeDeclExpr->getNameInfo().getAsString() != "alloc_etherdev") return shared_struct_str; for (auto i = callExpr->arg_begin(), e = callExpr->arg_end(); i != e; ++i) { if (!isa<ImplicitCastExpr>(*i)) continue; ImplicitCastExpr *argImplExpr = cast<ImplicitCastExpr>(*i); if (!isa<UnaryExprOrTypeTraitExpr>(argImplExpr->getSubExpr())) continue; UnaryExprOrTypeTraitExpr *argExpr = cast<UnaryExprOrTypeTraitExpr>(argImplExpr->getSubExpr()); ParenExpr *parenExpr = cast<ParenExpr>(argExpr->getArgumentExpr()); UnaryOperator *uop = cast<UnaryOperator>(parenExpr->getSubExpr()); ImplicitCastExpr *implExpr = cast<ImplicitCastExpr>(uop->getSubExpr()); DeclRefExpr *declExpr = cast<DeclRefExpr>(implExpr->getSubExpr()); ValueDecl *valueDecl = cast<ValueDecl>(declExpr->getDecl()); shared_struct_str = valueDecl->getType().getAsString(Context->getPrintingPolicy()); break; } return shared_struct_str; }
bool SILDeclRef::isClangImported() const { if (!hasDecl()) return false; ValueDecl *d = getDecl(); DeclContext *moduleContext = d->getDeclContext()->getModuleScopeContext(); if (isa<ClangModuleUnit>(moduleContext)) { if (isClangGenerated()) return true; if (isa<ConstructorDecl>(d) || isa<EnumElementDecl>(d)) return !isForeign; if (auto *FD = dyn_cast<FuncDecl>(d)) if (FD->isAccessor() || isa<NominalTypeDecl>(d->getDeclContext())) return !isForeign; } return false; }
bool ide::printDeclUSR(const ValueDecl *D, raw_ostream &OS) { using namespace Mangle; if (!isa<FuncDecl>(D) && !D->hasName()) return true; // Ignore. if (D->getModuleContext()->isBuiltinModule()) return true; // Ignore. ValueDecl *VD = const_cast<ValueDecl *>(D); auto interpretAsClangNode = [](const ValueDecl *D)->ClangNode { ClangNode ClangN = D->getClangNode(); if (auto ClangD = ClangN.getAsDecl()) { // NSErrorDomain causes the clang enum to be imported like this: // // struct MyError { // enum Code : Int32 { // case errFirst // case errSecond // } // static var errFirst: MyError.Code { get } // static var errSecond: MyError.Code { get } // } // // The clang enum and enum constants are associated with both the // struct/nested enum, and the static vars/enum cases. // But we want unique USRs for the above symbols, so use the clang USR // for the enum and enum cases, and the Swift USR for the struct and vars. // if (isa<clang::EnumDecl>(ClangD)) { if (ClangD->hasAttr<clang::NSErrorDomainAttr>() && isa<StructDecl>(D)) return ClangNode(); } else if (auto *ClangEnumConst = dyn_cast<clang::EnumConstantDecl>(ClangD)) { if (auto *ClangEnum = dyn_cast<clang::EnumDecl>(ClangEnumConst->getDeclContext())) { if (ClangEnum->hasAttr<clang::NSErrorDomainAttr>() && isa<VarDecl>(D)) return ClangNode(); } } } return ClangN; }; if (ClangNode ClangN = interpretAsClangNode(D)) { llvm::SmallString<128> Buf; if (auto ClangD = ClangN.getAsDecl()) { bool Ignore = clang::index::generateUSRForDecl(ClangD, Buf); if (!Ignore) OS << Buf.str(); return Ignore; } auto &Importer = *D->getASTContext().getClangModuleLoader(); auto ClangMacroInfo = ClangN.getAsMacro(); auto PPRecord = Importer.getClangPreprocessor().getPreprocessingRecord(); assert(PPRecord && "Clang importer should be created with " "-detailed-preprocessing-record option"); auto ClangMacroDef = PPRecord->findMacroDefinition(ClangMacroInfo); bool Ignore = clang::index::generateUSRForMacro( ClangMacroDef, Importer.getClangASTContext().getSourceManager(), Buf); if (!Ignore) OS << Buf.str(); return Ignore; } if (!D->hasType()) return true; // FIXME: mangling 'self' in destructors crashes in mangler. if (isa<ParamDecl>(VD) && isa<DestructorDecl>(VD->getDeclContext())) return true; OS << getUSRSpacePrefix(); Mangler Mangler; Mangler.bindGenericParameters(VD->getDeclContext()); if (auto Ctor = dyn_cast<ConstructorDecl>(VD)) { Mangler.mangleConstructorEntity(Ctor, /*isAllocating=*/false, /*uncurryingLevel=*/0); } else if (auto Dtor = dyn_cast<DestructorDecl>(VD)) { Mangler.mangleDestructorEntity(Dtor, /*isDeallocating=*/false); } else if (auto NTD = dyn_cast<NominalTypeDecl>(VD)) { Mangler.mangleNominalType(NTD); } else if (isa<TypeAliasDecl>(VD) || isa<AssociatedTypeDecl>(VD)) { Mangler.mangleContextOf(VD); Mangler.mangleDeclName(VD); } else { Mangler.mangleEntity(VD, /*uncurryingLevel=*/0); } Mangler.finalize(OS); return false; }
void NetworkDriverRewriteVisitor::CreateCheckerFunction(FunctionDecl* funcDecl, string fdFile) { string device_str; Stmt *body = funcDecl->getBody(); for (auto i = body->child_begin(), e = body->child_end(); i != e; ++i) { if (!isa<DeclStmt>(*i)) continue; DeclStmt *declStmt = cast<DeclStmt>(*i); if (!declStmt->isSingleDecl() && !isa<VarDecl>(declStmt->getSingleDecl())) continue; VarDecl *varDecl = cast<VarDecl>(declStmt->getSingleDecl()); if (!isa<ValueDecl>(varDecl)) continue; ValueDecl *value = cast<ValueDecl>(varDecl); if (value->getType().getAsString(Context->getPrintingPolicy()) != "struct net_device *") continue; if (!isa<NamedDecl>(varDecl)) continue; NamedDecl *named = cast<NamedDecl>(varDecl); device_str = named->getNameAsString(); break; } if (device_str.empty()) return; string shared_struct_str = GetSharedStructStrInFunctionBody(body, true); if (shared_struct_str.empty()) return; FileID fileId = Context->getSourceManager().getFileID(funcDecl->getLocation()); SourceLocation loc = Context->getSourceManager().getLocForEndOfFile(fileId); RW.InsertText(loc, "\n", true, true); RW.InsertText(loc, "void whoop$checker(", true, true); map<string, string> func_params; for (auto i = funcDecl->param_begin(), e = funcDecl->param_end(); i != e; ++i) { ValueDecl *paramVal = cast<ValueDecl>(*i); NamedDecl *paramNam = cast<NamedDecl>(*i); string paramType = paramVal->getType().getAsString(Context->getPrintingPolicy()); string paramName = paramNam->getNameAsString(); func_params[paramType] = paramName; if (i == funcDecl->param_begin()) RW.InsertText(loc, paramType + " " + paramName + ", ", true, true); else RW.InsertText(loc, paramType + " " + paramName, true, true); } RW.InsertText(loc, ")\n", true, true); RW.InsertText(loc, "{\n", true, true); RW.InsertText(loc, "\tstruct net_device *dev;\n", true, true); RW.InsertText(loc, "\t" + shared_struct_str + "shared;\n", true, true); RW.InsertText(loc, "\tdev = alloc_etherdev(sizeof(*shared));\n\n", true, true); RW.InsertText(loc, "\tstruct sk_buff *whoop_skb = (struct sk_buff *) malloc(sizeof(struct sk_buff));\n", true, true); RW.InsertText(loc, "\tstruct ethtool_wolinfo *whoop_wolinfo = (struct ethtool_wolinfo *) malloc(sizeof(struct ethtool_wolinfo));\n", true, true); RW.InsertText(loc, "\tstruct ethtool_cmd *whoop_ecmd = (struct ethtool_cmd *) malloc(sizeof(struct ethtool_cmd));\n", true, true); RW.InsertText(loc, "\tstruct ifreq *whoop_ifreq = (struct ifreq *) malloc(sizeof(struct ifreq));\n", true, true); RW.InsertText(loc, "\tstruct rtnl_link_stats64 *whoop_rtnlsts64 = (struct rtnl_link_stats64 *) malloc(sizeof(struct rtnl_link_stats64));\n", true, true); RW.InsertText(loc, "\tstruct ethtool_regs *whoop_ethtoolregs = (struct ethtool_regs *) malloc(sizeof(struct ethtool_regs));\n", true, true); RW.InsertText(loc, "\tstruct ethtool_stats *whoop_ethtoolsts = (struct ethtool_stats *) malloc(sizeof(struct ethtool_stats));\n", true, true); RW.InsertText(loc, "\tstruct ethtool_drvinfo *whoop_ethtooldrvinfo = (struct ethtool_drvinfo *) malloc(sizeof(struct ethtool_drvinfo));\n", true, true); RW.InsertText(loc, "\tnetdev_features_t whoop_netdevfeat = NETIF_F_RXCSUM;\n\n", true, true); RW.InsertText(loc, "\tint whoop_int = __SMACK_nondet();\n", true, true); RW.InsertText(loc, "\t__SMACK_code(\"assume @ >= @;\", whoop_int, 0);\n\n", true, true); auto entry_points = DI->getInstance().GetEntryPoints(); for(auto i = entry_points.rbegin(); i != entry_points.rend(); i++) { string entry_point_call; entry_point_call = "" + i->first + "("; if (find(i->second.begin(), i->second.end(), "struct net_device *") == i->second.end()) entry_point_call += device_str + ", "; for(auto j = i->second.begin(); j != i->second.end(); j++) { if (*j == "struct net_device *") entry_point_call += device_str + ", "; else if (*j == "struct pci_dev *") entry_point_call += func_params["struct pci_dev *"] + ", "; else if (*j == "struct device *") entry_point_call += "&" + func_params["struct pci_dev *"] + "->dev, "; else if (*j == "void *") entry_point_call += "NULL, "; else if (*j == "u64 *") entry_point_call += "NULL, "; else if (*j == "u8 *") entry_point_call += "NULL, "; else if (*j == "struct sk_buff *") entry_point_call += "whoop_skb, "; else if (*j == "struct ethtool_wolinfo *") entry_point_call += "whoop_wolinfo, "; else if (*j == "struct ethtool_cmd *") entry_point_call += "whoop_ecmd, "; else if (*j == "struct ifreq *") entry_point_call += "whoop_ifreq, "; else if (*j == "struct rtnl_link_stats64 *") entry_point_call += "whoop_rtnlsts64, "; else if (*j == "struct ethtool_regs *") entry_point_call += "whoop_ethtoolregs, "; else if (*j == "struct ethtool_stats *") entry_point_call += "whoop_ethtoolsts, "; else if (*j == "struct ethtool_drvinfo *") entry_point_call += "whoop_ethtooldrvinfo, "; else if (*j == "netdev_features_t") entry_point_call += "whoop_netdevfeat, "; else if (*j == "int") entry_point_call += "whoop_int, "; else if (*j == "u32") entry_point_call += "whoop_int, "; else entry_point_call += *j + ", "; } entry_point_call.resize(entry_point_call.size() - 2); RW.InsertText(loc, "\t" + entry_point_call + ");\n", true, true); } RW.InsertText(loc, "}", true, true); }
string NetworkDriverRewriteVisitor::GetSharedStructStrInFunctionBody(Stmt *body, bool doLog) { string shared_struct_str = ""; for (auto i = body->child_begin(), e = body->child_end(); i != e; ++i) { if (isa<DeclStmt>(*i)) { DeclStmt *declStmt = cast<DeclStmt>(*i); if (!declStmt->isSingleDecl() && !isa<VarDecl>(declStmt->getSingleDecl())) continue; VarDecl *varDecl = cast<VarDecl>(declStmt->getSingleDecl()); if (!isa<ValueDecl>(varDecl)) continue; ValueDecl *value = cast<ValueDecl>(varDecl); if (value->getType().getAsString(Context->getPrintingPolicy()) != "struct net_device *") continue; if (!isa<NamedDecl>(varDecl)) continue; if (varDecl->getInit() == 0 || !isa<CallExpr>(varDecl->getInit())) continue; CallExpr *callExpr = cast<CallExpr>(varDecl->getInit()); shared_struct_str = GetSharedStructStr(callExpr); if (shared_struct_str != "") { if (doLog) { Expr *callee = callExpr->getCallee(); ImplicitCastExpr *calleeImplExpr = cast<ImplicitCastExpr>(callee); DeclRefExpr *calleeDeclExpr = cast<DeclRefExpr>(calleeImplExpr->getSubExpr()); DI->getInstance().AddSharedStructInformation("whoop_network_shared_struct", calleeDeclExpr->getNameInfo().getAsString()); } break; } } else if (isa<BinaryOperator>(*i)) { BinaryOperator *binOp = cast<BinaryOperator>(*i); if (!isa<CallExpr>(binOp->getRHS())) continue; CallExpr *callExpr = cast<CallExpr>(binOp->getRHS()); shared_struct_str = GetSharedStructStr(callExpr); if (shared_struct_str != "") { if (doLog) { Expr *callee = callExpr->getCallee(); ImplicitCastExpr *calleeImplExpr = cast<ImplicitCastExpr>(callee); DeclRefExpr *calleeDeclExpr = cast<DeclRefExpr>(calleeImplExpr->getSubExpr()); DI->getInstance().AddSharedStructInformation("whoop_network_shared_struct", calleeDeclExpr->getNameInfo().getAsString()); } break; } } } return shared_struct_str; }
void USBDriverRewriteVisitor::CreateCheckerFunction(FunctionDecl* funcDecl, string fdFile) { string device_str; string shared_struct_str; FileID fileId = Context->getSourceManager().getFileID(funcDecl->getLocation()); SourceLocation loc = Context->getSourceManager().getLocForEndOfFile(fileId); RW.InsertText(loc, "\n", true, true); RW.InsertText(loc, "void whoop$checker(", true, true); map<string, string> func_params; for (auto i = funcDecl->param_begin(), e = funcDecl->param_end(); i != e; ++i) { if (i != funcDecl->param_begin()) RW.InsertText(loc, ", ", true, true); ValueDecl *paramVal = cast<ValueDecl>(*i); NamedDecl *paramNam = cast<NamedDecl>(*i); string paramType = paramVal->getType().getAsString(Context->getPrintingPolicy()); string paramName = paramNam->getNameAsString(); func_params[paramType] = paramName; RW.InsertText(loc, paramType + " " + paramName, true, true); } RW.InsertText(loc, ")\n", true, true); RW.InsertText(loc, "{\n", true, true); RW.InsertText(loc, "\tstruct tty_struct *whoop_tty_struct = (struct tty_struct *) malloc(sizeof(struct tty_struct));\n", true, true); RW.InsertText(loc, "\tstruct usb_serial *whoop_usb_serial = (struct usb_serial *) malloc(sizeof(struct usb_serial));\n", true, true); RW.InsertText(loc, "\tstruct usb_serial_port *whoop_usb_serial_port = (struct usb_serial_port *) malloc(sizeof(struct usb_serial_port));\n", true, true); RW.InsertText(loc, "\tstruct usb_interface *whoop_usb_interface = (struct usb_interface *) malloc(sizeof(struct usb_interface));\n", true, true); RW.InsertText(loc, "\tstruct ktermios *whoop_ktermios = (struct ktermios *) malloc(sizeof(struct ktermios));\n", true, true); RW.InsertText(loc, "\tstruct urb *whoop_urb = (struct urb *) malloc(sizeof(struct urb));\n", true, true); RW.InsertText(loc, "\tconst char *whoop_buf = (char *) malloc(sizeof(char));\n\n", true, true); RW.InsertText(loc, "\tint whoop_int = __SMACK_nondet();\n", true, true); RW.InsertText(loc, "\t__SMACK_code(\"assume @ >= @;\", whoop_int, 0);\n\n", true, true); auto entry_points = DI->getInstance().GetEntryPoints(); for(auto i = entry_points.rbegin(); i != entry_points.rend(); i++) { string entry_point_call; entry_point_call = "" + i->first + "("; for(auto j = i->second.begin(); j != i->second.end(); j++) { if (*j == "void") entry_point_call += ""; else if (*j == "void *") entry_point_call += "NULL, "; else if (*j == "u64 *") entry_point_call += "NULL, "; else if (*j == "u8 *") entry_point_call += "NULL, "; else if (*j == "struct tty_struct *") entry_point_call += "whoop_tty_struct, "; else if (*j == "struct usb_serial *") entry_point_call += "whoop_usb_serial, "; else if (*j == "struct usb_serial_port *") entry_point_call += "whoop_usb_serial_port, "; else if (*j == "struct usb_interface *") entry_point_call += "whoop_usb_interface, "; else if (*j == "struct urb *") entry_point_call += "whoop_ktermios, "; else if (*j == "struct ktermios *") entry_point_call += "whoop_urb, "; else if (*j == "char *") entry_point_call += "whoop_buf, "; else if (*j == "const char *") entry_point_call += "whoop_buf, "; else if (*j == "size_t") entry_point_call += "whoop_int, "; else if (*j == "int") entry_point_call += "whoop_int, "; else if (*j == "unsigned int") entry_point_call += "whoop_int, "; else if (*j == "long") entry_point_call += "whoop_int, "; else if (*j == "unsigned long") entry_point_call += "whoop_int, "; else if (*j == "u32") entry_point_call += "whoop_int, "; else if (*j == "fmode_t") entry_point_call += "whoop_int, "; else entry_point_call += *j + ", "; } if (entry_point_call != i->first + "(") { entry_point_call.resize(entry_point_call.size() - 2); } RW.InsertText(loc, "\t" + entry_point_call + ");\n", true, true); } RW.InsertText(loc, "}", true, true); }
/* this helper function is called when the traversal reaches a node of type Stmt */ void StmtHelper(Stmt *x){ //variable used for <cond> </cond> //bool condition = false; bool isElse = false; if(x != NULL){ string output = ""; //find current level and next level int intLevel = getLevelStmt(x); int intNextLevel = intLevel+1; //convert them both to strings to use for output string level; string nextLevel; stringstream ss; ss << intLevel; level = ss.str(); stringstream ss2; ss2 << intNextLevel; nextLevel = ss2.str(); const Stmt* parent = getStmtParent(x, Context); //PROBLEM if(x->getStmtClassName() != std::string("ForStmt") && isFlowControl(x, Context)){ //return; } //if the parent is calling any type of funciton then this node should be enclosed in <args> </args> string filename; if(callStackDebug && !callStack.empty()){ cerr << "stmt: call stack top: " << callStack.top()->getStmtClassName() << endl; } while(!callStack.empty() && numClosingArgsNeeded > 0 && !isParentStmt(parent, callStack.top()->getStmtClassName())){ if(debugPrint){ cerr << "adding args" << endl; } numClosingArgsNeeded--; output += "</args,1>\n"; callStack.pop(); if(callStackDebug){ cerr << "popping" << endl; printCallStack(); } } if(isParentStmtInCurFile(x,"CXXConstructExpr") && isParentStmt(x, "CXXConstructExpr")){ if(debugPrint){ cerr << "setting previousConstructorCall to true" << endl; } }else if(isParentStmtInCurFile(x,"CXXTemporaryObjectExpr") && isParentStmt(x, "CXXTemporaryObjectExpr")){ if(debugPrint){ cerr << "setting previousTempConstructorCallArg" << endl; } }else if(isParentStmt(x, "CallExpr")){ if(debugPrint){ cerr << "setting previousCallArgs to true" << endl; } }else if(isParentStmt(x, "CXXMemberCallExpr")){ if(debugPrint){ cerr << "setting previousMemberCallArgs to true" << endl; } } //if the parent is a variable declaration then this node should be encolsed in <decl> </decl> if(isParentStmt(x, "Var")){ previousRhsDecl = true; if(debugPrint){ cout << "setting prev var to true" << endl; } }else if(previousRhsDecl && numClosingVarsNeeded > 0){ //if the current node is not a child of a variable declaration //but the previous node was a child of a variable declation //then we know to print a </decl> output +="</variableDecl,1>\n"; numClosingVarsNeeded--; previousRhsDecl = false; } if(parent != NULL && strcmp(parent->getStmtClassName(), "IfStmt") == 0){ if(debugPrint){ cerr << "possibly an if statement" << endl; } //find the first child of the if statemt const Stmt* firstChild = NULL; auto children = parent->children(); for(const Stmt* child : children){ if(child != NULL){ firstChild = child; break; } } //if the first child is the current node, then we know it is part of the condition if(firstChild != NULL && x->getLocStart() == firstChild->getLocStart()){ if(debugPrint){ cerr << "part of the condition" << endl; } prevCondition = true; }else if(prevCondition){ output +="</cond,1>\n"; prevCondition = false; } //find if else const IfStmt* ifstmt = (IfStmt*) parent; const Stmt* elseStmt = ifstmt->getElse(); if(elseStmt != NULL){ if(debugPrint){ cout << "checking if " << x->getLocStart().printToString(Context->getSourceManager()); cout << " == " << elseStmt->getLocStart().printToString(Context->getSourceManager()); cout << " : " << (x->getLocStart() == elseStmt->getLocStart()) << endl; } if(x->getLocStart() == elseStmt->getLocStart()){ isElse = true; } } } string node = x->getStmtClassName(); if(node == "ReturnStmt"){ output += "<return"; }else if(node == "ForStmt"){ output += "<forLoop"; }else if(node == "WhileStmt"){ output += "<whileLoop"; }else if(node == "DoStmt"){ output += "<do"; }else if(node == "IfStmt"){ if(parent->getStmtClassName() != std::string("IfStmt")){ stringstream ssminus; ssminus << (intLevel-1); output += "<ifBlock," + ssminus.str() + ">\n"; intLevel += 1; stringstream ssif; ssif << intLevel; level = ssif.str(); } output += "<ifStatement"; }else if(node == "SwitchStmt"){ output += "<switch"; }else if(node == "CaseStmt"){ output += "<case"; }else if(node == "CXXMemberCallExpr"){ CXXMemberCallExpr* ce = (CXXMemberCallExpr*) x; Expr* obj = ce->getImplicitObjectArgument(); CallExpr* expr = (CallExpr*) x; output += "<object: "; QualType qt = obj->getType(); output += qt.getBaseTypeIdentifier()->getName().str(); output += "; calling func: "; output += expr->getDirectCallee()->getNameInfo().getAsString(); output += ", " + level + ">\n"; output += "<args"; numClosingArgsNeeded++; callStack.push(x); if(callStackDebug){ cerr << "pushing" << endl; printCallStack(); } }else if(node == "CallExpr"){ CallExpr* expr = (CallExpr*) x; output += "<calling func: "; output += expr->getDirectCallee()->getNameInfo().getAsString(); output += ", " + level + ">\n"; output += "<args"; numClosingArgsNeeded++; callStack.push(x); if(callStackDebug){ cerr << "pushing" << endl; printCallStack(); } }else if(node == "CXXConstructExpr"){ CXXConstructExpr* ce = (CXXConstructExpr*) x; //Decl* CD = ce->getConstructor(); string filename; //if(isInCurFile(Context, CD, filename)){ CXXMethodDecl* MD = ce->getConstructor(); output += "<calling func: "; output += MD->getNameInfo().getAsString(); output += "," + level + ">\n"; output += "<args"; numClosingArgsNeeded++; callStack.push(x); if(callStackDebug){ cerr << "pushing" << endl; printCallStack(); } //} }else if(node == "BinaryOperator"){ BinaryOperator* binaryOp = (BinaryOperator*) x; if(binaryOp->isAssignmentOp()){ output += "<assignment"; }else if(binaryOp->isComparisonOp()){ output += "<comparison"; }else{ output += "<binaryOp"; } }else if(node == "UnaryOperator"){ UnaryOperator* uo = (UnaryOperator*) x; string op = uo->getOpcodeStr(uo->getOpcode()).str(); if(op != "-"){ output += "<unaryOp"; } }else if(node == "CompoundAssignOperator"){ output += "<augAssign"; }else if(node == "CompoundStmt"){ if(isElse){ output += "<elseStatement"; }else{ output += "<compoundStmt"; } }else if(node == "CXXThrowExpr"){ output += "<raisingException"; }else if(node == "CXXTryStmt"){ output += "<try"; }else if(node == "CXXCatchStmt"){ output += "<except"; }else if(node == "CXXOperatorCallExpr"){ CXXOperatorCallExpr* ce = (CXXOperatorCallExpr*) x; if(ce->isAssignmentOp()){ output += "<assignment"; } }else if(node == "CXXTemporaryObjectExpr"){ CXXTemporaryObjectExpr* ce = (CXXTemporaryObjectExpr*) x; Decl* CD = ce->getConstructor(); string filename; if(isInCurFile(Context, CD, filename)){ CXXMethodDecl* MD = ce->getConstructor(); output += "<calling func: "; output += MD->getNameInfo().getAsString(); output += "," + level + ">\n"; output += "<args"; numClosingArgsNeeded++; callStack.push(x); if(callStackDebug){ cerr << "pushing" << endl; printCallStack(); } } }else if(node == "DeclRefExpr"){ if(parent != NULL && parent->getStmtClassName() == std::string("ImplicitCastExpr")){ DeclRefExpr* dr = (DeclRefExpr*) x; ValueDecl* d = (ValueDecl*) dr->getDecl(); //cout << d->getQualType().getAsString() << endl; if(d != NULL){ QualType qt = d->getType(); //cout << qt.getAsString() << endl; if(qt.getAsString() == "std::vector<int, class std::allocator<int> >::const_reference (std::vector::size_type) const noexcept"){ //string type = io->getName().str(); //cout << type << endl; //if(type == "vector"){ output += "<expr"; //} } } } }else{ if(allNodes){ output += "<"; output += node; output += ">"; } } if(output.size() != 0 && !endsIn(output, "</cond,1>\n") && !endsIn(output,"</variableDecl,1>\n") && !endsIn(output,"</args,1>\n") && !endsIn(output,">") && !endsIn(output, ">\n")){ output += ", " + level + ">"; cout << output << endl; output = ""; }else if(output.size() != 0){ cout << output << endl; output = ""; if(debugPrint){ cerr << "printing output" << endl; } } } }
SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const { if (getAbstractClosureExpr()) { return isSerialized() ? SILLinkage::Shared : SILLinkage::Private; } // Add External to the linkage (e.g. Public -> PublicExternal) if this is a // declaration not a definition. auto maybeAddExternal = [&](SILLinkage linkage) { return forDefinition ? linkage : addExternalToLinkage(linkage); }; // Native function-local declarations have shared linkage. // FIXME: @objc declarations should be too, but we currently have no way // of marking them "used" other than making them external. ValueDecl *d = getDecl(); DeclContext *moduleContext = d->getDeclContext(); while (!moduleContext->isModuleScopeContext()) { if (!isForeign && moduleContext->isLocalContext()) { return isSerialized() ? SILLinkage::Shared : SILLinkage::Private; } moduleContext = moduleContext->getParent(); } // Enum constructors and curry thunks either have private or shared // linkage, dependings are essentially the same as thunks, they are // emitted by need and have shared linkage. if (isEnumElement() || isCurried) { switch (d->getEffectiveAccess()) { case AccessLevel::Private: case AccessLevel::FilePrivate: return maybeAddExternal(SILLinkage::Private); case AccessLevel::Internal: case AccessLevel::Public: case AccessLevel::Open: return SILLinkage::Shared; } } // Calling convention thunks have shared linkage. if (isForeignToNativeThunk()) return SILLinkage::Shared; // If a function declares a @_cdecl name, its native-to-foreign thunk // is exported with the visibility of the function. if (isNativeToForeignThunk() && !d->getAttrs().hasAttribute<CDeclAttr>()) return SILLinkage::Shared; // Declarations imported from Clang modules have shared linkage. if (isClangImported()) return SILLinkage::Shared; // Default argument generators of Public functions have PublicNonABI linkage // if the function was type-checked in Swift 4 mode. if (kind == SILDeclRef::Kind::DefaultArgGenerator) { if (isSerialized()) return maybeAddExternal(SILLinkage::PublicNonABI); } enum class Limit { /// No limit. None, /// The declaration is emitted on-demand; it should end up with internal /// or shared linkage. OnDemand, /// The declaration should never be made public. NeverPublic }; auto limit = Limit::None; // ivar initializers and destroyers are completely contained within the class // from which they come, and never get seen externally. if (isIVarInitializerOrDestroyer()) { limit = Limit::NeverPublic; } // Stored property initializers get the linkage of their containing type. if (isStoredPropertyInitializer()) { // Three cases: // // 1) Type is formally @_fixed_layout. Root initializers can be declared // @inlinable. The property initializer must only reference // public symbols, and is serialized, so we give it PublicNonABI linkage. // // 2) Type is not formally @_fixed_layout and the module is not resilient. // Root initializers can be declared @inlinable. This is the annoying // case. We give the initializer public linkage if the type is public. // // 3) Type is resilient. The property initializer is never public because // root initializers cannot be @inlinable. // // FIXME: Get rid of case 2 somehow. if (isSerialized()) return maybeAddExternal(SILLinkage::PublicNonABI); d = cast<NominalTypeDecl>(d->getDeclContext()); // FIXME: This should always be true. if (d->getDeclContext()->getParentModule()->getResilienceStrategy() == ResilienceStrategy::Resilient) limit = Limit::NeverPublic; } // The global addressor is never public for resilient globals. if (kind == Kind::GlobalAccessor) { if (cast<VarDecl>(d)->isResilient()) { limit = Limit::NeverPublic; } } // Forced-static-dispatch functions are created on-demand and have // at best shared linkage. if (auto fn = dyn_cast<FuncDecl>(d)) { if (fn->hasForcedStaticDispatch()) { limit = Limit::OnDemand; } } auto effectiveAccess = d->getEffectiveAccess(); // Private setter implementations for an internal storage declaration should // be internal as well, so that a dynamically-writable // keypath can be formed from other files. if (auto accessor = dyn_cast<AccessorDecl>(d)) { if (accessor->isSetter() && accessor->getStorage()->getEffectiveAccess() == AccessLevel::Internal) effectiveAccess = AccessLevel::Internal; } switch (effectiveAccess) { case AccessLevel::Private: case AccessLevel::FilePrivate: return maybeAddExternal(SILLinkage::Private); case AccessLevel::Internal: if (limit == Limit::OnDemand) return SILLinkage::Shared; return maybeAddExternal(SILLinkage::Hidden); case AccessLevel::Public: case AccessLevel::Open: if (limit == Limit::OnDemand) return SILLinkage::Shared; if (limit == Limit::NeverPublic) return maybeAddExternal(SILLinkage::Hidden); return maybeAddExternal(SILLinkage::Public); } llvm_unreachable("unhandled access"); }
bool ide::printDeclUSR(const ValueDecl *D, raw_ostream &OS) { using namespace Mangle; if (!D->hasName() && (!isa<FuncDecl>(D) || cast<FuncDecl>(D)->getAccessorKind() == AccessorKind::NotAccessor)) return true; // Ignore. if (D->getModuleContext()->isBuiltinModule()) return true; // Ignore. ValueDecl *VD = const_cast<ValueDecl *>(D); auto interpretAsClangNode = [](const ValueDecl *D)->ClangNode { ClangNode ClangN = D->getClangNode(); if (auto ClangD = ClangN.getAsDecl()) { // NSErrorDomain causes the clang enum to be imported like this: // // struct MyError { // enum Code : Int32 { // case errFirst // case errSecond // } // static var errFirst: MyError.Code { get } // static var errSecond: MyError.Code { get } // } // // The clang enum and enum constants are associated with both the // struct/nested enum, and the static vars/enum cases. // But we want unique USRs for the above symbols, so use the clang USR // for the enum and enum cases, and the Swift USR for the struct and vars. // if (isa<clang::EnumDecl>(ClangD)) { if (ClangD->hasAttr<clang::NSErrorDomainAttr>() && isa<StructDecl>(D)) return ClangNode(); } else if (auto *ClangEnumConst = dyn_cast<clang::EnumConstantDecl>(ClangD)) { if (auto *ClangEnum = dyn_cast<clang::EnumDecl>(ClangEnumConst->getDeclContext())) { if (ClangEnum->hasAttr<clang::NSErrorDomainAttr>() && isa<VarDecl>(D)) return ClangNode(); } } } return ClangN; }; if (ClangNode ClangN = interpretAsClangNode(D)) { llvm::SmallString<128> Buf; if (auto ClangD = ClangN.getAsDecl()) { bool Ignore = clang::index::generateUSRForDecl(ClangD, Buf); if (!Ignore) OS << Buf.str(); return Ignore; } auto &Importer = *D->getASTContext().getClangModuleLoader(); auto ClangMacroInfo = ClangN.getAsMacro(); bool Ignore = clang::index::generateUSRForMacro(D->getNameStr(), ClangMacroInfo->getDefinitionLoc(), Importer.getClangASTContext().getSourceManager(), Buf); if (!Ignore) OS << Buf.str(); return Ignore; } if (ShouldUseObjCUSR(VD)) { return printObjCUSR(VD, OS); } if (!D->hasInterfaceType()) return true; // FIXME: mangling 'self' in destructors crashes in mangler. if (isa<ParamDecl>(VD) && isa<DestructorDecl>(VD->getDeclContext())) return true; NewMangling::ASTMangler NewMangler; std::string Mangled = NewMangler.mangleDeclAsUSR(VD, getUSRSpacePrefix()); OS << Mangled; return false; }