//===--- ClangSyntaxPrinter.cpp - Printer for C and C++ code ----*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "ClangSyntaxPrinter.h" #include "PrimitiveTypeMapping.h" #include "swift/ABI/MetadataValues.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/Module.h" #include "swift/AST/SwiftNameTranslation.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/Assertions.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/NestedNameSpecifier.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" using namespace swift; using namespace cxx_synthesis; StringRef cxx_synthesis::getCxxSwiftNamespaceName() { return "swift"; } StringRef cxx_synthesis::getCxxImplNamespaceName() { return "_impl"; } StringRef cxx_synthesis::getCxxOpaqueStorageClassName() { return "OpaqueStorage"; } bool ClangSyntaxPrinter::isClangKeyword(StringRef name) { static const llvm::DenseSet keywords = [] { llvm::DenseSet set; // FIXME: clang::IdentifierInfo /nearly/ has the API we need to do this // in a more principled way, but not quite. #define KEYWORD(SPELLING, FLAGS) set.insert(#SPELLING); #define CXX_KEYWORD_OPERATOR(SPELLING, TOK) set.insert(#SPELLING); #include "clang/Basic/TokenKinds.def" return set; }(); return keywords.contains(name); } bool ClangSyntaxPrinter::isClangKeyword(Identifier name) { if (name.empty()) return false; return ClangSyntaxPrinter::isClangKeyword(name.str()); } void ClangSyntaxPrinter::printIdentifier(StringRef name) const { os << name; if (ClangSyntaxPrinter::isClangKeyword(name)) os << '_'; } void ClangSyntaxPrinter::printBaseName(const ValueDecl *decl) const { assert(decl->getName().isSimpleName()); printIdentifier(cxx_translation::getNameForCxx(decl)); } void ClangSyntaxPrinter::printModuleNameCPrefix(const ModuleDecl &mod) { os << mod.getName().str() << '_'; } void ClangSyntaxPrinter::printModuleNamespaceQualifiersIfNeeded( const ModuleDecl *referencedModule, const ModuleDecl *currentContext) { if (referencedModule == currentContext) return; printBaseName(referencedModule); os << "::"; } bool ClangSyntaxPrinter::printNominalTypeOutsideMemberDeclTemplateSpecifiers( const NominalTypeDecl *typeDecl) { if (!typeDecl->isGeneric()) return true; printGenericSignature( typeDecl->getGenericSignature().getCanonicalSignature()); return false; } bool ClangSyntaxPrinter::printNominalTypeOutsideMemberDeclInnerStaticAssert( const NominalTypeDecl *typeDecl) { if (!typeDecl->isGeneric()) return true; printGenericSignatureInnerStaticAsserts( typeDecl->getGenericSignature().getCanonicalSignature()); return false; } void ClangSyntaxPrinter::printClangTypeReference(const clang::Decl *typeDecl) { if (cast(typeDecl)->getDeclName().isEmpty() && isa(typeDecl)) { if (auto *tnd = cast(typeDecl)->getTypedefNameForAnonDecl()) { printClangTypeReference(tnd); return; } } auto &clangCtx = typeDecl->getASTContext(); clang::PrintingPolicy pp(clangCtx.getLangOpts()); const auto *NS = clang::NestedNameSpecifier::getRequiredQualification( clangCtx, clangCtx.getTranslationUnitDecl(), typeDecl->getLexicalDeclContext()); if (NS) NS->print(os, pp); assert(cast(typeDecl)->getDeclName().isIdentifier()); os << cast(typeDecl)->getName(); if (auto *ctd = dyn_cast(typeDecl)) { if (ctd->getTemplateArgs().size()) { os << '<'; llvm::interleaveComma(ctd->getTemplateArgs().asArray(), os, [&](const clang::TemplateArgument &arg) { arg.print(pp, os, /*IncludeType=*/true); }); os << '>'; } } } bool ClangSyntaxPrinter::printNestedTypeNamespaceQualifiers(const ValueDecl *D, bool forC) const { bool first = true; while (auto parent = dyn_cast_or_null( D->getDeclContext()->getAsDecl())) { // C++ namespaces are imported as enums. if (parent->hasClangNode() && isa(parent->getClangNode().getAsDecl())) break; if (!first) os << (forC ? "_" : "::"); first = false; if (!forC) os << "__"; printBaseName(parent); os << "Nested"; D = parent; } return first; } void ClangSyntaxPrinter::printNominalTypeReference( const NominalTypeDecl *typeDecl, const ModuleDecl *moduleContext) { if (typeDecl->hasClangNode()) { printClangTypeReference(typeDecl->getClangDecl()); return; } printModuleNamespaceQualifiersIfNeeded(typeDecl->getModuleContext(), moduleContext); if (!printNestedTypeNamespaceQualifiers(typeDecl)) os << "::"; ClangSyntaxPrinter(typeDecl->getASTContext(), os).printBaseName(typeDecl); if (typeDecl->isGeneric()) printGenericSignatureParams( typeDecl->getGenericSignature().getCanonicalSignature()); } void ClangSyntaxPrinter::printNominalTypeQualifier( const NominalTypeDecl *typeDecl, const ModuleDecl *moduleContext) { printNominalTypeReference(typeDecl, moduleContext); os << "::"; } void ClangSyntaxPrinter::printModuleNamespaceStart( const ModuleDecl &moduleContext) const { os << "namespace "; printBaseName(&moduleContext); os << " SWIFT_PRIVATE_ATTR"; printSymbolUSRAttribute(&moduleContext); os << " {\n"; } /// Print a C++ namespace declaration with the give name and body. void ClangSyntaxPrinter::printNamespace( llvm::function_ref namePrinter, llvm::function_ref bodyPrinter, NamespaceTrivia trivia, const ModuleDecl *moduleContext) const { os << "namespace "; namePrinter(os); if (trivia == NamespaceTrivia::AttributeSwiftPrivate) os << " SWIFT_PRIVATE_ATTR"; if (moduleContext) printSymbolUSRAttribute(moduleContext); os << " {\n\n"; bodyPrinter(os); os << "\n} // namespace "; namePrinter(os); os << "\n\n"; } void ClangSyntaxPrinter::printNamespace( StringRef name, llvm::function_ref bodyPrinter, NamespaceTrivia trivia) const { printNamespace([&](raw_ostream &os) { os << name; }, bodyPrinter, trivia); } void ClangSyntaxPrinter::printParentNamespaceForNestedTypes( const ValueDecl *D, llvm::function_ref bodyPrinter, NamespaceTrivia trivia) const { if (!isa_and_nonnull(D->getDeclContext()->getAsDecl()) || importer::isClangNamespace(D->getDeclContext())) { bodyPrinter(os); return; } printNamespace( [=](raw_ostream &os) { printNestedTypeNamespaceQualifiers(D); }, bodyPrinter, trivia); } void ClangSyntaxPrinter::printExternC( llvm::function_ref bodyPrinter) const { os << "#ifdef __cplusplus\n"; os << "extern \"C\" {\n"; os << "#endif\n\n"; bodyPrinter(os); os << "\n#ifdef __cplusplus\n"; os << "}\n"; os << "#endif\n"; } void ClangSyntaxPrinter::printObjCBlock( llvm::function_ref bodyPrinter) const { os << "#if defined(__OBJC__)\n"; bodyPrinter(os); os << "\n#endif // defined(__OBJC__)\n"; } void ClangSyntaxPrinter::printSwiftImplQualifier() const { os << "swift::" << cxx_synthesis::getCxxImplNamespaceName() << "::"; } void ClangSyntaxPrinter::printInlineForThunk() const { os << "SWIFT_INLINE_THUNK "; } void ClangSyntaxPrinter::printInlineForHelperFunction() const { os << "SWIFT_INLINE_PRIVATE_HELPER "; } void ClangSyntaxPrinter::printNullability( std::optional kind, NullabilityPrintKind printKind) const { if (!kind) return; switch (printKind) { case NullabilityPrintKind::ContextSensitive: switch (*kind) { case OTK_None: os << "nonnull"; break; case OTK_Optional: os << "nullable"; break; case OTK_ImplicitlyUnwrappedOptional: os << "null_unspecified"; break; } break; case NullabilityPrintKind::After: os << ' '; LLVM_FALLTHROUGH; case NullabilityPrintKind::Before: switch (*kind) { case OTK_None: os << "_Nonnull"; break; case OTK_Optional: os << "_Nullable"; break; case OTK_ImplicitlyUnwrappedOptional: os << "_Null_unspecified"; break; } break; } if (printKind != NullabilityPrintKind::After) os << ' '; } void ClangSyntaxPrinter::printSwiftTypeMetadataAccessFunctionCall( StringRef name, ArrayRef requirements) { os << name << "(0"; printGenericRequirementsInstantiantions(requirements, LeadingTrivia::Comma); os << ')'; } void ClangSyntaxPrinter::printValueWitnessTableAccessSequenceFromTypeMetadata( StringRef metadataVariable, StringRef vwTableVariable, int indent) { os << std::string(indent, ' '); os << "auto *vwTableAddr = "; os << "reinterpret_cast<"; printSwiftImplQualifier(); os << "ValueWitnessTable **>(" << metadataVariable << "._0) - 1;\n"; os << "#ifdef __arm64e__\n"; os << std::string(indent, ' '); os << "auto *" << vwTableVariable << " = "; os << "reinterpret_cast<"; printSwiftImplQualifier(); os << "ValueWitnessTable *>(ptrauth_auth_data("; os << "reinterpret_cast(*vwTableAddr), " "ptrauth_key_process_independent_data, "; os << "ptrauth_blend_discriminator(vwTableAddr, " << SpecialPointerAuthDiscriminators::ValueWitnessTable << ")));\n"; os << "#else\n"; os << std::string(indent, ' '); os << "auto *" << vwTableVariable << " = *vwTableAddr;\n"; os << "#endif\n"; } void ClangSyntaxPrinter::printCTypeMetadataTypeFunction( const TypeDecl *typeDecl, StringRef typeMetadataFuncName, llvm::ArrayRef genericRequirements) { // FIXME: Support generic requirements > 3. if (!genericRequirements.empty()) os << "static_assert(" << genericRequirements.size() << " <= " << NumDirectGenericTypeMetadataAccessFunctionArgs << ", \"unsupported generic requirement list for metadata func\");\n"; os << "// Type metadata accessor for " << typeDecl->getNameStr() << "\n"; os << "SWIFT_EXTERN "; printSwiftImplQualifier(); os << "MetadataResponseTy " << typeMetadataFuncName << '('; printSwiftImplQualifier(); os << "MetadataRequestTy"; if (!genericRequirements.empty()) os << ", "; llvm::interleaveComma(genericRequirements, os, [&](const GenericRequirement &) { // FIXME: Print parameter name. os << "void * _Nonnull"; }); os << ')'; os << " SWIFT_NOEXCEPT SWIFT_CALL;\n\n"; } void ClangSyntaxPrinter::printGenericTypeParamTypeName( const GenericTypeParamType *gtpt) { os << "T_" << gtpt->getDepth() << '_' << gtpt->getIndex(); } void ClangSyntaxPrinter::printGenericSignature( GenericSignature signature) { os << "template<"; llvm::interleaveComma(signature.getInnermostGenericParams(), os, [&](const GenericTypeParamType *genericParamType) { os << "class "; printGenericTypeParamTypeName(genericParamType); }); os << ">\n"; os << "#ifdef __cpp_concepts\n"; os << "requires "; llvm::interleave( signature.getInnermostGenericParams(), os, [&](const GenericTypeParamType *genericParamType) { os << "swift::isUsableInGenericContext<"; printGenericTypeParamTypeName(genericParamType); os << ">"; }, " && "); os << "\n#endif // __cpp_concepts\n"; } void ClangSyntaxPrinter::printGenericSignatureInnerStaticAsserts( GenericSignature signature) { os << "#ifndef __cpp_concepts\n"; llvm::interleave( signature.getInnermostGenericParams(), os, [&](const GenericTypeParamType *genericParamType) { os << "static_assert(swift::isUsableInGenericContext<"; printGenericTypeParamTypeName(genericParamType); os << ">, \"type cannot be used in a Swift generic context\");"; }, "\n"); os << "\n#endif // __cpp_concepts\n"; } void ClangSyntaxPrinter::printGenericSignatureParams( GenericSignature signature) { os << '<'; llvm::interleaveComma(signature.getInnermostGenericParams(), os, [&](const GenericTypeParamType *genericParamType) { printGenericTypeParamTypeName(genericParamType); }); os << '>'; } void ClangSyntaxPrinter::printGenericRequirementInstantiantion( const GenericRequirement &requirement) { assert(requirement.isAnyMetadata() && "protocol requirements not supported yet!"); auto *gtpt = requirement.getTypeParameter()->getAs(); assert(gtpt && "unexpected generic param type"); os << "swift::TypeMetadataTrait<"; printGenericTypeParamTypeName(gtpt); os << ">::getTypeMetadata()"; } void ClangSyntaxPrinter::printGenericRequirementsInstantiantions( ArrayRef requirements, LeadingTrivia leadingTrivia) { if (leadingTrivia == LeadingTrivia::Comma && !requirements.empty()) os << ", "; llvm::interleaveComma(requirements, os, [&](const GenericRequirement &requirement) { printGenericRequirementInstantiantion(requirement); }); } void ClangSyntaxPrinter::printPrimaryCxxTypeName( const NominalTypeDecl *type, const ModuleDecl *moduleContext) { printModuleNamespaceQualifiersIfNeeded(type->getModuleContext(), moduleContext); if (!printNestedTypeNamespaceQualifiers(type)) os << "::"; printBaseName(type); } void ClangSyntaxPrinter::printIncludeForShimHeader(StringRef headerName) { printIgnoredDiagnosticBlock("non-modular-include-in-framework-module", [&] { os << "// Allow user to find the header using additional include paths\n"; os << "#if __has_include()\n"; os << "#include \n"; os << "// Look for the C++ interop support header relative to clang's " "resource dir:\n"; os << "// " "'/usr/lib/clang//include/../../../swift/" "swiftToCxx'.\n"; os << "#elif __has_include(<../../../swift/swiftToCxx/" << headerName << ">)\n"; os << "#include <../../../swift/swiftToCxx/" << headerName << ">\n"; os << "#elif __has_include(<../../../../../lib/swift/swiftToCxx/" << headerName << ">)\n"; os << "// " "'/usr/local/lib/clang//include/../../../../../" "lib/" "swift/swiftToCxx'.\n"; os << "#include <../../../../../lib/swift/swiftToCxx/" << headerName << ">\n"; os << "#endif\n"; }); } void ClangSyntaxPrinter::printDefine(StringRef macroName) { os << "#define " << macroName << "\n"; } void ClangSyntaxPrinter::printIgnoredDiagnosticBlock( StringRef diagName, llvm::function_ref bodyPrinter) { os << "#pragma clang diagnostic push\n"; os << "#pragma clang diagnostic ignored \"-W" << diagName << "\"\n"; bodyPrinter(); os << "#pragma clang diagnostic pop\n"; } void ClangSyntaxPrinter::printIgnoredCxx17ExtensionDiagnosticBlock( llvm::function_ref bodyPrinter) { printIgnoredDiagnosticBlock("c++17-extensions", bodyPrinter); } void ClangSyntaxPrinter::printSymbolUSRAttribute(const ValueDecl *D) const { if (isa(D)) { os << " SWIFT_SYMBOL_MODULE(\""; printBaseName(D); os << "\")"; return; } auto result = evaluateOrDefault(D->getASTContext().evaluator, USRGenerationRequest{D, {}}, std::string()); if (result.empty()) return; os << " SWIFT_SYMBOL(\"" << result << "\")"; } void ClangSyntaxPrinter::printKnownCType( Type t, PrimitiveTypeMapping &typeMapping) const { auto info = typeMapping.getKnownCTypeInfo(t->getNominalOrBoundGenericNominal()); assert(info.has_value() && "not a known type"); os << info->name; if (info->canBeNullable) os << " _Null_unspecified"; } void ClangSyntaxPrinter::printSwiftMangledNameForDebugger( const NominalTypeDecl *typeDecl) { printIgnoredCxx17ExtensionDiagnosticBlock([&]() { os << "#pragma clang diagnostic push\n"; os << "#pragma clang diagnostic ignored \"-Wreserved-identifier\"\n"; auto mangled_name = mangler.mangleTypeForDebugger( typeDecl->getDeclaredInterfaceType(), nullptr); if (!mangled_name.empty()) { os << " typedef char " << mangled_name << ";\n"; os << " static inline constexpr " << mangled_name << " __swift_mangled_name = 0;\n"; } }); os << "#pragma clang diagnostic pop\n"; }