From feb61342aaf3e5ef2bcc36b3d512eba600e03c9c Mon Sep 17 00:00:00 2001 From: cokeom Date: Fri, 14 Oct 2022 18:30:00 +0800 Subject: [PATCH] Implement -aux-info option. --- include/clang/AST/DeclBase.h | 2 + include/clang/AST/PrettyPrinter.h | 6 +- include/clang/Driver/Options.td | 7 ++ include/clang/Frontend/ASTConsumers.h | 3 + include/clang/Frontend/FrontendActions.h | 6 ++ include/clang/Frontend/FrontendOptions.h | 3 + lib/AST/DeclPrinter.cpp | 96 +++++++++++++++++++ lib/AST/TypePrinter.cpp | 23 +++-- lib/Driver/Driver.cpp | 6 +- lib/Driver/ToolChains/Clang.cpp | 7 ++ lib/Frontend/ASTConsumers.cpp | 34 +++++++ lib/Frontend/CompilerInvocation.cpp | 7 ++ lib/Frontend/FrontendActions.cpp | 13 +++ .../ExecuteCompilerInvocation.cpp | 2 + test/Frontend/print-function-prototype.c | 28 ++++++ 15 files changed, 230 insertions(+), 13 deletions(-) create mode 100644 test/Frontend/print-function-prototype.c diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 15eb29f7..a46b13e4 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -1164,6 +1164,8 @@ public: bool PrintInstantiation = false) const; void print(raw_ostream &Out, const PrintingPolicy &Policy, unsigned Indentation = 0, bool PrintInstantiation = false) const; + void printDeclPrototype(raw_ostream &Out, unsigned Indentation = 0, + bool PrintInstantiation = false) const; static void printGroup(Decl** Begin, unsigned NumDecls, raw_ostream &Out, const PrintingPolicy &Policy, unsigned Indentation = 0); diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h index 3baf2b2b..f147fd87 100644 --- a/include/clang/AST/PrettyPrinter.h +++ b/include/clang/AST/PrettyPrinter.h @@ -74,7 +74,8 @@ struct PrintingPolicy { MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true), MSVCFormatting(false), ConstantsAsWritten(false), SuppressImplicitBase(false), FullyQualifiedName(false), - PrintCanonicalTypes(false), PrintInjectedClassNameWithArguments(true) {} + PrintCanonicalTypes(false), PrintInjectedClassNameWithArguments(true), + PrintRestrict(true) {} /// Adjust this printing policy for cases where it's known that we're /// printing C++ code (for instance, if AST dumping reaches a C++-only @@ -273,6 +274,9 @@ struct PrintingPolicy { /// invalid C++ code. unsigned PrintInjectedClassNameWithArguments : 1; + /// Whether to print the keyword "restrict" in the function prototype. + unsigned PrintRestrict : 1; + /// Callbacks to use to allow the behavior of printing to be customized. const PrintingCallbacks *Callbacks = nullptr; }; diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 04521197..2126f0df 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -491,6 +491,13 @@ def convert : Separate<["-"], "convert">, Group, HelpText<"Generate big-endian/little-endian code">; +def aux_info : Separate<["-"], "aux-info">, + Flags<[NoXarchOption, CoreOption, CC1Option]>, + Group, + HelpText<"Output to the given filename prototyped declarations " + "for all functions declared and/or defined in a " + "translation unit, including those in header files">; + // Developer Driver Options def internal_Group : OptionGroup<"">, Flags<[HelpHidden]>; diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h index 98cfc7ca..ecd3c268 100644 --- a/include/clang/Frontend/ASTConsumers.h +++ b/include/clang/Frontend/ASTConsumers.h @@ -50,6 +50,9 @@ std::unique_ptr CreateASTDeclNodeLister(); // function declarations to stderr. std::unique_ptr CreateASTViewer(); +std::unique_ptr +CreateASTFunctionPrinter(std::unique_ptr Out); + } // end clang namespace #endif diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h index 25ca9598..d2b294a5 100644 --- a/include/clang/Frontend/FrontendActions.h +++ b/include/clang/Frontend/FrontendActions.h @@ -74,6 +74,12 @@ protected: StringRef InFile) override; }; +class ASTFunctionPrinterAction : public ASTFrontendAction { +protected: + std::unique_ptr CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; +}; + class GeneratePCHAction : public ASTFrontendAction { protected: std::unique_ptr CreateASTConsumer(CompilerInstance &CI, diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h index 223c1e05..3362a2fc 100644 --- a/include/clang/Frontend/FrontendOptions.h +++ b/include/clang/Frontend/FrontendOptions.h @@ -44,6 +44,9 @@ enum ActionKind { /// Parse ASTs and view them in Graphviz. ASTView, + /// Print function prototype. + ASTFunctionPrinter, + /// Dump the compiler configuration. DumpCompilerOptions, diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index ca64f8f6..a857466e 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -115,6 +115,7 @@ namespace { void prettyPrintAttributes(Decl *D); void prettyPrintPragmas(Decl *D); void printDeclType(QualType T, StringRef DeclName, bool Pack = false); + void printFunctionDeclPrototype(FunctionDecl *D); }; } @@ -135,6 +136,14 @@ void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context, print(Out, Context, Context.getPrintingPolicy(), OmitTemplateKW); } +void Decl::printDeclPrototype(raw_ostream &Out, unsigned Indentation, + bool PrintInstantiation) const { + DeclPrinter Printer(Out, getASTContext().getPrintingPolicy(), getASTContext(), + Indentation, PrintInstantiation); + auto *FD = const_cast(dyn_cast(this)); + Printer.printFunctionDeclPrototype(FD); +} + void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context, const PrintingPolicy &Policy, bool OmitTemplateKW) const { @@ -784,6 +793,93 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { } } +void DeclPrinter::printFunctionDeclPrototype(FunctionDecl *D) { + if (!Policy.SuppressSpecifiers) { + switch (D->getStorageClass()) { + case SC_None: + case SC_Extern: + case SC_PrivateExtern: + Out << "extern "; + break; + case SC_Static: + Out << "static "; + break; + case SC_Auto: + case SC_Register: + llvm_unreachable("invalid for functions"); + } + } + + PrintingPolicy SubPolicy(Policy); + SubPolicy.SuppressSpecifiers = false; + SubPolicy.PrintRestrict = false; + std::string Proto; + + /// Print the function name. + if (Policy.FullyQualifiedName) { + Proto += D->getQualifiedNameAsString(); + } else { + llvm::raw_string_ostream OS(Proto); + if (!Policy.SuppressScope) { + if (const NestedNameSpecifier *NS = D->getQualifier()) { + NS->print(OS, Policy); + } + } + D->getNameInfo().printName(OS, Policy); + } + + QualType Ty = D->getType(); + while (const ParenType *PT = dyn_cast(Ty)) { + Proto = '(' + Proto + ')'; + Ty = PT->getInnerType(); + } + if (const FunctionType *AFT = Ty->getAs()) { + const FunctionProtoType *FT = nullptr; + if (D->hasWrittenPrototype()) + FT = dyn_cast(AFT); + + Proto += "("; + + /// Print function parameters. + if (FT) { + llvm::raw_string_ostream POut(Proto); + for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) { + if (i) + POut << ", "; + ParmVarDecl *PVD = D->getParamDecl(i); + QualType T = PVD->getTypeSourceInfo() + ? PVD->getTypeSourceInfo()->getType() + : PVD->getASTContext().getUnqualifiedObjCPointerType( + PVD->getType()); + T.print(POut, SubPolicy, "", Indentation); + } + + if (FT->isVariadic()) { + if (D->getNumParams()) + POut << ", "; + POut << "..."; + } else if (!D->getNumParams()) { + POut << "void"; + } + } else if (D->doesThisDeclarationHaveABody() && !D->hasPrototype()) { + for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) { + if (i) + Proto += ", "; + Proto += D->getParamDecl(i)->getNameAsString(); + } + if (!D->getNumParams()) { + Proto += "void"; + } + } + Proto += ")"; + + /// Print the function return type. + AFT->getReturnType().print(Out, Policy, Proto); + } else { + Ty.print(Out, Policy, Proto); + } +} + void DeclPrinter::VisitFriendDecl(FriendDecl *D) { if (TypeSourceInfo *TSI = D->getFriendType()) { unsigned NumTPLists = D->getFriendTypeNumTemplateParameterLists(); diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 25d7874b..37d116ca 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -139,7 +139,7 @@ namespace { } // namespace static void AppendTypeQualList(raw_ostream &OS, unsigned TypeQuals, - bool HasRestrictKeyword) { + bool HasRestrictKeyword, bool PrintRestrict) { bool appendSpace = false; if (TypeQuals & Qualifiers::Const) { OS << "const"; @@ -151,11 +151,13 @@ static void AppendTypeQualList(raw_ostream &OS, unsigned TypeQuals, appendSpace = true; } if (TypeQuals & Qualifiers::Restrict) { - if (appendSpace) OS << ' '; - if (HasRestrictKeyword) { - OS << "restrict"; - } else { - OS << "__restrict"; + if (PrintRestrict) { + if (appendSpace) OS << ' '; + if (HasRestrictKeyword) { + OS << "restrict"; + } else { + OS << "__restrict"; + } } } } @@ -506,8 +508,8 @@ void TypePrinter::printConstantArrayAfter(const ConstantArrayType *T, raw_ostream &OS) { OS << '['; if (T->getIndexTypeQualifiers().hasQualifiers()) { - AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers(), - Policy.Restrict); + AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers(), Policy.Restrict, + Policy.PrintRestrict); OS << ' '; } @@ -542,7 +544,8 @@ void TypePrinter::printVariableArrayAfter(const VariableArrayType *T, raw_ostream &OS) { OS << '['; if (T->getIndexTypeQualifiers().hasQualifiers()) { - AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers(), Policy.Restrict); + AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers(), Policy.Restrict, + Policy.PrintRestrict); OS << ' '; } @@ -2149,7 +2152,7 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy, unsigned quals = getCVRQualifiers(); if (quals) { - AppendTypeQualList(OS, quals, Policy.Restrict); + AppendTypeQualList(OS, quals, Policy.Restrict, Policy.PrintRestrict); addSpace = true; } if (hasUnaligned()) { diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 95c0e256..ce677965 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -309,7 +309,8 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, (PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) || (PhaseArg = DAL.getLastArg(options::OPT__migrate)) || (PhaseArg = DAL.getLastArg(options::OPT__analyze)) || - (PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) { + (PhaseArg = DAL.getLastArg(options::OPT_emit_ast)) || + (PhaseArg = DAL.getLastArg(options::OPT_aux_info))) { FinalPhase = phases::Compile; // -S only runs up to the backend. @@ -3851,7 +3852,8 @@ Action *Driver::ConstructPhaseAction( return C.MakeAction(Input, OutputTy); } case phases::Compile: { - if (Args.hasArg(options::OPT_fsyntax_only)) + if (Args.hasArg(options::OPT_fsyntax_only) || + Args.hasArg(options::OPT_aux_info)) return C.MakeAction(Input, types::TY_Nothing); if (Args.hasArg(options::OPT_rewrite_objc)) return C.MakeAction(Input, types::TY_RewrittenObjC); diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index 706d0431..e7946529 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -6258,6 +6258,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + if (Arg *A = Args.getLastArg(options::OPT_aux_info)) { + if (Input.getType() == types::TY_C) { + CmdArgs.push_back("-aux-info"); + CmdArgs.push_back(A->getValue()); + } + } + // With -save-temps, we want to save the unoptimized bitcode output from the // CompileJobAction, use -disable-llvm-passes to get pristine IR generated // by the frontend. diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index a73cc887..48f999ab 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -212,3 +212,37 @@ void ASTViewer::HandleTopLevelSingleDecl(Decl *D) { std::unique_ptr clang::CreateASTViewer() { return std::make_unique(); } + +//===----------------------------------------------------------------------===// +/// ASTFunctionPrototype - AST FunctionPrototype print +namespace { + class ASTFunctionPrinter : public ASTConsumer { + private: + llvm::raw_fd_ostream &Out; + std::unique_ptr OwnedOut; + public: + ASTFunctionPrinter(std::unique_ptr Out) + : Out(Out ? *Out : llvm::outs()), OwnedOut(std::move(Out)) {} + + bool HandleTopLevelDecl(DeclGroupRef D) override { + for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) + HandleTopLevelSingleDecl(*I); + return true; + } + + void HandleTopLevelSingleDecl(Decl *D); + }; +} // namespace + +void ASTFunctionPrinter::HandleTopLevelSingleDecl(Decl *D) { + if (isa(D)) { + D->printDeclPrototype(Out); + Out << ";"; + Out << '\n'; + } +} + +std::unique_ptr +clang::CreateASTFunctionPrinter(std::unique_ptr Out) { + return std::make_unique(std::move(Out)); +} \ No newline at end of file diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 5c5cf461..9665b4ed 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1574,6 +1574,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ProgramAction = frontend::ASTPrint; break; case OPT_ast_view: Opts.ProgramAction = frontend::ASTView; break; + case OPT_aux_info: + Opts.ProgramAction = frontend::ASTFunctionPrinter; break; case OPT_compiler_options_dump: Opts.ProgramAction = frontend::DumpCompilerOptions; break; case OPT_dump_raw_tokens: @@ -2711,6 +2713,7 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { case frontend::ASTDump: case frontend::ASTPrint: case frontend::ASTView: + case frontend::ASTFunctionPrinter: case frontend::EmitAssembly: case frontend::EmitBC: case frontend::EmitHTML: @@ -2971,6 +2974,10 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, FixupInvocation(Res, Diags, Args, DashX); + if (Arg *A = Args.getLastArg(OPT_aux_info)) { + Res.getFrontendOpts().OutputFile = A->getValue(); + } + return Success; } diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 060cec23..1d0044c8 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -93,6 +93,19 @@ ASTViewAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { return CreateASTViewer(); } +std::unique_ptr +ASTFunctionPrinterAction::CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { + StringRef OutputFileName = CI.getFrontendOpts().OutputFile; + std::unique_ptr OutFile; + if (!OutputFileName.empty() && OutputFileName != "-") { + std::error_code EC; + OutFile.reset(new llvm::raw_fd_ostream(OutputFileName.str(), EC, + llvm::sys::fs::CD_CreateAlways)); + } + return CreateASTFunctionPrinter(std::move(OutFile)); +} + std::unique_ptr GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { std::string Sysroot; diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp index ac64e170..63a6b403 100644 --- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -46,6 +46,8 @@ CreateFrontendBaseAction(CompilerInstance &CI) { case ASTDump: return std::make_unique(); case ASTPrint: return std::make_unique(); case ASTView: return std::make_unique(); + case ASTFunctionPrinter: + return std::make_unique(); case DumpCompilerOptions: return std::make_unique(); case DumpRawTokens: return std::make_unique(); diff --git a/test/Frontend/print-function-prototype.c b/test/Frontend/print-function-prototype.c new file mode 100644 index 00000000..5abc7550 --- /dev/null +++ b/test/Frontend/print-function-prototype.c @@ -0,0 +1,28 @@ +// Test that -aux-info prints correct function prototypes. +// RUN: %clang %s -aux-info %t 2>&1 \ +// RUN: | FileCheck -input-file=%t %s +// CHECK: extern void function1(int, const int, float); +// CHECK: extern int function2(int, int); +// CHECK: extern void function3(int, double, float); +// CHECK: static void function4(void); +// CHECK: extern int function5(volatile int *); +// CHECK: extern int function6(int *); +// CHECK: extern const int function7(void); +// CHECK: extern volatile float function8(void); +// CHECK: extern int main(void); +// CHECK: extern void function1(int, const int, float); + +void function1(int, const int, float); +int function2(int a, int b) { return a + b; } +void function3(int a, double b, float c) {} +static void function4() {} +inline int function5(volatile int *j); +int function6(int *a) { return 0; } +const int function7() { return 1; } +volatile float function8() { return 0.; } +int main() { + function1(1, 1, 0.0); + function2(1, 1); + return 0; +} +void function1(int a, const int b, float c) {} \ No newline at end of file -- 2.25.1