diff options
Diffstat (limited to 'clang/lib')
33 files changed, 763 insertions, 1304 deletions
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 94a47a8..45d4c96 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -4541,6 +4541,10 @@ ExpectedDecl ASTNodeImporter::VisitVarDecl(VarDecl *D) { ToVar->setQualifierInfo(ToQualifierLoc); ToVar->setAccess(D->getAccess()); ToVar->setLexicalDeclContext(LexicalDC); + if (D->isInlineSpecified()) + ToVar->setInlineSpecified(); + if (D->isInline()) + ToVar->setImplicitlyInline(); if (FoundByLookup) { auto *Recent = const_cast<VarDecl *>(FoundByLookup->getMostRecentDecl()); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 2cbb86b31..66a727d 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1852,9 +1852,9 @@ DeclContext::lookup(DeclarationName Name) const { DeclContext::lookup_result DeclContext::noload_lookup(DeclarationName Name) { - assert(getDeclKind() != Decl::LinkageSpec && - getDeclKind() != Decl::Export && - "should not perform lookups into transparent contexts"); + // For transparent DeclContext, we should lookup in their enclosing context. + if (getDeclKind() == Decl::LinkageSpec || getDeclKind() == Decl::Export) + return getParent()->noload_lookup(Name); DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 9d551ff..075c8aba 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1746,14 +1746,15 @@ void TypePrinter::printPackExpansionAfter(const PackExpansionType *T, static void printCountAttributedImpl(const CountAttributedType *T, raw_ostream &OS, const PrintingPolicy &Policy) { + OS << ' '; if (T->isCountInBytes() && T->isOrNull()) - OS << " __sized_by_or_null("; + OS << "__sized_by_or_null("; else if (T->isCountInBytes()) - OS << " __sized_by("; + OS << "__sized_by("; else if (T->isOrNull()) - OS << " __counted_by_or_null("; + OS << "__counted_by_or_null("; else - OS << " __counted_by("; + OS << "__counted_by("; if (T->getCountExpr()) T->getCountExpr()->printPretty(OS, nullptr, Policy); OS << ')'; @@ -1762,14 +1763,14 @@ static void printCountAttributedImpl(const CountAttributedType *T, void TypePrinter::printCountAttributedBefore(const CountAttributedType *T, raw_ostream &OS) { printBefore(T->desugar(), OS); - if (!T->desugar()->isArrayType()) + if (!T->isArrayType()) printCountAttributedImpl(T, OS, Policy); } void TypePrinter::printCountAttributedAfter(const CountAttributedType *T, raw_ostream &OS) { printAfter(T->desugar(), OS); - if (T->desugar()->isArrayType()) + if (T->isArrayType()) printCountAttributedImpl(T, OS, Policy); } diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index f729d67..70ac076 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -166,17 +166,16 @@ static Value *joinDistinctValues(QualType Type, Value &Val1, return JoinedVal; } -// When widening does not change `Current`, return value will equal `&Prev`. -static Value &widenDistinctValues(QualType Type, Value &Prev, - const Environment &PrevEnv, Value &Current, - Environment &CurrentEnv, - Environment::ValueModel &Model) { +static WidenResult widenDistinctValues(QualType Type, Value &Prev, + const Environment &PrevEnv, + Value &Current, Environment &CurrentEnv, + Environment::ValueModel &Model) { // Boolean-model widening. if (auto *PrevBool = dyn_cast<BoolValue>(&Prev)) { - // If previous value was already Top, re-use that to (implicitly) indicate - // that no change occurred. if (isa<TopBoolValue>(Prev)) - return Prev; + // Safe to return `Prev` here, because Top is never dependent on the + // environment. + return {&Prev, LatticeEffect::Unchanged}; // We may need to widen to Top, but before we do so, check whether both // values are implied to be either true or false in the current environment. @@ -185,22 +184,24 @@ static Value &widenDistinctValues(QualType Type, Value &Prev, bool TruePrev = PrevEnv.proves(PrevBool->formula()); bool TrueCur = CurrentEnv.proves(CurBool.formula()); if (TruePrev && TrueCur) - return CurrentEnv.getBoolLiteralValue(true); + return {&CurrentEnv.getBoolLiteralValue(true), LatticeEffect::Unchanged}; if (!TruePrev && !TrueCur && PrevEnv.proves(PrevEnv.arena().makeNot(PrevBool->formula())) && CurrentEnv.proves(CurrentEnv.arena().makeNot(CurBool.formula()))) - return CurrentEnv.getBoolLiteralValue(false); + return {&CurrentEnv.getBoolLiteralValue(false), LatticeEffect::Unchanged}; - return CurrentEnv.makeTopBoolValue(); + return {&CurrentEnv.makeTopBoolValue(), LatticeEffect::Changed}; } // FIXME: Add other built-in model widening. // Custom-model widening. - if (auto *W = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv)) - return *W; + if (auto Result = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv)) + return *Result; - return equateUnknownValues(Prev.getKind()) ? Prev : Current; + return {&Current, equateUnknownValues(Prev.getKind()) + ? LatticeEffect::Unchanged + : LatticeEffect::Changed}; } // Returns whether the values in `Map1` and `Map2` compare equal for those @@ -271,7 +272,7 @@ llvm::MapVector<Key, Value *> widenKeyToValueMap(const llvm::MapVector<Key, Value *> &CurMap, const llvm::MapVector<Key, Value *> &PrevMap, Environment &CurEnv, const Environment &PrevEnv, - Environment::ValueModel &Model, LatticeJoinEffect &Effect) { + Environment::ValueModel &Model, LatticeEffect &Effect) { llvm::MapVector<Key, Value *> WidenedMap; for (auto &Entry : CurMap) { Key K = Entry.first; @@ -290,11 +291,11 @@ widenKeyToValueMap(const llvm::MapVector<Key, Value *> &CurMap, continue; } - Value &WidenedVal = widenDistinctValues(K->getType(), *PrevIt->second, - PrevEnv, *Val, CurEnv, Model); - WidenedMap.insert({K, &WidenedVal}); - if (&WidenedVal != PrevIt->second) - Effect = LatticeJoinEffect::Changed; + auto [WidenedVal, ValEffect] = widenDistinctValues( + K->getType(), *PrevIt->second, PrevEnv, *Val, CurEnv, Model); + WidenedMap.insert({K, WidenedVal}); + if (ValEffect == LatticeEffect::Changed) + Effect = LatticeEffect::Changed; } return WidenedMap; @@ -617,15 +618,15 @@ bool Environment::equivalentTo(const Environment &Other, return true; } -LatticeJoinEffect Environment::widen(const Environment &PrevEnv, - Environment::ValueModel &Model) { +LatticeEffect Environment::widen(const Environment &PrevEnv, + Environment::ValueModel &Model) { assert(DACtx == PrevEnv.DACtx); assert(ReturnVal == PrevEnv.ReturnVal); assert(ReturnLoc == PrevEnv.ReturnLoc); assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc); assert(CallStack == PrevEnv.CallStack); - auto Effect = LatticeJoinEffect::Unchanged; + auto Effect = LatticeEffect::Unchanged; // By the API, `PrevEnv` is a previous version of the environment for the same // block, so we have some guarantees about its shape. In particular, it will @@ -646,7 +647,7 @@ LatticeJoinEffect Environment::widen(const Environment &PrevEnv, ExprToLoc.size() != PrevEnv.ExprToLoc.size() || ExprToVal.size() != PrevEnv.ExprToVal.size() || LocToVal.size() != PrevEnv.LocToVal.size()) - Effect = LatticeJoinEffect::Changed; + Effect = LatticeEffect::Changed; return Effect; } diff --git a/clang/lib/Basic/Targets/Mips.h b/clang/lib/Basic/Targets/Mips.h index c9dcf43..0d6e4b4 100644 --- a/clang/lib/Basic/Targets/Mips.h +++ b/clang/lib/Basic/Targets/Mips.h @@ -318,6 +318,7 @@ public: FPMode = isFP64Default() ? FP64 : FPXX; NoOddSpreg = false; bool OddSpregGiven = false; + bool StrictAlign = false; for (const auto &Feature : Features) { if (Feature == "+single-float") @@ -330,6 +331,10 @@ public: IsMicromips = true; else if (Feature == "+mips32r6" || Feature == "+mips64r6") HasUnalignedAccess = true; + // We cannot be sure that the order of strict-align vs mips32r6. + // Thus we need an extra variable here. + else if (Feature == "+strict-align") + StrictAlign = true; else if (Feature == "+dsp") DspRev = std::max(DspRev, DSP1); else if (Feature == "+dspr2") @@ -368,6 +373,9 @@ public: if (FPMode == FPXX && !OddSpregGiven) NoOddSpreg = true; + if (StrictAlign) + HasUnalignedAccess = false; + setDataLayout(); return true; diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 4899c9b..ee4bd80 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -99,9 +99,6 @@ using namespace llvm; namespace llvm { extern cl::opt<bool> PrintPipelinePasses; -static cl::opt<bool> ClRemoveTraps("clang-remove-traps", cl::Optional, - cl::desc("Insert remove-traps pass.")); - // Experiment to move sanitizers earlier. static cl::opt<bool> ClSanitizeOnOptimizerEarlyEP( "sanitizer-early-opt-ep", cl::Optional, @@ -749,7 +746,7 @@ static void addSanitizers(const Triple &TargetTriple, PB.registerOptimizerLastEPCallback(SanitizersCallback); } - if (ClRemoveTraps) { + if (RemoveTrapsPass::IsRequested()) { // We can optimize after inliner, and PGO profile matching. The hook below // is called at the end `buildFunctionSimplificationPipeline`, which called // from `buildInlinerPipeline`, which called after profile matching. diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index a01f2c7..47f063b 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -962,7 +962,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { } // If it's a reference variable, copy the reference into the block field. - } else if (auto refType = type->getAs<ReferenceType>()) { + } else if (type->getAs<ReferenceType>()) { Builder.CreateStore(src.emitRawPointer(*this), blockField); // If type is const-qualified, copy the value into the block field. diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 483f9c2..2537e71 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -7281,8 +7281,6 @@ static const std::pair<unsigned, unsigned> NEONEquivalentIntrinsicMap[] = { { NEON::BI__builtin_neon_vabdq_f16, NEON::BI__builtin_neon_vabdq_v, }, { NEON::BI__builtin_neon_vabs_f16, NEON::BI__builtin_neon_vabs_v, }, { NEON::BI__builtin_neon_vabsq_f16, NEON::BI__builtin_neon_vabsq_v, }, - { NEON::BI__builtin_neon_vbsl_f16, NEON::BI__builtin_neon_vbsl_v, }, - { NEON::BI__builtin_neon_vbslq_f16, NEON::BI__builtin_neon_vbslq_v, }, { NEON::BI__builtin_neon_vcage_f16, NEON::BI__builtin_neon_vcage_v, }, { NEON::BI__builtin_neon_vcageq_f16, NEON::BI__builtin_neon_vcageq_v, }, { NEON::BI__builtin_neon_vcagt_f16, NEON::BI__builtin_neon_vcagt_v, }, @@ -7301,8 +7299,6 @@ static const std::pair<unsigned, unsigned> NEONEquivalentIntrinsicMap[] = { { NEON::BI__builtin_neon_vclezq_f16, NEON::BI__builtin_neon_vclezq_v, }, { NEON::BI__builtin_neon_vcltz_f16, NEON::BI__builtin_neon_vcltz_v, }, { NEON::BI__builtin_neon_vcltzq_f16, NEON::BI__builtin_neon_vcltzq_v, }, - { NEON::BI__builtin_neon_vext_f16, NEON::BI__builtin_neon_vext_v, }, - { NEON::BI__builtin_neon_vextq_f16, NEON::BI__builtin_neon_vextq_v, }, { NEON::BI__builtin_neon_vfma_f16, NEON::BI__builtin_neon_vfma_v, }, { NEON::BI__builtin_neon_vfma_lane_f16, NEON::BI__builtin_neon_vfma_lane_v, }, { NEON::BI__builtin_neon_vfma_laneq_f16, NEON::BI__builtin_neon_vfma_laneq_v, }, @@ -7405,12 +7401,6 @@ static const std::pair<unsigned, unsigned> NEONEquivalentIntrinsicMap[] = { { NEON::BI__builtin_neon_vst4_lane_bf16, NEON::BI__builtin_neon_vst4_lane_v }, { NEON::BI__builtin_neon_vst4q_bf16, NEON::BI__builtin_neon_vst4q_v }, { NEON::BI__builtin_neon_vst4q_lane_bf16, NEON::BI__builtin_neon_vst4q_lane_v }, - { NEON::BI__builtin_neon_vtrn_f16, NEON::BI__builtin_neon_vtrn_v, }, - { NEON::BI__builtin_neon_vtrnq_f16, NEON::BI__builtin_neon_vtrnq_v, }, - { NEON::BI__builtin_neon_vuzp_f16, NEON::BI__builtin_neon_vuzp_v, }, - { NEON::BI__builtin_neon_vuzpq_f16, NEON::BI__builtin_neon_vuzpq_v, }, - { NEON::BI__builtin_neon_vzip_f16, NEON::BI__builtin_neon_vzip_v, }, - { NEON::BI__builtin_neon_vzipq_f16, NEON::BI__builtin_neon_vzipq_v, }, // The mangling rules cause us to have one ID for each type for vldap1(q)_lane // and vstl1(q)_lane, but codegen is equivalent for all of them. Choose an // arbitrary one to be handled as tha canonical variation. diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 7c66140..5443235 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -56,13 +56,7 @@ using namespace CodeGen; // Experiment to make sanitizers easier to debug static llvm::cl::opt<bool> ClSanitizeDebugDeoptimization( "ubsan-unique-traps", llvm::cl::Optional, - llvm::cl::desc("Deoptimize traps for UBSAN so there is 1 trap per check.")); - -// TODO: Introduce frontend options to enabled per sanitizers, similar to -// `fsanitize-trap`. -static llvm::cl::opt<bool> ClSanitizeExpHot( - "ubsan-exp-hot", llvm::cl::Optional, - llvm::cl::desc("Pass UBSAN checks if `llvm.experimental.hot()` is true.")); + llvm::cl::desc("Deoptimize traps for UBSAN so there is 1 trap per check")); //===--------------------------------------------------------------------===// // Miscellaneous Helper Methods @@ -3804,13 +3798,6 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked, SanitizerHandler CheckHandlerID) { llvm::BasicBlock *Cont = createBasicBlock("cont"); - if (ClSanitizeExpHot) { - llvm::Value *Allow = - Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::allow_ubsan_check), - llvm::ConstantInt::get(CGM.Int8Ty, CheckHandlerID)); - Checked = Builder.CreateOr(Checked, Builder.CreateNot(Allow)); - } - // If we're optimizing, collapse all calls to trap down to just one per // check-type per function to save on code size. if ((int)TrapBBs.size() <= CheckHandlerID) diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index a793b21..1facadd 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -319,12 +319,12 @@ public: // doubles the exponent of SmallerType.LargestFiniteVal) if (llvm::APFloat::semanticsMaxExponent(ElementTypeSemantics) * 2 + 1 <= llvm::APFloat::semanticsMaxExponent(HigherElementTypeSemantics)) { + FPHasBeenPromoted = true; return CGF.getContext().getComplexType(HigherElementType); } else { - FPHasBeenPromoted = true; DiagnosticsEngine &Diags = CGF.CGM.getDiags(); Diags.Report(diag::warn_next_larger_fp_type_same_size_than_fp); - return CGF.getContext().getComplexType(ElementType); + return QualType(); } } @@ -1037,7 +1037,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) { LHSi = llvm::Constant::getNullValue(RHSi->getType()); if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Improved || (Op.FPFeatures.getComplexRange() == LangOptions::CX_Promoted && - FPHasBeenPromoted)) + !FPHasBeenPromoted)) return EmitRangeReductionDiv(LHSr, LHSi, RHSr, RHSi); else if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Basic || Op.FPFeatures.getComplexRange() == LangOptions::CX_Promoted) diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index bc36331..8eb1058 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -2648,9 +2648,9 @@ void CGOpenMPRuntime::emitDistributeStaticInit( void CGOpenMPRuntime::emitForStaticFinish(CodeGenFunction &CGF, SourceLocation Loc, OpenMPDirectiveKind DKind) { - assert(DKind == OMPD_distribute || DKind == OMPD_for || - DKind == OMPD_sections && - "Expected distribute, for, or sections directive kind"); + assert((DKind == OMPD_distribute || DKind == OMPD_for || + DKind == OMPD_sections) && + "Expected distribute, for, or sections directive kind"); if (!CGF.HaveInsertPoint()) return; // Call __kmpc_for_static_fini(ident_t *loc, kmp_int32 tid); diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp index 1146a85..c831777 100644 --- a/clang/lib/CodeGen/Targets/X86.cpp +++ b/clang/lib/CodeGen/Targets/X86.cpp @@ -1069,6 +1069,12 @@ Address X86_32ABIInfo::EmitVAArg(CodeGenFunction &CGF, auto TypeInfo = getContext().getTypeInfoInChars(Ty); + CCState State(*const_cast<CGFunctionInfo *>(CGF.CurFnInfo)); + ABIArgInfo AI = classifyArgumentType(Ty, State, /*ArgIndex*/ 0); + // Empty records are ignored for parameter passing purposes. + if (AI.isIgnore()) + return CGF.CreateMemTemp(Ty); + // x86-32 changes the alignment of certain arguments on the stack. // // Just messing with TypeInfo like this works because we never pass diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 1a0f5f2..e6c1767 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -49,6 +49,7 @@ #include "ToolChains/WebAssembly.h" #include "ToolChains/XCore.h" #include "ToolChains/ZOS.h" +#include "clang/Basic/DiagnosticDriver.h" #include "clang/Basic/TargetID.h" #include "clang/Basic/Version.h" #include "clang/Config/config.h" @@ -5889,6 +5890,12 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, &JA); } + if (JA.getType() == types::TY_API_INFO && + C.getArgs().hasArg(options::OPT_emit_extension_symbol_graphs) && + C.getArgs().hasArg(options::OPT_o)) + Diag(clang::diag::err_drv_unexpected_symbol_graph_output) + << C.getArgs().getLastArgValue(options::OPT_o); + // DXC defaults to standard out when generating assembly. We check this after // any DXC flags that might specify a file. if (AtTopLevel && JA.getType() == types::TY_PP_Asm && IsDXCMode()) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index b03ac60..766a9b91 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4045,9 +4045,18 @@ static bool RenderModulesOptions(Compilation &C, const Driver &D, // module fragment. CmdArgs.push_back("-fskip-odr-check-in-gmf"); - // Claim `-fmodule-output` and `-fmodule-output=` to avoid unused warnings. - Args.ClaimAllArgs(options::OPT_fmodule_output); - Args.ClaimAllArgs(options::OPT_fmodule_output_EQ); + // We need to include the case the input file is a module file here. + // Since the default compilation model for C++ module interface unit will + // create temporary module file and compile the temporary module file + // to get the object file. Then the `-fmodule-output` flag will be + // brought to the second compilation process. So we have to claim it for + // the case too. + if (Input.getType() == driver::types::TY_CXXModule || + Input.getType() == driver::types::TY_PP_CXXModule || + Input.getType() == driver::types::TY_ModuleFile) { + Args.ClaimAllArgs(options::OPT_fmodule_output); + Args.ClaimAllArgs(options::OPT_fmodule_output_EQ); + } return HaveModules; } @@ -5037,11 +5046,26 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, assert(JA.getType() == types::TY_API_INFO && "Extract API actions must generate a API information."); CmdArgs.push_back("-extract-api"); + + if (Arg *PrettySGFArg = Args.getLastArg(options::OPT_emit_pretty_sgf)) + PrettySGFArg->render(Args, CmdArgs); + + Arg *SymbolGraphDirArg = Args.getLastArg(options::OPT_symbol_graph_dir_EQ); + if (Arg *ProductNameArg = Args.getLastArg(options::OPT_product_name_EQ)) ProductNameArg->render(Args, CmdArgs); if (Arg *ExtractAPIIgnoresFileArg = Args.getLastArg(options::OPT_extract_api_ignores_EQ)) ExtractAPIIgnoresFileArg->render(Args, CmdArgs); + if (Arg *EmitExtensionSymbolGraphs = + Args.getLastArg(options::OPT_emit_extension_symbol_graphs)) { + if (!SymbolGraphDirArg) + D.Diag(diag::err_drv_missing_symbol_graph_dir); + + EmitExtensionSymbolGraphs->render(Args, CmdArgs); + } + if (SymbolGraphDirArg) + SymbolGraphDirArg->render(Args, CmdArgs); } else { assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) && "Invalid action for clang tool."); @@ -5858,7 +5882,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CM = "large"; if (Triple.isAArch64(64)) { Ok = CM == "tiny" || CM == "small" || CM == "large"; - if (CM == "large" && RelocationModel != llvm::Reloc::Static) + if (CM == "large" && !Triple.isOSBinFormatMachO() && + RelocationModel != llvm::Reloc::Static) D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) << "-fno-pic"; } else if (Triple.isLoongArch()) { diff --git a/clang/lib/ExtractAPI/API.cpp b/clang/lib/ExtractAPI/API.cpp index aa7a1e9..5a62c5d 100644 --- a/clang/lib/ExtractAPI/API.cpp +++ b/clang/lib/ExtractAPI/API.cpp @@ -13,514 +13,67 @@ //===----------------------------------------------------------------------===// #include "clang/ExtractAPI/API.h" -#include "clang/AST/CommentCommandTraits.h" -#include "clang/AST/CommentLexer.h" #include "clang/AST/RawCommentList.h" +#include "clang/Basic/Module.h" #include "clang/Index/USRGeneration.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/ErrorHandling.h" #include <memory> using namespace clang::extractapi; using namespace llvm; -namespace { +SymbolReference::SymbolReference(const APIRecord *R) + : Name(R->Name), USR(R->USR), Record(R) {} -template <typename RecordTy, typename... CtorArgsTy> -RecordTy *addTopLevelRecord(DenseMap<StringRef, APIRecord *> &USRLookupTable, - APISet::RecordMap<RecordTy> &RecordMap, - StringRef USR, CtorArgsTy &&...CtorArgs) { - auto Result = RecordMap.insert({USR, nullptr}); - - // Create the record if it does not already exist - if (Result.second) - Result.first->second = - std::make_unique<RecordTy>(USR, std::forward<CtorArgsTy>(CtorArgs)...); - - auto *Record = Result.first->second.get(); - USRLookupTable.insert({USR, Record}); - return Record; -} - -} // namespace - -NamespaceRecord * -APISet::addNamespace(APIRecord *Parent, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, - LinkageInfo Linkage, const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader) { - auto *Record = addTopLevelRecord( - USRBasedLookupTable, Namespaces, USR, Name, Loc, std::move(Availability), - Linkage, Comment, Declaration, SubHeading, IsFromSystemHeader); - - if (Parent) - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - return Record; -} - -GlobalVariableRecord * -APISet::addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Fragments, - DeclarationFragments SubHeading, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, GlobalVariables, USR, Name, Loc, - std::move(Availability), Linkage, Comment, Fragments, - SubHeading, IsFromSystemHeader); -} - -GlobalVariableTemplateRecord *APISet::addGlobalVariableTemplate( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, Template Template, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, GlobalVariableTemplates, USR, - Name, Loc, std::move(Availability), Linkage, Comment, - Declaration, SubHeading, Template, - IsFromSystemHeader); -} - -GlobalFunctionRecord *APISet::addGlobalFunction( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Fragments, - DeclarationFragments SubHeading, FunctionSignature Signature, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, GlobalFunctions, USR, Name, Loc, - std::move(Availability), Linkage, Comment, Fragments, - SubHeading, Signature, IsFromSystemHeader); -} - -GlobalFunctionTemplateRecord *APISet::addGlobalFunctionTemplate( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, FunctionSignature Signature, - Template Template, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, GlobalFunctionTemplates, USR, - Name, Loc, std::move(Availability), Linkage, Comment, - Declaration, SubHeading, Signature, Template, - IsFromSystemHeader); -} - -GlobalFunctionTemplateSpecializationRecord * -APISet::addGlobalFunctionTemplateSpecialization( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, FunctionSignature Signature, - bool IsFromSystemHeader) { - return addTopLevelRecord( - USRBasedLookupTable, GlobalFunctionTemplateSpecializations, USR, Name, - Loc, std::move(Availability), Linkage, Comment, Declaration, SubHeading, - Signature, IsFromSystemHeader); -} - -EnumConstantRecord *APISet::addEnumConstant(EnumRecord *Enum, StringRef Name, - StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - bool IsFromSystemHeader) { - auto Record = std::make_unique<EnumConstantRecord>( - USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading, - IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Enum->USR, Enum->Name, Enum->getKind(), Enum); - USRBasedLookupTable.insert({USR, Record.get()}); - return Enum->Constants.emplace_back(std::move(Record)).get(); -} - -EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, Enums, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, IsFromSystemHeader); -} - -RecordFieldRecord *APISet::addRecordField( - RecordRecord *Record, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - APIRecord::RecordKind Kind, bool IsFromSystemHeader) { - auto RecordField = std::make_unique<RecordFieldRecord>( - USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading, - Kind, IsFromSystemHeader); - RecordField->ParentInformation = APIRecord::HierarchyInformation( - Record->USR, Record->Name, Record->getKind(), Record); - USRBasedLookupTable.insert({USR, RecordField.get()}); - return Record->Fields.emplace_back(std::move(RecordField)).get(); -} - -RecordRecord *APISet::addRecord(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - APIRecord::RecordKind Kind, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, Records, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Kind, IsFromSystemHeader); -} - -StaticFieldRecord * -APISet::addStaticField(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, SymbolReference Context, - AccessControl Access, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, StaticFields, USR, Name, Loc, - std::move(Availability), Linkage, Comment, - Declaration, SubHeading, Context, Access, - IsFromSystemHeader); -} - -CXXFieldRecord * -APISet::addCXXField(APIRecord *CXXClass, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, AccessControl Access, - bool IsFromSystemHeader) { - auto *Record = addTopLevelRecord( - USRBasedLookupTable, CXXFields, USR, Name, Loc, std::move(Availability), - Comment, Declaration, SubHeading, Access, IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - CXXClass->USR, CXXClass->Name, CXXClass->getKind(), CXXClass); - return Record; -} - -CXXFieldTemplateRecord *APISet::addCXXFieldTemplate( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - AccessControl Access, Template Template, bool IsFromSystemHeader) { - auto *Record = - addTopLevelRecord(USRBasedLookupTable, CXXFieldTemplates, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Access, Template, IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - - return Record; -} - -CXXClassRecord * -APISet::addCXXClass(APIRecord *Parent, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, APIRecord::RecordKind Kind, - AccessControl Access, bool IsFromSystemHeader) { - auto *Record = addTopLevelRecord( - USRBasedLookupTable, CXXClasses, USR, Name, Loc, std::move(Availability), - Comment, Declaration, SubHeading, Kind, Access, IsFromSystemHeader); - if (Parent) - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - return Record; -} - -ClassTemplateRecord *APISet::addClassTemplate( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - Template Template, AccessControl Access, bool IsFromSystemHeader) { - auto *Record = - addTopLevelRecord(USRBasedLookupTable, ClassTemplates, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Template, Access, IsFromSystemHeader); - if (Parent) - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - return Record; -} - -ClassTemplateSpecializationRecord *APISet::addClassTemplateSpecialization( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - AccessControl Access, bool IsFromSystemHeader) { - auto *Record = - addTopLevelRecord(USRBasedLookupTable, ClassTemplateSpecializations, USR, - Name, Loc, std::move(Availability), Comment, - Declaration, SubHeading, Access, IsFromSystemHeader); - if (Parent) - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - return Record; -} - -ClassTemplatePartialSpecializationRecord * -APISet::addClassTemplatePartialSpecialization( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - Template Template, AccessControl Access, bool IsFromSystemHeader) { - auto *Record = addTopLevelRecord( - USRBasedLookupTable, ClassTemplatePartialSpecializations, USR, Name, Loc, - std::move(Availability), Comment, Declaration, SubHeading, Template, - Access, IsFromSystemHeader); - if (Parent) - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - return Record; -} - -GlobalVariableTemplateSpecializationRecord * -APISet::addGlobalVariableTemplateSpecialization( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, - GlobalVariableTemplateSpecializations, USR, Name, - Loc, std::move(Availability), Linkage, Comment, - Declaration, SubHeading, IsFromSystemHeader); -} - -GlobalVariableTemplatePartialSpecializationRecord * -APISet::addGlobalVariableTemplatePartialSpecialization( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, Template Template, - bool IsFromSystemHeader) { - return addTopLevelRecord( - USRBasedLookupTable, GlobalVariableTemplatePartialSpecializations, USR, - Name, Loc, std::move(Availability), Linkage, Comment, Declaration, - SubHeading, Template, IsFromSystemHeader); -} - -ConceptRecord *APISet::addConcept(StringRef Name, StringRef USR, - PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - Template Template, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, Concepts, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Template, IsFromSystemHeader); -} - -CXXMethodRecord *APISet::addCXXInstanceMethod( - APIRecord *CXXClassRecord, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, AccessControl Access, - bool IsFromSystemHeader) { - CXXMethodRecord *Record = - addTopLevelRecord(USRBasedLookupTable, CXXInstanceMethods, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Signature, Access, IsFromSystemHeader); - - Record->ParentInformation = APIRecord::HierarchyInformation( - CXXClassRecord->USR, CXXClassRecord->Name, CXXClassRecord->getKind(), - CXXClassRecord); - return Record; -} - -CXXMethodRecord *APISet::addCXXStaticMethod( - APIRecord *CXXClassRecord, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, AccessControl Access, - bool IsFromSystemHeader) { - CXXMethodRecord *Record = - addTopLevelRecord(USRBasedLookupTable, CXXStaticMethods, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Signature, Access, IsFromSystemHeader); - - Record->ParentInformation = APIRecord::HierarchyInformation( - CXXClassRecord->USR, CXXClassRecord->Name, CXXClassRecord->getKind(), - CXXClassRecord); - return Record; -} - -CXXMethodTemplateRecord *APISet::addCXXMethodTemplate( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, AccessControl Access, Template Template, - bool IsFromSystemHeader) { - auto *Record = addTopLevelRecord(USRBasedLookupTable, CXXMethodTemplates, USR, - Name, Loc, std::move(Availability), Comment, - Declaration, SubHeading, Signature, Access, - Template, IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - - return Record; -} - -CXXMethodTemplateSpecializationRecord *APISet::addCXXMethodTemplateSpec( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, AccessControl Access, - bool IsFromSystemHeader) { - - auto *Record = addTopLevelRecord( - USRBasedLookupTable, CXXMethodTemplateSpecializations, USR, Name, Loc, - std::move(Availability), Comment, Declaration, SubHeading, Signature, - Access, IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - - return Record; -} - -ObjCCategoryRecord *APISet::addObjCCategory( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - SymbolReference Interface, bool IsFromSystemHeader, - bool IsFromExternalModule) { - // Create the category record. - auto *Record = - addTopLevelRecord(USRBasedLookupTable, ObjCCategories, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Interface, IsFromSystemHeader); - - Record->IsFromExternalModule = IsFromExternalModule; - - auto It = ObjCInterfaces.find(Interface.USR); - if (It != ObjCInterfaces.end()) - It->second->Categories.push_back(Record); - - return Record; -} - -ObjCInterfaceRecord * -APISet::addObjCInterface(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - SymbolReference SuperClass, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, ObjCInterfaces, USR, Name, Loc, - std::move(Availability), Linkage, Comment, - Declaration, SubHeading, SuperClass, - IsFromSystemHeader); -} - -ObjCMethodRecord *APISet::addObjCMethod( - ObjCContainerRecord *Container, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, bool IsInstanceMethod, - bool IsFromSystemHeader) { - std::unique_ptr<ObjCMethodRecord> Record; - if (IsInstanceMethod) - Record = std::make_unique<ObjCInstanceMethodRecord>( - USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Signature, IsFromSystemHeader); - else - Record = std::make_unique<ObjCClassMethodRecord>( - USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Signature, IsFromSystemHeader); - - Record->ParentInformation = APIRecord::HierarchyInformation( - Container->USR, Container->Name, Container->getKind(), Container); - USRBasedLookupTable.insert({USR, Record.get()}); - return Container->Methods.emplace_back(std::move(Record)).get(); -} - -ObjCPropertyRecord *APISet::addObjCProperty( - ObjCContainerRecord *Container, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName, - StringRef SetterName, bool IsOptional, bool IsInstanceProperty, - bool IsFromSystemHeader) { - std::unique_ptr<ObjCPropertyRecord> Record; - if (IsInstanceProperty) - Record = std::make_unique<ObjCInstancePropertyRecord>( - USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Attributes, GetterName, SetterName, IsOptional, - IsFromSystemHeader); - else - Record = std::make_unique<ObjCClassPropertyRecord>( - USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Attributes, GetterName, SetterName, IsOptional, - IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Container->USR, Container->Name, Container->getKind(), Container); - USRBasedLookupTable.insert({USR, Record.get()}); - return Container->Properties.emplace_back(std::move(Record)).get(); -} - -ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable( - ObjCContainerRecord *Container, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - ObjCInstanceVariableRecord::AccessControl Access, bool IsFromSystemHeader) { - auto Record = std::make_unique<ObjCInstanceVariableRecord>( - USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading, - Access, IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Container->USR, Container->Name, Container->getKind(), Container); - USRBasedLookupTable.insert({USR, Record.get()}); - return Container->Ivars.emplace_back(std::move(Record)).get(); +APIRecord *APIRecord::castFromRecordContext(const RecordContext *Ctx) { + switch (Ctx->getKind()) { +#define RECORD_CONTEXT(CLASS, KIND) \ + case KIND: \ + return static_cast<CLASS *>(const_cast<RecordContext *>(Ctx)); +#include "clang/ExtractAPI/APIRecords.inc" + default: + return nullptr; + // llvm_unreachable("RecordContext derived class isn't propertly + // implemented"); + } } -ObjCProtocolRecord *APISet::addObjCProtocol(StringRef Name, StringRef USR, - PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, ObjCProtocols, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, IsFromSystemHeader); +RecordContext *APIRecord::castToRecordContext(const APIRecord *Record) { + if (!Record) + return nullptr; + switch (Record->getKind()) { +#define RECORD_CONTEXT(CLASS, KIND) \ + case KIND: \ + return static_cast<CLASS *>(const_cast<APIRecord *>(Record)); +#include "clang/ExtractAPI/APIRecords.inc" + default: + return nullptr; + // llvm_unreachable("RecordContext derived class isn't propertly + // implemented"); + } } -MacroDefinitionRecord * -APISet::addMacroDefinition(StringRef Name, StringRef USR, PresumedLoc Loc, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, Macros, USR, Name, Loc, - Declaration, SubHeading, IsFromSystemHeader); -} +void RecordContext::addToRecordChain(APIRecord *Record) const { + if (!First) { + First = Record; + Last = Record; + return; + } -TypedefRecord * -APISet::addTypedef(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - SymbolReference UnderlyingType, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, Typedefs, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, UnderlyingType, IsFromSystemHeader); + Last->NextInContext = Record; + Last = Record; } APIRecord *APISet::findRecordForUSR(StringRef USR) const { if (USR.empty()) return nullptr; - return USRBasedLookupTable.lookup(USR); -} - -StringRef APISet::recordUSR(const Decl *D) { - SmallString<128> USR; - index::generateUSRForDecl(D, USR); - return copyString(USR); -} + auto FindIt = USRBasedLookupTable.find(USR); + if (FindIt != USRBasedLookupTable.end()) + return FindIt->getSecond().get(); -StringRef APISet::recordUSRForMacro(StringRef Name, SourceLocation SL, - const SourceManager &SM) { - SmallString<128> USR; - index::generateUSRForMacro(Name, SL, SM, USR); - return copyString(USR); + return nullptr; } StringRef APISet::copyString(StringRef String) { @@ -528,15 +81,22 @@ StringRef APISet::copyString(StringRef String) { return {}; // No need to allocate memory and copy if the string has already been stored. - if (StringAllocator.identifyObject(String.data())) + if (Allocator.identifyObject(String.data())) return String; - void *Ptr = StringAllocator.Allocate(String.size(), 1); + void *Ptr = Allocator.Allocate(String.size(), 1); memcpy(Ptr, String.data(), String.size()); return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); } +SymbolReference APISet::createSymbolReference(StringRef Name, StringRef USR, + StringRef Source) { + return SymbolReference(copyString(Name), copyString(USR), copyString(Source)); +} + APIRecord::~APIRecord() {} +RecordRecord::~RecordRecord() {} +RecordFieldRecord::~RecordFieldRecord() {} ObjCContainerRecord::~ObjCContainerRecord() {} ObjCMethodRecord::~ObjCMethodRecord() {} ObjCPropertyRecord::~ObjCPropertyRecord() {} @@ -546,8 +106,10 @@ void GlobalFunctionRecord::anchor() {} void GlobalVariableRecord::anchor() {} void EnumConstantRecord::anchor() {} void EnumRecord::anchor() {} -void RecordFieldRecord::anchor() {} -void RecordRecord::anchor() {} +void StructFieldRecord::anchor() {} +void StructRecord::anchor() {} +void UnionFieldRecord::anchor() {} +void UnionRecord::anchor() {} void CXXFieldRecord::anchor() {} void CXXClassRecord::anchor() {} void CXXConstructorRecord::anchor() {} diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp index 22b98e0..0a24312 100644 --- a/clang/lib/ExtractAPI/DeclarationFragments.cpp +++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp @@ -57,23 +57,44 @@ void findTypeLocForBlockDecl(const clang::TypeSourceInfo *TSInfo, } // namespace -DeclarationFragments &DeclarationFragments::appendSpace() { +DeclarationFragments & +DeclarationFragments::appendUnduplicatedTextCharacter(char Character) { if (!Fragments.empty()) { Fragment &Last = Fragments.back(); if (Last.Kind == FragmentKind::Text) { // Merge the extra space into the last fragment if the last fragment is // also text. - if (Last.Spelling.back() != ' ') { // avoid extra trailing spaces. - Last.Spelling.push_back(' '); + if (Last.Spelling.back() != Character) { // avoid duplicates at end + Last.Spelling.push_back(Character); } } else { - append(" ", FragmentKind::Text); + append("", FragmentKind::Text); + Fragments.back().Spelling.push_back(Character); } } return *this; } +DeclarationFragments &DeclarationFragments::appendSpace() { + return appendUnduplicatedTextCharacter(' '); +} + +DeclarationFragments &DeclarationFragments::appendSemicolon() { + return appendUnduplicatedTextCharacter(';'); +} + +DeclarationFragments &DeclarationFragments::removeTrailingSemicolon() { + if (Fragments.empty()) + return *this; + + Fragment &Last = Fragments.back(); + if (Last.Kind == FragmentKind::Text && Last.Spelling.back() == ';') + Last.Spelling.pop_back(); + + return *this; +} + StringRef DeclarationFragments::getFragmentKindString( DeclarationFragments::FragmentKind Kind) { switch (Kind) { @@ -466,7 +487,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForNamespace( if (!Decl->isAnonymousNamespace()) Fragments.appendSpace().append( Decl->getName(), DeclarationFragments::FragmentKind::Identifier); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments @@ -508,7 +529,7 @@ DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) { return Fragments .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier) .append(std::move(After)) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -538,7 +559,7 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplate(const VarDecl *Var) { Fragments.append(std::move(ArgumentFragment)) .appendSpace() .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); return Fragments; } @@ -698,7 +719,7 @@ DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) { Fragments.append(DeclarationFragments::getExceptionSpecificationString( Func->getExceptionSpecType())); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForEnumConstant( @@ -727,7 +748,7 @@ DeclarationFragmentsBuilder::getFragmentsForEnum(const EnumDecl *EnumDecl) { getFragmentsForType(IntegerType, EnumDecl->getASTContext(), After)) .append(std::move(After)); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments @@ -743,7 +764,7 @@ DeclarationFragmentsBuilder::getFragmentsForField(const FieldDecl *Field) { .appendSpace() .append(Field->getName(), DeclarationFragments::FragmentKind::Identifier) .append(std::move(After)) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForRecordDecl( @@ -761,7 +782,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForRecordDecl( Fragments.appendSpace().append( Record->getName(), DeclarationFragments::FragmentKind::Identifier); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXClass( @@ -776,7 +797,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXClass( Fragments.appendSpace().append( Record->getName(), DeclarationFragments::FragmentKind::Identifier); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments @@ -806,7 +827,7 @@ DeclarationFragmentsBuilder::getFragmentsForSpecialCXXMethod( Fragments.append(DeclarationFragments::getExceptionSpecificationString( Method->getExceptionSpecType())); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXMethod( @@ -846,7 +867,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXMethod( Fragments.append(DeclarationFragments::getExceptionSpecificationString( Method->getExceptionSpecType())); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments @@ -877,7 +898,7 @@ DeclarationFragmentsBuilder::getFragmentsForConversionFunction( Fragments.appendSpace().append("const", DeclarationFragments::FragmentKind::Keyword); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments @@ -909,7 +930,7 @@ DeclarationFragmentsBuilder::getFragmentsForOverloadedOperator( Fragments.append(DeclarationFragments::getExceptionSpecificationString( Method->getExceptionSpecType())); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } // Get fragments for template parameters, e.g. T in tempalte<typename T> ... @@ -997,7 +1018,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForConcept( .appendSpace() .append(Concept->getName().str(), DeclarationFragments::FragmentKind::Identifier) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -1038,7 +1059,7 @@ DeclarationFragmentsBuilder::getFragmentsForClassTemplateSpecialization( getFragmentsForTemplateArguments(Decl->getTemplateArgs().asArray(), Decl->getASTContext(), std::nullopt)) .append(">", DeclarationFragments::FragmentKind::Text) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -1060,7 +1081,7 @@ DeclarationFragmentsBuilder::getFragmentsForClassTemplatePartialSpecialization( Decl->getTemplateArgs().asArray(), Decl->getASTContext(), Decl->getTemplateArgsAsWritten()->arguments())) .append(">", DeclarationFragments::FragmentKind::Text) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -1079,7 +1100,7 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplateSpecialization( getFragmentsForTemplateArguments(Decl->getTemplateArgs().asArray(), Decl->getASTContext(), std::nullopt)) .append(">", DeclarationFragments::FragmentKind::Text) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -1101,7 +1122,7 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplatePartialSpecialization( Decl->getTemplateArgs().asArray(), Decl->getASTContext(), Decl->getTemplateArgsAsWritten()->arguments())) .append(">", DeclarationFragments::FragmentKind::Text) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -1172,7 +1193,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCCategory( Fragments.append("@interface", DeclarationFragments::FragmentKind::Keyword) .appendSpace() - .append(Category->getClassInterface()->getName(), + .append(Interface->getName(), DeclarationFragments::FragmentKind::TypeIdentifier, InterfaceUSR, Interface) .append(" (", DeclarationFragments::FragmentKind::Text) @@ -1246,7 +1267,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCMethod( Fragments.append(getFragmentsForParam(Param)); } - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty( @@ -1347,7 +1368,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty( .append(Property->getName(), DeclarationFragments::FragmentKind::Identifier) .append(std::move(After)) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProtocol( @@ -1391,7 +1412,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForTypedef( .appendSpace() .append(Decl->getName(), DeclarationFragments::FragmentKind::Identifier); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } // Instantiate template for FunctionDecl. diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp index 275f49b..d633585 100644 --- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp +++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp @@ -30,6 +30,7 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/MultiplexConsumer.h" +#include "clang/Index/USRGeneration.h" #include "clang/InstallAPI/HeaderFile.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/PPCallbacks.h" @@ -39,6 +40,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" @@ -327,11 +329,12 @@ public: StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName(); PresumedLoc Loc = SM.getPresumedLoc(PM.MacroNameToken.getLocation()); - StringRef USR = - API.recordUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM); + SmallString<128> USR; + index::generateUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM, + USR); - API.addMacroDefinition( - Name, USR, Loc, + API.createRecord<extractapi::MacroDefinitionRecord>( + USR, Name, SymbolReference(), Loc, DeclarationFragmentsBuilder::getFragmentsForMacro(Name, PM.MD), DeclarationFragmentsBuilder::getSubHeadingForMacro(Name), SM.isInSystemHeader(PM.MacroNameToken.getLocation())); @@ -372,40 +375,57 @@ private: LocationFileChecker &LCF; }; +std::unique_ptr<llvm::raw_pwrite_stream> +createAdditionalSymbolGraphFile(CompilerInstance &CI, Twine BaseName) { + auto OutputDirectory = CI.getFrontendOpts().SymbolGraphOutputDir; + + SmallString<256> FileName; + llvm::sys::path::append(FileName, OutputDirectory, + BaseName + ".symbols.json"); + return CI.createOutputFile( + FileName, /*Binary*/ false, /*RemoveFileOnSignal*/ false, + /*UseTemporary*/ true, /*CreateMissingDirectories*/ true); +} + } // namespace -void ExtractAPIActionBase::ImplEndSourceFileAction() { - if (!OS) - return; +void ExtractAPIActionBase::ImplEndSourceFileAction(CompilerInstance &CI) { + SymbolGraphSerializerOption SerializationOptions; + SerializationOptions.Compact = !CI.getFrontendOpts().EmitPrettySymbolGraphs; + SerializationOptions.EmitSymbolLabelsForTesting = + CI.getFrontendOpts().EmitSymbolGraphSymbolLabelsForTesting; + + if (CI.getFrontendOpts().EmitExtensionSymbolGraphs) { + auto ConstructOutputFile = [&CI](Twine BaseName) { + return createAdditionalSymbolGraphFile(CI, BaseName); + }; + + SymbolGraphSerializer::serializeWithExtensionGraphs( + *OS, *API, IgnoresList, ConstructOutputFile, SerializationOptions); + } else { + SymbolGraphSerializer::serializeMainSymbolGraph(*OS, *API, IgnoresList, + SerializationOptions); + } - // Setup a SymbolGraphSerializer to write out collected API information in - // the Symbol Graph format. - // FIXME: Make the kind of APISerializer configurable. - SymbolGraphSerializer SGSerializer(*API, IgnoresList); - SGSerializer.serialize(*OS); + // Flush the stream and close the main output stream. OS.reset(); } -std::unique_ptr<raw_pwrite_stream> -ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) { - std::unique_ptr<raw_pwrite_stream> OS; - OS = CI.createDefaultOutputFile(/*Binary=*/false, InFile, - /*Extension=*/"json", - /*RemoveFileOnSignal=*/false); - if (!OS) - return nullptr; - return OS; -} - std::unique_ptr<ASTConsumer> ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { - OS = CreateOutputFile(CI, InFile); + auto ProductName = CI.getFrontendOpts().ProductName; + + if (CI.getFrontendOpts().SymbolGraphOutputDir.empty()) + OS = CI.createDefaultOutputFile(/*Binary*/ false, InFile, + /*Extension*/ "symbols.json", + /*RemoveFileOnSignal*/ false, + /*CreateMissingDirectories*/ true); + else + OS = createAdditionalSymbolGraphFile(CI, ProductName); if (!OS) return nullptr; - auto ProductName = CI.getFrontendOpts().ProductName; - // Now that we have enough information about the language options and the // target triple, let's create the APISet before anyone uses it. API = std::make_unique<APISet>( @@ -495,7 +515,9 @@ bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) { return true; } -void ExtractAPIAction::EndSourceFileAction() { ImplEndSourceFileAction(); } +void ExtractAPIAction::EndSourceFileAction() { + ImplEndSourceFileAction(getCompilerInstance()); +} std::unique_ptr<ASTConsumer> WrappingExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, @@ -506,11 +528,9 @@ WrappingExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, CreatedASTConsumer = true; - OS = CreateOutputFile(CI, InFile); - if (!OS) - return nullptr; - - auto ProductName = CI.getFrontendOpts().ProductName; + ProductName = CI.getFrontendOpts().ProductName; + auto InputFilename = llvm::sys::path::filename(InFile); + OS = createAdditionalSymbolGraphFile(CI, InputFilename); // Now that we have enough information about the language options and the // target triple, let's create the APISet before anyone uses it. @@ -552,32 +572,6 @@ void WrappingExtractAPIAction::EndSourceFileAction() { WrapperFrontendAction::EndSourceFileAction(); if (CreatedASTConsumer) { - ImplEndSourceFileAction(); + ImplEndSourceFileAction(getCompilerInstance()); } } - -std::unique_ptr<raw_pwrite_stream> -WrappingExtractAPIAction::CreateOutputFile(CompilerInstance &CI, - StringRef InFile) { - std::unique_ptr<raw_pwrite_stream> OS; - std::string OutputDir = CI.getFrontendOpts().SymbolGraphOutputDir; - - // The symbol graphs need to be generated as a side effect of regular - // compilation so the output should be dumped in the directory provided with - // the command line option. - llvm::SmallString<128> OutFilePath(OutputDir); - auto Seperator = llvm::sys::path::get_separator(); - auto Infilename = llvm::sys::path::filename(InFile); - OutFilePath.append({Seperator, Infilename}); - llvm::sys::path::replace_extension(OutFilePath, "json"); - // StringRef outputFilePathref = *OutFilePath; - - // don't use the default output file - OS = CI.createOutputFile(/*OutputPath=*/OutFilePath, /*Binary=*/false, - /*RemoveFileOnSignal=*/true, - /*UseTemporary=*/true, - /*CreateMissingDirectories=*/true); - if (!OS) - return nullptr; - return OS; -} diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp index 545860a..57f966c 100644 --- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp +++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp @@ -14,13 +14,17 @@ #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Version.h" +#include "clang/ExtractAPI/API.h" #include "clang/ExtractAPI/DeclarationFragments.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLFunctionalExtras.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Path.h" #include "llvm/Support/VersionTuple.h" +#include "llvm/Support/raw_ostream.h" +#include <iterator> #include <optional> #include <type_traits> @@ -33,26 +37,27 @@ namespace { /// Helper function to inject a JSON object \p Obj into another object \p Paren /// at position \p Key. -void serializeObject(Object &Paren, StringRef Key, std::optional<Object> Obj) { +void serializeObject(Object &Paren, StringRef Key, + std::optional<Object> &&Obj) { if (Obj) Paren[Key] = std::move(*Obj); } -/// Helper function to inject a StringRef \p String into an object \p Paren at -/// position \p Key -void serializeString(Object &Paren, StringRef Key, - std::optional<std::string> String) { - if (String) - Paren[Key] = std::move(*String); -} - /// Helper function to inject a JSON array \p Array into object \p Paren at /// position \p Key. -void serializeArray(Object &Paren, StringRef Key, std::optional<Array> Array) { +void serializeArray(Object &Paren, StringRef Key, + std::optional<Array> &&Array) { if (Array) Paren[Key] = std::move(*Array); } +/// Helper function to inject a JSON array composed of the values in \p C into +/// object \p Paren at position \p Key. +template <typename ContainerTy> +void serializeArray(Object &Paren, StringRef Key, ContainerTy &&C) { + Paren[Key] = Array(C); +} + /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version /// format. /// @@ -248,6 +253,7 @@ std::optional<Object> serializeDocComment(const DocComment &Comment) { return std::nullopt; Object DocComment; + Array LinesArray; for (const auto &CommentLine : Comment) { Object Line; @@ -256,7 +262,8 @@ std::optional<Object> serializeDocComment(const DocComment &Comment) { serializeSourceRange(CommentLine.Begin, CommentLine.End)); LinesArray.emplace_back(std::move(Line)); } - serializeArray(DocComment, "lines", LinesArray); + + serializeArray(DocComment, "lines", std::move(LinesArray)); return DocComment; } @@ -322,19 +329,14 @@ serializeDeclarationFragments(const DeclarationFragments &DF) { /// - \c subHeading : An array of declaration fragments that provides tags, /// and potentially more tokens (for example the \c +/- symbol for /// Objective-C methods). Can be used as sub-headings for documentation. -Object serializeNames(const APIRecord &Record) { +Object serializeNames(const APIRecord *Record) { Object Names; - if (auto *CategoryRecord = - dyn_cast_or_null<const ObjCCategoryRecord>(&Record)) - Names["title"] = - (CategoryRecord->Interface.Name + " (" + Record.Name + ")").str(); - else - Names["title"] = Record.Name; + Names["title"] = Record->Name; serializeArray(Names, "subHeading", - serializeDeclarationFragments(Record.SubHeading)); + serializeDeclarationFragments(Record->SubHeading)); DeclarationFragments NavigatorFragments; - NavigatorFragments.append(Record.Name, + NavigatorFragments.append(Record->Name, DeclarationFragments::FragmentKind::Identifier, /*PreciseIdentifier*/ ""); serializeArray(Names, "navigator", @@ -351,7 +353,8 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { Object Kind; switch (RK) { case APIRecord::RK_Unknown: - llvm_unreachable("Records should have an explicit kind"); + Kind["identifier"] = AddLangPrefix("unknown"); + Kind["displayName"] = "Unknown"; break; case APIRecord::RK_Namespace: Kind["identifier"] = AddLangPrefix("namespace"); @@ -484,10 +487,6 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { Kind["identifier"] = AddLangPrefix("class.extension"); Kind["displayName"] = "Class Extension"; break; - case APIRecord::RK_ObjCCategoryModule: - Kind["identifier"] = AddLangPrefix("module.extension"); - Kind["displayName"] = "Module Extension"; - break; case APIRecord::RK_ObjCProtocol: Kind["identifier"] = AddLangPrefix("protocol"); Kind["displayName"] = "Protocol"; @@ -500,6 +499,8 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { Kind["identifier"] = AddLangPrefix("typealias"); Kind["displayName"] = "Type Alias"; break; + default: + llvm_unreachable("API Record with uninstantiable kind"); } return Kind; @@ -514,12 +515,18 @@ Object serializeSymbolKind(const APIRecord &Record, Language Lang) { return serializeSymbolKind(Record.getKind(), Lang); } +/// Serialize the function signature field, as specified by the +/// Symbol Graph format. +/// +/// The Symbol Graph function signature property contains two arrays. +/// - The \c returns array is the declaration fragments of the return type; +/// - The \c parameters array contains names and declaration fragments of the +/// parameters. template <typename RecordTy> -std::optional<Object> -serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) { +void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { const auto &FS = Record.Signature; if (FS.empty()) - return std::nullopt; + return; Object Signature; serializeArray(Signature, "returns", @@ -537,63 +544,14 @@ serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) { if (!Parameters.empty()) Signature["parameters"] = std::move(Parameters); - return Signature; + serializeObject(Paren, "functionSignature", std::move(Signature)); } template <typename RecordTy> -std::optional<Object> -serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) { - return std::nullopt; -} - -/// Serialize the function signature field, as specified by the -/// Symbol Graph format. -/// -/// The Symbol Graph function signature property contains two arrays. -/// - The \c returns array is the declaration fragments of the return type; -/// - The \c parameters array contains names and declaration fragments of the -/// parameters. -/// -/// \returns \c std::nullopt if \p FS is empty, or an \c Object containing the -/// formatted function signature. -template <typename RecordTy> -void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { - serializeObject(Paren, "functionSignature", - serializeFunctionSignatureMixinImpl( - Record, has_function_signature<RecordTy>())); -} - -template <typename RecordTy> -std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record, - std::true_type) { - const auto &AccessControl = Record.Access; - std::string Access; - if (AccessControl.empty()) - return std::nullopt; - Access = AccessControl.getAccess(); - return Access; -} - -template <typename RecordTy> -std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record, - std::false_type) { - return std::nullopt; -} - -template <typename RecordTy> -void serializeAccessMixin(Object &Paren, const RecordTy &Record) { - auto accessLevel = serializeAccessMixinImpl(Record, has_access<RecordTy>()); - if (!accessLevel.has_value()) - accessLevel = "public"; - serializeString(Paren, "accessLevel", accessLevel); -} - -template <typename RecordTy> -std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record, - std::true_type) { +void serializeTemplateMixin(Object &Paren, const RecordTy &Record) { const auto &Template = Record.Templ; if (Template.empty()) - return std::nullopt; + return; Object Generics; Array GenericParameters; @@ -619,97 +577,66 @@ std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record, if (!GenericConstraints.empty()) Generics["constraints"] = std::move(GenericConstraints); - return Generics; -} - -template <typename RecordTy> -std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record, - std::false_type) { - return std::nullopt; + serializeObject(Paren, "swiftGenerics", Generics); } -template <typename RecordTy> -void serializeTemplateMixin(Object &Paren, const RecordTy &Record) { - serializeObject(Paren, "swiftGenerics", - serializeTemplateMixinImpl(Record, has_template<RecordTy>())); -} +Array generateParentContexts(const SmallVectorImpl<SymbolReference> &Parents, + Language Lang) { + Array ParentContexts; -struct PathComponent { - StringRef USR; - StringRef Name; - APIRecord::RecordKind Kind; + for (const auto &Parent : Parents) { + Object Elem; + Elem["usr"] = Parent.USR; + Elem["name"] = Parent.Name; + if (Parent.Record) + Elem["kind"] = + serializeSymbolKind(Parent.Record->getKind(), Lang)["identifier"]; + else + Elem["kind"] = + serializeSymbolKind(APIRecord::RK_Unknown, Lang)["identifier"]; + ParentContexts.emplace_back(std::move(Elem)); + } - PathComponent(StringRef USR, StringRef Name, APIRecord::RecordKind Kind) - : USR(USR), Name(Name), Kind(Kind) {} -}; + return ParentContexts; +} -template <typename RecordTy> -bool generatePathComponents( - const RecordTy &Record, const APISet &API, - function_ref<void(const PathComponent &)> ComponentTransformer) { - SmallVector<PathComponent, 4> ReverseComponenents; - ReverseComponenents.emplace_back(Record.USR, Record.Name, Record.getKind()); - const auto *CurrentParent = &Record.ParentInformation; - bool FailedToFindParent = false; - while (CurrentParent && !CurrentParent->empty()) { - PathComponent CurrentParentComponent(CurrentParent->ParentUSR, - CurrentParent->ParentName, - CurrentParent->ParentKind); - - auto *ParentRecord = CurrentParent->ParentRecord; - // Slow path if we don't have a direct reference to the ParentRecord - if (!ParentRecord) - ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR); - - // If the parent is a category extended from internal module then we need to - // pretend this belongs to the associated interface. - if (auto *CategoryRecord = - dyn_cast_or_null<ObjCCategoryRecord>(ParentRecord)) { - if (!CategoryRecord->IsFromExternalModule) { - ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR); - CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR, - CategoryRecord->Interface.Name, - APIRecord::RK_ObjCInterface); - } - } - - // The parent record doesn't exist which means the symbol shouldn't be - // treated as part of the current product. - if (!ParentRecord) { - FailedToFindParent = true; - break; - } - - ReverseComponenents.push_back(std::move(CurrentParentComponent)); - CurrentParent = &ParentRecord->ParentInformation; +/// Walk the records parent information in reverse to generate a hierarchy +/// suitable for serialization. +SmallVector<SymbolReference, 8> +generateHierarchyFromRecord(const APIRecord *Record) { + SmallVector<SymbolReference, 8> ReverseHierarchy; + for (const auto *Current = Record; Current != nullptr; + Current = Current->Parent.Record) + ReverseHierarchy.emplace_back(Current); + + return SmallVector<SymbolReference, 8>( + std::make_move_iterator(ReverseHierarchy.rbegin()), + std::make_move_iterator(ReverseHierarchy.rend())); +} + +SymbolReference getHierarchyReference(const APIRecord *Record, + const APISet &API) { + // If the parent is a category extended from internal module then we need to + // pretend this belongs to the associated interface. + if (auto *CategoryRecord = dyn_cast_or_null<ObjCCategoryRecord>(Record)) { + return CategoryRecord->Interface; + // FIXME: TODO generate path components correctly for categories extending + // an external module. } - for (const auto &PC : reverse(ReverseComponenents)) - ComponentTransformer(PC); - - return FailedToFindParent; + return SymbolReference(Record); } -Object serializeParentContext(const PathComponent &PC, Language Lang) { - Object ParentContextElem; - ParentContextElem["usr"] = PC.USR; - ParentContextElem["name"] = PC.Name; - ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"]; - return ParentContextElem; -} +} // namespace -template <typename RecordTy> -Array generateParentContexts(const RecordTy &Record, const APISet &API, - Language Lang) { - Array ParentContexts; - generatePathComponents( - Record, API, [Lang, &ParentContexts](const PathComponent &PC) { - ParentContexts.push_back(serializeParentContext(PC, Lang)); - }); +Object *ExtendedModule::addSymbol(Object &&Symbol) { + Symbols.emplace_back(std::move(Symbol)); + return Symbols.back().getAsObject(); +} - return ParentContexts; +void ExtendedModule::addRelationship(Object &&Relationship) { + Relationships.emplace_back(std::move(Relationship)); } -} // namespace /// Defines the format version emitted by SymbolGraphSerializer. const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3}; @@ -722,84 +649,44 @@ Object SymbolGraphSerializer::serializeMetadata() const { return Metadata; } -Object SymbolGraphSerializer::serializeModule() const { +Object +SymbolGraphSerializer::serializeModuleObject(StringRef ModuleName) const { Object Module; - // The user is expected to always pass `--product-name=` on the command line - // to populate this field. - Module["name"] = API.ProductName; + Module["name"] = ModuleName; serializeObject(Module, "platform", serializePlatform(API.getTarget())); return Module; } -bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const { - // Skip explicitly ignored symbols. - if (IgnoresList.shouldIgnore(Record.Name)) +bool SymbolGraphSerializer::shouldSkip(const APIRecord *Record) const { + if (!Record) return true; // Skip unconditionally unavailable symbols - if (Record.Availability.isUnconditionallyUnavailable()) + if (Record->Availability.isUnconditionallyUnavailable()) return true; // Filter out symbols prefixed with an underscored as they are understood to // be symbols clients should not use. - if (Record.Name.starts_with("_")) + if (Record->Name.starts_with("_")) + return true; + + // Skip explicitly ignored symbols. + if (IgnoresList.shouldIgnore(Record->Name)) return true; return false; } -template <typename RecordTy> -std::optional<Object> -SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const { - if (shouldSkip(Record)) - return std::nullopt; - - Object Obj; - serializeObject(Obj, "identifier", - serializeIdentifier(Record, API.getLanguage())); - serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage())); - serializeObject(Obj, "names", serializeNames(Record)); - serializeObject( - Obj, "location", - serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true)); - serializeArray(Obj, "availability", - serializeAvailability(Record.Availability)); - serializeObject(Obj, "docComment", serializeDocComment(Record.Comment)); - serializeArray(Obj, "declarationFragments", - serializeDeclarationFragments(Record.Declaration)); - SmallVector<StringRef, 4> PathComponentsNames; - // If this returns true it indicates that we couldn't find a symbol in the - // hierarchy. - if (generatePathComponents(Record, API, - [&PathComponentsNames](const PathComponent &PC) { - PathComponentsNames.push_back(PC.Name); - })) - return {}; - - serializeArray(Obj, "pathComponents", Array(PathComponentsNames)); +ExtendedModule &SymbolGraphSerializer::getModuleForCurrentSymbol() { + if (!ForceEmitToMainModule && ModuleForCurrentSymbol) + return *ModuleForCurrentSymbol; - serializeFunctionSignatureMixin(Obj, Record); - serializeAccessMixin(Obj, Record); - serializeTemplateMixin(Obj, Record); - - return Obj; + return MainModule; } -template <typename MemberTy> -void SymbolGraphSerializer::serializeMembers( - const APIRecord &Record, - const SmallVector<std::unique_ptr<MemberTy>> &Members) { - // Members should not be serialized if we aren't recursing. - if (!ShouldRecurse) - return; - for (const auto &Member : Members) { - auto MemberRecord = serializeAPIRecord(*Member); - if (!MemberRecord) - continue; - - Symbols.emplace_back(std::move(*MemberRecord)); - serializeRelationship(RelationshipKind::MemberOf, *Member, Record); - } +Array SymbolGraphSerializer::serializePathComponents( + const APIRecord *Record) const { + return Array(map_range(Hierarchy, [](auto Elt) { return Elt.Name; })); } StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { @@ -816,6 +703,33 @@ StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { llvm_unreachable("Unhandled relationship kind"); } +void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, + const SymbolReference &Source, + const SymbolReference &Target, + ExtendedModule &Into) { + Object Relationship; + SmallString<64> TestRelLabel; + if (EmitSymbolLabelsForTesting) { + llvm::raw_svector_ostream OS(TestRelLabel); + OS << SymbolGraphSerializer::getRelationshipString(Kind) << " $ " + << Source.USR << " $ "; + if (Target.USR.empty()) + OS << Target.Name; + else + OS << Target.USR; + Relationship["!testRelLabel"] = TestRelLabel; + } + Relationship["source"] = Source.USR; + Relationship["target"] = Target.USR; + Relationship["targetFallback"] = Target.Name; + Relationship["kind"] = SymbolGraphSerializer::getRelationshipString(Kind); + + if (ForceEmitToMainModule) + MainModule.addRelationship(std::move(Relationship)); + else + Into.addRelationship(std::move(Relationship)); +} + StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) { switch (Kind) { case ConstraintKind::Conformance: @@ -826,430 +740,324 @@ StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) { llvm_unreachable("Unhandled constraint kind"); } -void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, - SymbolReference Source, - SymbolReference Target) { - Object Relationship; - Relationship["source"] = Source.USR; - Relationship["target"] = Target.USR; - Relationship["targetFallback"] = Target.Name; - Relationship["kind"] = getRelationshipString(Kind); - - Relationships.emplace_back(std::move(Relationship)); -} +void SymbolGraphSerializer::serializeAPIRecord(const APIRecord *Record) { + Object Obj; -void SymbolGraphSerializer::visitNamespaceRecord( - const NamespaceRecord &Record) { - auto Namespace = serializeAPIRecord(Record); - if (!Namespace) - return; - Symbols.emplace_back(std::move(*Namespace)); - if (!Record.ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); -} + // If we need symbol labels for testing emit the USR as the value and the key + // starts with '!'' to ensure it ends up at the top of the object. + if (EmitSymbolLabelsForTesting) + Obj["!testLabel"] = Record->USR; -void SymbolGraphSerializer::visitGlobalFunctionRecord( - const GlobalFunctionRecord &Record) { - auto Obj = serializeAPIRecord(Record); - if (!Obj) - return; + serializeObject(Obj, "identifier", + serializeIdentifier(*Record, API.getLanguage())); + serializeObject(Obj, "kind", serializeSymbolKind(*Record, API.getLanguage())); + serializeObject(Obj, "names", serializeNames(Record)); + serializeObject( + Obj, "location", + serializeSourceLocation(Record->Location, /*IncludeFileURI=*/true)); + serializeArray(Obj, "availability", + serializeAvailability(Record->Availability)); + serializeObject(Obj, "docComment", serializeDocComment(Record->Comment)); + serializeArray(Obj, "declarationFragments", + serializeDeclarationFragments(Record->Declaration)); - Symbols.emplace_back(std::move(*Obj)); -} + Obj["pathComponents"] = serializePathComponents(Record); + Obj["accessLevel"] = Record->Access.getAccess(); -void SymbolGraphSerializer::visitGlobalVariableRecord( - const GlobalVariableRecord &Record) { - auto Obj = serializeAPIRecord(Record); - if (!Obj) - return; + ExtendedModule &Module = getModuleForCurrentSymbol(); + // If the hierarchy has at least one parent and child. + if (Hierarchy.size() >= 2) + serializeRelationship(MemberOf, Hierarchy.back(), + Hierarchy[Hierarchy.size() - 2], Module); - Symbols.emplace_back(std::move(*Obj)); + CurrentSymbol = Module.addSymbol(std::move(Obj)); } -void SymbolGraphSerializer::visitEnumRecord(const EnumRecord &Record) { - auto Enum = serializeAPIRecord(Record); - if (!Enum) - return; - - Symbols.emplace_back(std::move(*Enum)); - serializeMembers(Record, Record.Constants); +bool SymbolGraphSerializer::traverseAPIRecord(const APIRecord *Record) { + if (!Record) + return true; + if (shouldSkip(Record)) + return true; + Hierarchy.push_back(getHierarchyReference(Record, API)); + // Defer traversal mechanics to APISetVisitor base implementation + auto RetVal = Base::traverseAPIRecord(Record); + Hierarchy.pop_back(); + return RetVal; } -void SymbolGraphSerializer::visitRecordRecord(const RecordRecord &Record) { - auto SerializedRecord = serializeAPIRecord(Record); - if (!SerializedRecord) - return; - - Symbols.emplace_back(std::move(*SerializedRecord)); - serializeMembers(Record, Record.Fields); +bool SymbolGraphSerializer::visitAPIRecord(const APIRecord *Record) { + serializeAPIRecord(Record); + return true; } -void SymbolGraphSerializer::visitStaticFieldRecord( - const StaticFieldRecord &Record) { - auto StaticField = serializeAPIRecord(Record); - if (!StaticField) - return; - Symbols.emplace_back(std::move(*StaticField)); - serializeRelationship(RelationshipKind::MemberOf, Record, Record.Context); +bool SymbolGraphSerializer::visitGlobalFunctionRecord( + const GlobalFunctionRecord *Record) { + if (!CurrentSymbol) + return true; + + serializeFunctionSignatureMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord &Record) { - auto Class = serializeAPIRecord(Record); - if (!Class) - return; +bool SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*Class)); - for (const auto &Base : Record.Bases) - serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); - if (!Record.ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + for (const auto &Base : Record->Bases) + serializeRelationship(RelationshipKind::InheritsFrom, Record, Base, + getModuleForCurrentSymbol()); + return true; } -void SymbolGraphSerializer::visitClassTemplateRecord( - const ClassTemplateRecord &Record) { - auto Class = serializeAPIRecord(Record); - if (!Class) - return; +bool SymbolGraphSerializer::visitClassTemplateRecord( + const ClassTemplateRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*Class)); - for (const auto &Base : Record.Bases) - serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); - if (!Record.ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitClassTemplateSpecializationRecord( - const ClassTemplateSpecializationRecord &Record) { - auto Class = serializeAPIRecord(Record); - if (!Class) - return; - - Symbols.emplace_back(std::move(*Class)); +bool SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord( + const ClassTemplatePartialSpecializationRecord *Record) { + if (!CurrentSymbol) + return true; - for (const auto &Base : Record.Bases) - serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); - if (!Record.ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord( - const ClassTemplatePartialSpecializationRecord &Record) { - auto Class = serializeAPIRecord(Record); - if (!Class) - return; - - Symbols.emplace_back(std::move(*Class)); +bool SymbolGraphSerializer::visitCXXMethodRecord( + const CXXMethodRecord *Record) { + if (!CurrentSymbol) + return true; - for (const auto &Base : Record.Bases) - serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); - if (!Record.ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeFunctionSignatureMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitCXXInstanceMethodRecord( - const CXXInstanceMethodRecord &Record) { - auto InstanceMethod = serializeAPIRecord(Record); - if (!InstanceMethod) - return; +bool SymbolGraphSerializer::visitCXXMethodTemplateRecord( + const CXXMethodTemplateRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*InstanceMethod)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitCXXStaticMethodRecord( - const CXXStaticMethodRecord &Record) { - auto StaticMethod = serializeAPIRecord(Record); - if (!StaticMethod) - return; +bool SymbolGraphSerializer::visitCXXFieldTemplateRecord( + const CXXFieldTemplateRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*StaticMethod)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitMethodTemplateRecord( - const CXXMethodTemplateRecord &Record) { - if (!ShouldRecurse) - // Ignore child symbols - return; - auto MethodTemplate = serializeAPIRecord(Record); - if (!MethodTemplate) - return; - Symbols.emplace_back(std::move(*MethodTemplate)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); -} +bool SymbolGraphSerializer::visitConceptRecord(const ConceptRecord *Record) { + if (!CurrentSymbol) + return true; -void SymbolGraphSerializer::visitMethodTemplateSpecializationRecord( - const CXXMethodTemplateSpecializationRecord &Record) { - if (!ShouldRecurse) - // Ignore child symbols - return; - auto MethodTemplateSpecialization = serializeAPIRecord(Record); - if (!MethodTemplateSpecialization) - return; - Symbols.emplace_back(std::move(*MethodTemplateSpecialization)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitCXXFieldRecord(const CXXFieldRecord &Record) { - if (!ShouldRecurse) - return; - auto CXXField = serializeAPIRecord(Record); - if (!CXXField) - return; - Symbols.emplace_back(std::move(*CXXField)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); -} +bool SymbolGraphSerializer::visitGlobalVariableTemplateRecord( + const GlobalVariableTemplateRecord *Record) { + if (!CurrentSymbol) + return true; -void SymbolGraphSerializer::visitCXXFieldTemplateRecord( - const CXXFieldTemplateRecord &Record) { - if (!ShouldRecurse) - // Ignore child symbols - return; - auto CXXFieldTemplate = serializeAPIRecord(Record); - if (!CXXFieldTemplate) - return; - Symbols.emplace_back(std::move(*CXXFieldTemplate)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitConceptRecord(const ConceptRecord &Record) { - auto Concept = serializeAPIRecord(Record); - if (!Concept) - return; +bool SymbolGraphSerializer:: + visitGlobalVariableTemplatePartialSpecializationRecord( + const GlobalVariableTemplatePartialSpecializationRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*Concept)); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitGlobalVariableTemplateRecord( - const GlobalVariableTemplateRecord &Record) { - auto GlobalVariableTemplate = serializeAPIRecord(Record); - if (!GlobalVariableTemplate) - return; - Symbols.emplace_back(std::move(*GlobalVariableTemplate)); -} +bool SymbolGraphSerializer::visitGlobalFunctionTemplateRecord( + const GlobalFunctionTemplateRecord *Record) { + if (!CurrentSymbol) + return true; -void SymbolGraphSerializer::visitGlobalVariableTemplateSpecializationRecord( - const GlobalVariableTemplateSpecializationRecord &Record) { - auto GlobalVariableTemplateSpecialization = serializeAPIRecord(Record); - if (!GlobalVariableTemplateSpecialization) - return; - Symbols.emplace_back(std::move(*GlobalVariableTemplateSpecialization)); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer:: - visitGlobalVariableTemplatePartialSpecializationRecord( - const GlobalVariableTemplatePartialSpecializationRecord &Record) { - auto GlobalVariableTemplatePartialSpecialization = serializeAPIRecord(Record); - if (!GlobalVariableTemplatePartialSpecialization) - return; - Symbols.emplace_back(std::move(*GlobalVariableTemplatePartialSpecialization)); -} +bool SymbolGraphSerializer::visitObjCContainerRecord( + const ObjCContainerRecord *Record) { + if (!CurrentSymbol) + return true; -void SymbolGraphSerializer::visitGlobalFunctionTemplateRecord( - const GlobalFunctionTemplateRecord &Record) { - auto GlobalFunctionTemplate = serializeAPIRecord(Record); - if (!GlobalFunctionTemplate) - return; - Symbols.emplace_back(std::move(*GlobalFunctionTemplate)); -} + for (const auto &Protocol : Record->Protocols) + serializeRelationship(ConformsTo, Record, Protocol, + getModuleForCurrentSymbol()); -void SymbolGraphSerializer::visitGlobalFunctionTemplateSpecializationRecord( - const GlobalFunctionTemplateSpecializationRecord &Record) { - auto GlobalFunctionTemplateSpecialization = serializeAPIRecord(Record); - if (!GlobalFunctionTemplateSpecialization) - return; - Symbols.emplace_back(std::move(*GlobalFunctionTemplateSpecialization)); + return true; } -void SymbolGraphSerializer::visitObjCContainerRecord( - const ObjCContainerRecord &Record) { - auto ObjCContainer = serializeAPIRecord(Record); - if (!ObjCContainer) - return; +bool SymbolGraphSerializer::visitObjCInterfaceRecord( + const ObjCInterfaceRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*ObjCContainer)); - - serializeMembers(Record, Record.Ivars); - serializeMembers(Record, Record.Methods); - serializeMembers(Record, Record.Properties); - - for (const auto &Protocol : Record.Protocols) - // Record that Record conforms to Protocol. - serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); - - if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) { - if (!ObjCInterface->SuperClass.empty()) - // If Record is an Objective-C interface record and it has a super class, - // record that Record is inherited from SuperClass. - serializeRelationship(RelationshipKind::InheritsFrom, Record, - ObjCInterface->SuperClass); - - // Members of categories extending an interface are serialized as members of - // the interface. - for (const auto *Category : ObjCInterface->Categories) { - serializeMembers(Record, Category->Ivars); - serializeMembers(Record, Category->Methods); - serializeMembers(Record, Category->Properties); - - // Surface the protocols of the category to the interface. - for (const auto &Protocol : Category->Protocols) - serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); - } - } + if (!Record->SuperClass.empty()) + serializeRelationship(InheritsFrom, Record, Record->SuperClass, + getModuleForCurrentSymbol()); + return true; } -void SymbolGraphSerializer::visitObjCCategoryRecord( - const ObjCCategoryRecord &Record) { - if (!Record.IsFromExternalModule) - return; - - // Check if the current Category' parent has been visited before, if so skip. - if (!visitedCategories.contains(Record.Interface.Name)) { - visitedCategories.insert(Record.Interface.Name); - Object Obj; - serializeObject(Obj, "identifier", - serializeIdentifier(Record, API.getLanguage())); - serializeObject(Obj, "kind", - serializeSymbolKind(APIRecord::RK_ObjCCategoryModule, - API.getLanguage())); - Obj["accessLevel"] = "public"; - Symbols.emplace_back(std::move(Obj)); - } +bool SymbolGraphSerializer::traverseObjCCategoryRecord( + const ObjCCategoryRecord *Record) { + auto *CurrentModule = ModuleForCurrentSymbol; + if (Record->isExtendingExternalModule()) + ModuleForCurrentSymbol = &ExtendedModules[Record->Interface.Source]; - Object Relationship; - Relationship["source"] = Record.USR; - Relationship["target"] = Record.Interface.USR; - Relationship["targetFallback"] = Record.Interface.Name; - Relationship["kind"] = getRelationshipString(RelationshipKind::ExtensionTo); - Relationships.emplace_back(std::move(Relationship)); + if (!walkUpFromObjCCategoryRecord(Record)) + return false; - auto ObjCCategory = serializeAPIRecord(Record); + bool RetVal = traverseRecordContext(Record); + ModuleForCurrentSymbol = CurrentModule; + return RetVal; +} - if (!ObjCCategory) - return; +bool SymbolGraphSerializer::walkUpFromObjCCategoryRecord( + const ObjCCategoryRecord *Record) { + return visitObjCCategoryRecord(Record); +} - Symbols.emplace_back(std::move(*ObjCCategory)); - serializeMembers(Record, Record.Methods); - serializeMembers(Record, Record.Properties); +bool SymbolGraphSerializer::visitObjCCategoryRecord( + const ObjCCategoryRecord *Record) { + // If we need to create a record for the category in the future do so here, + // otherwise everything is set up to pretend that the category is in fact the + // interface it extends. + for (const auto &Protocol : Record->Protocols) + serializeRelationship(ConformsTo, Record->Interface, Protocol, + getModuleForCurrentSymbol()); - // Surface the protocols of the category to the interface. - for (const auto &Protocol : Record.Protocols) - serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); + return true; } -void SymbolGraphSerializer::visitMacroDefinitionRecord( - const MacroDefinitionRecord &Record) { - auto Macro = serializeAPIRecord(Record); +bool SymbolGraphSerializer::visitObjCMethodRecord( + const ObjCMethodRecord *Record) { + if (!CurrentSymbol) + return true; - if (!Macro) - return; + serializeFunctionSignatureMixin(*CurrentSymbol, *Record); + return true; +} - Symbols.emplace_back(std::move(*Macro)); +bool SymbolGraphSerializer::visitObjCInstanceVariableRecord( + const ObjCInstanceVariableRecord *Record) { + // FIXME: serialize ivar access control here. + return true; } -void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) { - switch (Record->getKind()) { - case APIRecord::RK_Unknown: - llvm_unreachable("Records should have a known kind!"); - case APIRecord::RK_GlobalFunction: - visitGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record)); - break; - case APIRecord::RK_GlobalVariable: - visitGlobalVariableRecord(*cast<GlobalVariableRecord>(Record)); - break; - case APIRecord::RK_Enum: - visitEnumRecord(*cast<EnumRecord>(Record)); - break; - case APIRecord::RK_Struct: - LLVM_FALLTHROUGH; - case APIRecord::RK_Union: - visitRecordRecord(*cast<RecordRecord>(Record)); - break; - case APIRecord::RK_StaticField: - visitStaticFieldRecord(*cast<StaticFieldRecord>(Record)); - break; - case APIRecord::RK_CXXClass: - visitCXXClassRecord(*cast<CXXClassRecord>(Record)); - break; - case APIRecord::RK_ObjCInterface: - visitObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record)); - break; - case APIRecord::RK_ObjCProtocol: - visitObjCContainerRecord(*cast<ObjCProtocolRecord>(Record)); - break; - case APIRecord::RK_ObjCCategory: - visitObjCCategoryRecord(*cast<ObjCCategoryRecord>(Record)); - break; - case APIRecord::RK_MacroDefinition: - visitMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record)); - break; - case APIRecord::RK_Typedef: - visitTypedefRecord(*cast<TypedefRecord>(Record)); - break; - default: - if (auto Obj = serializeAPIRecord(*Record)) { - Symbols.emplace_back(std::move(*Obj)); - auto &ParentInformation = Record->ParentInformation; - if (!ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, *Record, - *ParentInformation.ParentRecord); - } - break; - } +bool SymbolGraphSerializer::walkUpFromTypedefRecord( + const TypedefRecord *Record) { + // Short-circuit walking up the class hierarchy and handle creating typedef + // symbol objects manually as there are additional symbol dropping rules to + // respect. + return visitTypedefRecord(Record); } -void SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord &Record) { +bool SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord *Record) { // Typedefs of anonymous types have their entries unified with the underlying // type. - bool ShouldDrop = Record.UnderlyingType.Name.empty(); + bool ShouldDrop = Record->UnderlyingType.Name.empty(); // enums declared with `NS_OPTION` have a named enum and a named typedef, with // the same name - ShouldDrop |= (Record.UnderlyingType.Name == Record.Name); + ShouldDrop |= (Record->UnderlyingType.Name == Record->Name); if (ShouldDrop) - return; + return true; - auto Typedef = serializeAPIRecord(Record); - if (!Typedef) - return; + // Create the symbol record if the other symbol droppping rules permit it. + serializeAPIRecord(Record); + if (!CurrentSymbol) + return true; - (*Typedef)["type"] = Record.UnderlyingType.USR; + (*CurrentSymbol)["type"] = Record->UnderlyingType.USR; - Symbols.emplace_back(std::move(*Typedef)); + return true; } -Object SymbolGraphSerializer::serialize() { - traverseAPISet(); - return serializeCurrentGraph(); +void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) { + switch (Record->getKind()) { + // dispatch to the relevant walkUpFromMethod +#define CONCRETE_RECORD(CLASS, BASE, KIND) \ + case APIRecord::KIND: { \ + walkUpFrom##CLASS(static_cast<const CLASS *>(Record)); \ + break; \ + } +#include "clang/ExtractAPI/APIRecords.inc" + // otherwise fallback on the only behavior we can implement safely. + case APIRecord::RK_Unknown: + visitAPIRecord(Record); + break; + default: + llvm_unreachable("API Record with uninstantiable kind"); + } } -Object SymbolGraphSerializer::serializeCurrentGraph() { +Object SymbolGraphSerializer::serializeGraph(StringRef ModuleName, + ExtendedModule &&EM) { Object Root; serializeObject(Root, "metadata", serializeMetadata()); - serializeObject(Root, "module", serializeModule()); + serializeObject(Root, "module", serializeModuleObject(ModuleName)); - Root["symbols"] = std::move(Symbols); - Root["relationships"] = std::move(Relationships); + Root["symbols"] = std::move(EM.Symbols); + Root["relationships"] = std::move(EM.Relationships); return Root; } -void SymbolGraphSerializer::serialize(raw_ostream &os) { - Object root = serialize(); +void SymbolGraphSerializer::serializeGraphToStream( + raw_ostream &OS, SymbolGraphSerializerOption Options, StringRef ModuleName, + ExtendedModule &&EM) { + Object Root = serializeGraph(ModuleName, std::move(EM)); if (Options.Compact) - os << formatv("{0}", Value(std::move(root))) << "\n"; + OS << formatv("{0}", Value(std::move(Root))) << "\n"; else - os << formatv("{0:2}", Value(std::move(root))) << "\n"; + OS << formatv("{0:2}", Value(std::move(Root))) << "\n"; +} + +void SymbolGraphSerializer::serializeMainSymbolGraph( + raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList, + SymbolGraphSerializerOption Options) { + SymbolGraphSerializer Serializer(API, IgnoresList, + Options.EmitSymbolLabelsForTesting); + Serializer.traverseAPISet(); + Serializer.serializeGraphToStream(OS, Options, API.ProductName, + std::move(Serializer.MainModule)); + // FIXME: TODO handle extended modules here +} + +void SymbolGraphSerializer::serializeWithExtensionGraphs( + raw_ostream &MainOutput, const APISet &API, + const APIIgnoresList &IgnoresList, + llvm::function_ref<std::unique_ptr<llvm::raw_pwrite_stream>(Twine BaseName)> + CreateOutputStream, + SymbolGraphSerializerOption Options) { + SymbolGraphSerializer Serializer(API, IgnoresList, + Options.EmitSymbolLabelsForTesting); + Serializer.traverseAPISet(); + + Serializer.serializeGraphToStream(MainOutput, Options, API.ProductName, + std::move(Serializer.MainModule)); + + for (auto &ExtensionSGF : Serializer.ExtendedModules) { + if (auto ExtensionOS = + CreateOutputStream(ExtensionSGF.getKey() + "@" + API.ProductName)) + Serializer.serializeGraphToStream(*ExtensionOS, Options, + ExtensionSGF.getKey(), + std::move(ExtensionSGF.getValue())); + } } std::optional<Object> @@ -1262,14 +1070,20 @@ SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR, Object Root; APIIgnoresList EmptyIgnores; SymbolGraphSerializer Serializer(API, EmptyIgnores, - /*Options.Compact*/ {true}, - /*ShouldRecurse*/ false); + /*EmitSymbolLabelsForTesting*/ false, + /*ForceEmitToMainModule*/ true); + + // Set up serializer parent chain + Serializer.Hierarchy = generateHierarchyFromRecord(Record); + Serializer.serializeSingleRecord(Record); - serializeObject(Root, "symbolGraph", Serializer.serializeCurrentGraph()); + serializeObject(Root, "symbolGraph", + Serializer.serializeGraph(API.ProductName, + std::move(Serializer.MainModule))); Language Lang = API.getLanguage(); serializeArray(Root, "parentContexts", - generateParentContexts(*Record, API, Lang)); + generateParentContexts(Serializer.Hierarchy, Lang)); Array RelatedSymbols; @@ -1287,14 +1101,15 @@ SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR, Object RelatedSymbol; RelatedSymbol["usr"] = RelatedRecord->USR; RelatedSymbol["declarationLanguage"] = getLanguageName(Lang); - // TODO: once we record this properly let's serialize it right. - RelatedSymbol["accessLevel"] = "public"; + RelatedSymbol["accessLevel"] = RelatedRecord->Access.getAccess(); RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename(); RelatedSymbol["moduleName"] = API.ProductName; RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader; serializeArray(RelatedSymbol, "parentContexts", - generateParentContexts(*RelatedRecord, API, Lang)); + generateParentContexts( + generateHierarchyFromRecord(RelatedRecord), Lang)); + RelatedSymbols.push_back(std::move(RelatedSymbol)); } diff --git a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp b/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp index 3a5f62c..41e4e0c 100644 --- a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp +++ b/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h" +#include "clang/Basic/Module.h" #include "clang/Index/USRGeneration.h" using namespace clang; @@ -50,17 +51,20 @@ TypedefUnderlyingTypeResolver::getSymbolReferenceForType(QualType Type, SmallString<128> TypeUSR; const NamedDecl *TypeDecl = getUnderlyingTypeDecl(Type); const TypedefType *TypedefTy = Type->getAs<TypedefType>(); + StringRef OwningModuleName; if (TypeDecl) { if (!TypedefTy) TypeName = TypeDecl->getName().str(); clang::index::generateUSRForDecl(TypeDecl, TypeUSR); + if (auto *OwningModule = TypeDecl->getImportedOwningModule()) + OwningModuleName = OwningModule->Name; } else { clang::index::generateUSRForType(Type, Context, TypeUSR); } - return {API.copyString(TypeName), API.copyString(TypeUSR)}; + return API.createSymbolReference(TypeName, TypeUSR, OwningModuleName); } std::string TypedefUnderlyingTypeResolver::getUSRForType(QualType Type) const { diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index e41cf29..89e6c19 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -3581,7 +3581,7 @@ cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces, // We need to use lambda function here since there are two versions of // `cleanup`. auto Cleanup = [](const FormatStyle &Style, StringRef Code, - std::vector<tooling::Range> Ranges, + ArrayRef<tooling::Range> Ranges, StringRef FileName) -> tooling::Replacements { return cleanup(Style, Code, Ranges, FileName); }; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index a405a34..3e9988d 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -3889,6 +3889,8 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const { } } else if (ClosingParen) { for (auto *Tok = ClosingParen->Next; Tok; Tok = Tok->Next) { + if (Tok->is(TT_CtorInitializerColon)) + break; if (Tok->is(tok::arrow)) { Tok->setType(TT_TrailingReturnArrow); break; diff --git a/clang/lib/Frontend/PrecompiledPreamble.cpp b/clang/lib/Frontend/PrecompiledPreamble.cpp index 9b0ef30..fdf05c3 100644 --- a/clang/lib/Frontend/PrecompiledPreamble.cpp +++ b/clang/lib/Frontend/PrecompiledPreamble.cpp @@ -290,8 +290,7 @@ private: class PrecompilePreambleConsumer : public PCHGenerator { public: - PrecompilePreambleConsumer(PrecompilePreambleAction &Action, - const Preprocessor &PP, + PrecompilePreambleConsumer(PrecompilePreambleAction &Action, Preprocessor &PP, InMemoryModuleCache &ModuleCache, StringRef isysroot, std::shared_ptr<PCHBuffer> Buffer) diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 2446aee..f85f036 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -181,9 +181,13 @@ CreateFrontendAction(CompilerInstance &CI) { #endif // Wrap the base FE action in an extract api action to generate - // symbol graph as a biproduct of compilation ( enabled with - // --emit-symbol-graph option ) - if (!FEOpts.SymbolGraphOutputDir.empty()) { + // symbol graph as a biproduct of compilation (enabled with + // --emit-symbol-graph option) + if (FEOpts.EmitSymbolGraph) { + if (FEOpts.SymbolGraphOutputDir.empty()) { + CI.getDiagnostics().Report(diag::warn_missing_symbol_graph_dir); + CI.getFrontendOpts().SymbolGraphOutputDir = "."; + } CI.getCodeGenOpts().ClearASTBeforeBackend = false; Act = std::make_unique<WrappingExtractAPIAction>(std::move(Act)); } diff --git a/clang/lib/Headers/__stddef_unreachable.h b/clang/lib/Headers/__stddef_unreachable.h index 518580c..61df43e 100644 --- a/clang/lib/Headers/__stddef_unreachable.h +++ b/clang/lib/Headers/__stddef_unreachable.h @@ -7,6 +7,8 @@ *===-----------------------------------------------------------------------=== */ +#ifndef __cplusplus + /* * When -fbuiltin-headers-in-system-modules is set this is a non-modular header * and needs to behave as if it was textual. @@ -15,3 +17,5 @@ (__has_feature(modules) && !__building_module(_Builtin_stddef)) #define unreachable() __builtin_unreachable() #endif + +#endif diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 5c11528..cbd84dd 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2188,8 +2188,21 @@ void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD, assert(iter->getSecond() >= 0 && "Found a negative number of references to a VarDecl"); - if (iter->getSecond() != 0) - return; + if (int RefCnt = iter->getSecond(); RefCnt > 0) { + // Assume the given VarDecl is "used" if its ref count stored in + // `RefMinusAssignments` is positive, with one exception. + // + // For a C++ variable whose decl (with initializer) entirely consist the + // condition expression of a if/while/for construct, + // Clang creates a DeclRefExpr for the condition expression rather than a + // BinaryOperator of AssignmentOp. Thus, the C++ variable's ref + // count stored in `RefMinusAssignment` equals 1 when the variable is never + // used in the body of the if/while/for construct. + bool UnusedCXXCondDecl = VD->isCXXCondDecl() && (RefCnt == 1); + if (!UnusedCXXCondDecl) + return; + } + unsigned DiagID = isa<ParmVarDecl>(VD) ? diag::warn_unused_but_set_parameter : diag::warn_unused_but_set_variable; DiagReceiver(VD->getLocation(), PDiag(DiagID) << VD); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index f32ff39..068a2e4 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -18564,6 +18564,9 @@ DeclResult Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { return true; } + if (auto *VD = dyn_cast<VarDecl>(Dcl)) + VD->setCXXCondDecl(); + return Dcl; } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 80b4257..6b2eb24 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2751,7 +2751,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, QualType type = VD->getType().getNonReferenceType(); // This will eventually be translated into MemberExpr upon // the use of instantiated struct fields. - return BuildDeclRefExpr(VD, type, VK_PRValue, NameLoc); + return BuildDeclRefExpr(VD, type, VK_LValue, NameLoc); } } } diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 691857e..a033927 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -406,8 +406,8 @@ static void CheckForDuplicateLoopAttrs(Sema &S, ArrayRef<const Attr *> Attrs) { << *FirstItr; S.Diag((*FirstItr)->getLocation(), diag::note_previous_attribute); } - return; } + return; } static Attr *handleMSConstexprAttr(Sema &S, Stmt *St, const ParsedAttr &A, diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index a2b8cc1..d3def13 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2711,7 +2711,6 @@ SmallVector<unsigned> TemplateParamsReferencedInTemplateArgumentList( : TemplateParams(TemplateParams.begin(), TemplateParams.end()) {} bool VisitTemplateTypeParmType(TemplateTypeParmType *TTP) { - TTP->getIndex(); MarkAppeared(TTP->getDecl()); return true; } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 004859e..9a39e7d 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -6622,17 +6622,17 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { while (NumLocations--) { assert(Idx < Record.size() && "Invalid data, missing pragma diagnostic states"); - SourceLocation Loc = ReadSourceLocation(F, Record[Idx++]); - auto IDAndOffset = SourceMgr.getDecomposedLoc(Loc); - assert(IDAndOffset.first.isValid() && "invalid FileID for transition"); - assert(IDAndOffset.second == 0 && "not a start location for a FileID"); + FileID FID = ReadFileID(F, Record, Idx); + assert(FID.isValid() && "invalid FileID for transition"); + // FIXME: Remove this once we don't need the side-effects. + (void)SourceMgr.getSLocEntryOrNull(FID); unsigned Transitions = Record[Idx++]; // Note that we don't need to set up Parent/ParentOffset here, because // we won't be changing the diagnostic state within imported FileIDs // (other than perhaps appending to the main source file, which has no // parent). - auto &F = Diag.DiagStatesByLoc.Files[IDAndOffset.first]; + auto &F = Diag.DiagStatesByLoc.Files[FID]; F.StateTransitions.reserve(F.StateTransitions.size() + Transitions); for (unsigned I = 0; I != Transitions; ++I) { unsigned Offset = Record[Idx++]; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index a2668e6..ba6a8a5 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -3131,9 +3131,7 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag, continue; ++NumLocations; - SourceLocation Loc = Diag.SourceMgr->getComposedLoc(FileIDAndFile.first, 0); - assert(!Loc.isInvalid() && "start loc for valid FileID is invalid"); - AddSourceLocation(Loc, Record); + AddFileID(FileIDAndFile.first, Record); Record.push_back(FileIDAndFile.second.StateTransitions.size()); for (auto &StatePoint : FileIDAndFile.second.StateTransitions) { @@ -5109,69 +5107,7 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, for (auto *D : SemaRef.DeclsToCheckForDeferredDiags) DeclsToCheckForDeferredDiags.push_back(GetDeclRef(D)); - { - auto Abv = std::make_shared<BitCodeAbbrev>(); - Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE)); - Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); - Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); - UpdateVisibleAbbrev = Stream.EmitAbbrev(std::move(Abv)); - } - - RecordData DeclUpdatesOffsetsRecord; - - // Keep writing types, declarations, and declaration update records - // until we've emitted all of them. - Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/5); - DeclTypesBlockStartOffset = Stream.GetCurrentBitNo(); - WriteTypeAbbrevs(); - WriteDeclAbbrevs(); - do { - WriteDeclUpdatesBlocks(DeclUpdatesOffsetsRecord); - while (!DeclTypesToEmit.empty()) { - DeclOrType DOT = DeclTypesToEmit.front(); - DeclTypesToEmit.pop(); - if (DOT.isType()) - WriteType(DOT.getType()); - else - WriteDecl(Context, DOT.getDecl()); - } - } while (!DeclUpdates.empty()); - Stream.ExitBlock(); - - DoneWritingDeclsAndTypes = true; - - // These things can only be done once we've written out decls and types. - WriteTypeDeclOffsets(); - if (!DeclUpdatesOffsetsRecord.empty()) - Stream.EmitRecord(DECL_UPDATE_OFFSETS, DeclUpdatesOffsetsRecord); - - // Create a lexical update block containing all of the declarations in the - // translation unit that do not come from other AST files. - { - SmallVector<uint32_t, 128> NewGlobalKindDeclPairs; - for (const auto *D : TU->noload_decls()) { - if (!D->isFromASTFile()) { - NewGlobalKindDeclPairs.push_back(D->getKind()); - NewGlobalKindDeclPairs.push_back(GetDeclRef(D)); - } - } - - auto Abv = std::make_shared<BitCodeAbbrev>(); - Abv->Add(llvm::BitCodeAbbrevOp(TU_UPDATE_LEXICAL)); - Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); - unsigned TuUpdateLexicalAbbrev = Stream.EmitAbbrev(std::move(Abv)); - - RecordData::value_type Record[] = {TU_UPDATE_LEXICAL}; - Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record, - bytes(NewGlobalKindDeclPairs)); - } - - // And a visible updates block for the translation unit. - WriteDeclContextVisibleUpdate(TU); - - // If we have any extern "C" names, write out a visible update for them. - if (Context.ExternCContext) - WriteDeclContextVisibleUpdate(Context.ExternCContext); + WriteDeclAndTypes(Context); WriteFileDeclIDsMap(); WriteSourceManagerBlock(Context.getSourceManager(), PP); @@ -5257,10 +5193,6 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, if (!DeleteExprsToAnalyze.empty()) Stream.EmitRecord(DELETE_EXPRS_TO_ANALYZE, DeleteExprsToAnalyze); - // Write the visible updates to DeclContexts. - for (auto *DC : UpdatedDeclContexts) - WriteDeclContextVisibleUpdate(DC); - if (!WritingModule) { // Write the submodules that were imported, if any. struct ModuleInfo { @@ -5325,6 +5257,72 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, return backpatchSignature(); } +void ASTWriter::WriteDeclAndTypes(ASTContext &Context) { + // Keep writing types, declarations, and declaration update records + // until we've emitted all of them. + RecordData DeclUpdatesOffsetsRecord; + Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/5); + DeclTypesBlockStartOffset = Stream.GetCurrentBitNo(); + WriteTypeAbbrevs(); + WriteDeclAbbrevs(); + do { + WriteDeclUpdatesBlocks(DeclUpdatesOffsetsRecord); + while (!DeclTypesToEmit.empty()) { + DeclOrType DOT = DeclTypesToEmit.front(); + DeclTypesToEmit.pop(); + if (DOT.isType()) + WriteType(DOT.getType()); + else + WriteDecl(Context, DOT.getDecl()); + } + } while (!DeclUpdates.empty()); + Stream.ExitBlock(); + + DoneWritingDeclsAndTypes = true; + + // These things can only be done once we've written out decls and types. + WriteTypeDeclOffsets(); + if (!DeclUpdatesOffsetsRecord.empty()) + Stream.EmitRecord(DECL_UPDATE_OFFSETS, DeclUpdatesOffsetsRecord); + + const TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); + // Create a lexical update block containing all of the declarations in the + // translation unit that do not come from other AST files. + SmallVector<uint32_t, 128> NewGlobalKindDeclPairs; + for (const auto *D : TU->noload_decls()) { + if (!D->isFromASTFile()) { + NewGlobalKindDeclPairs.push_back(D->getKind()); + NewGlobalKindDeclPairs.push_back(GetDeclRef(D)); + } + } + + auto Abv = std::make_shared<llvm::BitCodeAbbrev>(); + Abv->Add(llvm::BitCodeAbbrevOp(TU_UPDATE_LEXICAL)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); + unsigned TuUpdateLexicalAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + RecordData::value_type Record[] = {TU_UPDATE_LEXICAL}; + Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record, + bytes(NewGlobalKindDeclPairs)); + + Abv = std::make_shared<llvm::BitCodeAbbrev>(); + Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); + UpdateVisibleAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + // And a visible updates block for the translation unit. + WriteDeclContextVisibleUpdate(TU); + + // If we have any extern "C" names, write out a visible update for them. + if (Context.ExternCContext) + WriteDeclContextVisibleUpdate(Context.ExternCContext); + + // Write the visible updates to DeclContexts. + for (auto *DC : UpdatedDeclContexts) + WriteDeclContextVisibleUpdate(DC); +} + void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { if (DeclUpdates.empty()) return; diff --git a/clang/lib/Serialization/GeneratePCH.cpp b/clang/lib/Serialization/GeneratePCH.cpp index f54db36..2fece29 100644 --- a/clang/lib/Serialization/GeneratePCH.cpp +++ b/clang/lib/Serialization/GeneratePCH.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTContext.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/SemaConsumer.h" #include "clang/Serialization/ASTReader.h" @@ -23,8 +24,8 @@ using namespace clang; PCHGenerator::PCHGenerator( - const Preprocessor &PP, InMemoryModuleCache &ModuleCache, - StringRef OutputFile, StringRef isysroot, std::shared_ptr<PCHBuffer> Buffer, + Preprocessor &PP, InMemoryModuleCache &ModuleCache, StringRef OutputFile, + StringRef isysroot, std::shared_ptr<PCHBuffer> Buffer, ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions, bool AllowASTWithErrors, bool IncludeTimestamps, bool BuildingImplicitModule, bool ShouldCacheASTInMemory, @@ -88,7 +89,7 @@ ASTDeserializationListener *PCHGenerator::GetASTDeserializationListener() { return &Writer; } -ReducedBMIGenerator::ReducedBMIGenerator(const Preprocessor &PP, +ReducedBMIGenerator::ReducedBMIGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache, StringRef OutputFile) : PCHGenerator( @@ -101,12 +102,24 @@ ReducedBMIGenerator::ReducedBMIGenerator(const Preprocessor &PP, Module *ReducedBMIGenerator::getEmittingModule(ASTContext &Ctx) { Module *M = Ctx.getCurrentNamedModule(); - assert(M->isNamedModuleUnit() && + assert(M && M->isNamedModuleUnit() && "ReducedBMIGenerator should only be used with C++20 Named modules."); return M; } void ReducedBMIGenerator::HandleTranslationUnit(ASTContext &Ctx) { + // We need to do this to make sure the size of reduced BMI not to be larger + // than full BMI. + // + // FIMXE: We'd better to wrap such options to a new class ASTWriterOptions + // since this is not about searching header really. + // FIXME2: We'd better to move the class writing full BMI with reduced BMI. + HeaderSearchOptions &HSOpts = + getPreprocessor().getHeaderSearchInfo().getHeaderSearchOpts(); + HSOpts.ModulesSkipDiagnosticOptions = true; + HSOpts.ModulesSkipHeaderSearchPaths = true; + HSOpts.ModulesSkipPragmaDiagnosticMappings = true; + PCHGenerator::HandleTranslationUnit(Ctx); if (!isComplete()) diff --git a/clang/lib/Tooling/CMakeLists.txt b/clang/lib/Tooling/CMakeLists.txt index 91e6cbdc..8b4ab0e 100644 --- a/clang/lib/Tooling/CMakeLists.txt +++ b/clang/lib/Tooling/CMakeLists.txt @@ -53,14 +53,16 @@ else() list(APPEND implicitDirs -I ${implicitDir}) endforeach() + setup_host_tool(clang-ast-dump CLANG_AST_DUMP clang_ast_dump_exe clang_ast_dump_target) + include(GetClangResourceDir) get_clang_resource_dir(resource_dir PREFIX ${LLVM_BINARY_DIR}) add_custom_command( COMMENT Generate ASTNodeAPI.json OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ASTNodeAPI.json - DEPENDS clang-ast-dump clang-resource-headers + DEPENDS ${clang_ast_dump_target} clang-resource-headers COMMAND - $<TARGET_FILE:clang-ast-dump> + ${clang_ast_dump_exe} # Skip this in debug mode because parsing AST.h is too slow --skip-processing=${skip_expensive_processing} -I ${resource_dir}/include |