Files
swift-mirror/lib/PrintAsClang/ClangSyntaxPrinter.cpp
Anthony Latsis bda6edb85c AST: Rename GenericContext::isGeneric to hasGenericParamList
`isGeneric` is a misleading name because this method checks for the
existence of a `GenericParamList`, which is not implied by genericity.
2025-11-11 15:55:16 +00:00

524 lines
18 KiB
C++

//===--- 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 "DeclAndTypePrinter.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/Type.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<StringRef> keywords = [] {
llvm::DenseSet<StringRef> 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->hasGenericParamList())
return true;
printGenericSignature(
typeDecl->getGenericSignature().getCanonicalSignature());
return false;
}
bool ClangSyntaxPrinter::printNominalTypeOutsideMemberDeclInnerStaticAssert(
const NominalTypeDecl *typeDecl) {
if (!typeDecl->hasGenericParamList())
return true;
printGenericSignatureInnerStaticAsserts(
typeDecl->getGenericSignature().getCanonicalSignature());
return false;
}
void ClangSyntaxPrinter::printClangTypeReference(const clang::Decl *typeDecl) {
StringRef osObjectName = DeclAndTypePrinter::maybeGetOSObjectBaseName(
dyn_cast<clang::NamedDecl>(cast<clang::NamedDecl>(typeDecl)));
if (!osObjectName.empty()) {
os << osObjectName << "_t";
return;
}
if (cast<clang::NamedDecl>(typeDecl)->getDeclName().isEmpty() &&
isa<clang::TagDecl>(typeDecl)) {
if (auto *tnd =
cast<clang::TagDecl>(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<clang::NamedDecl>(typeDecl)->getDeclName().isIdentifier());
os << cast<clang::NamedDecl>(typeDecl)->getName();
if (auto *ctd = dyn_cast<clang::ClassTemplateSpecializationDecl>(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 = D->getDeclContext()->getAsDecl()) {
const auto *parentNTD = dyn_cast<NominalTypeDecl>(parent);
if (!parentNTD)
if (const auto *ED = dyn_cast<ExtensionDecl>(parent))
parentNTD = ED->getExtendedNominal();
if (!parentNTD)
continue;
// C++ namespaces are imported as enums.
if (parentNTD->hasClangNode() &&
isa<clang::NamespaceDecl>(parentNTD->getClangNode().getAsDecl()))
break;
if (!first)
os << (forC ? "_" : "::");
first = false;
if (!forC)
os << "__";
printBaseName(parentNTD);
os << "Nested";
D = parentNTD;
}
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->hasGenericParamList())
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<void(raw_ostream &OS)> namePrinter,
llvm::function_ref<void(raw_ostream &OS)> 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<void(raw_ostream &OS)> bodyPrinter,
NamespaceTrivia trivia) const {
printNamespace([&](raw_ostream &os) { os << name; }, bodyPrinter, trivia);
}
void ClangSyntaxPrinter::printParentNamespaceForNestedTypes(
const ValueDecl *D, llvm::function_ref<void(raw_ostream &OS)> bodyPrinter,
NamespaceTrivia trivia) const {
if ((!isa_and_nonnull<NominalTypeDecl>(D->getDeclContext()->getAsDecl()) &&
!isa_and_nonnull<ExtensionDecl>(D->getDeclContext()->getAsDecl())) ||
importer::isClangNamespace(D->getDeclContext())) {
bodyPrinter(os);
return;
}
printNamespace(
[=](raw_ostream &os) { printNestedTypeNamespaceQualifiers(D); },
bodyPrinter, trivia);
}
void ClangSyntaxPrinter::printExternC(
llvm::function_ref<void(raw_ostream &OS)> 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<void(raw_ostream &OS)> 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<OptionalTypeKind> 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<GenericRequirement> 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<void *>(*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<GenericRequirement> 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<GenericTypeParamType>();
assert(gtpt && "unexpected generic param type");
os << "swift::TypeMetadataTrait<";
printGenericTypeParamTypeName(gtpt);
os << ">::getTypeMetadata()";
}
void ClangSyntaxPrinter::printGenericRequirementsInstantiantions(
ArrayRef<GenericRequirement> 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(<swiftToCxx/" << headerName << ">)\n";
os << "#include <swiftToCxx/" << headerName << ">\n";
os << "// Look for the C++ interop support header relative to clang's "
"resource dir:\n";
os << "// "
"'<toolchain>/usr/lib/clang/<version>/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 << "// "
"'<toolchain>/usr/local/lib/clang/<version>/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<void()> 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<void()> bodyPrinter) {
printIgnoredDiagnosticBlock("c++17-extensions", bodyPrinter);
}
void ClangSyntaxPrinter::printSymbolUSRAttribute(const ValueDecl *D) const {
if (isa<ModuleDecl>(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";
}