Index: include/clang-c/Index.h =================================================================== --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -32,7 +32,7 @@ * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable. */ #define CINDEX_VERSION_MAJOR 0 -#define CINDEX_VERSION_MINOR 46 +#define CINDEX_VERSION_MINOR 47 #define CINDEX_VERSION_ENCODE(major, minor) ( \ ((major) * 10000) \ @@ -4091,6 +4091,87 @@ unsigned pieceIndex, unsigned options); +/** + * \brief Opaque pointer representing a policy that controls pretty printing + * for \c clang_getCursorPrettyPrinted. + */ +typedef void *CXPrintingPolicy; + +/** + * \brief Properties for the printing policy. + * + * See \c clang::PrintingPolicy for more information. + */ +enum CXPrintingPolicyProperty { + CXPrintingPolicy_Indentation, + CXPrintingPolicy_SuppressSpecifiers, + CXPrintingPolicy_SuppressTagKeyword, + CXPrintingPolicy_IncludeTagDefinition, + CXPrintingPolicy_SuppressScope, + CXPrintingPolicy_SuppressUnwrittenScope, + CXPrintingPolicy_SuppressInitializers, + CXPrintingPolicy_ConstantArraySizeAsWritten, + CXPrintingPolicy_AnonymousTagLocations, + CXPrintingPolicy_SuppressStrongLifetime, + CXPrintingPolicy_SuppressLifetimeQualifiers, + CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors, + CXPrintingPolicy_Bool, + CXPrintingPolicy_Restrict, + CXPrintingPolicy_Alignof, + CXPrintingPolicy_UnderscoreAlignof, + CXPrintingPolicy_UseVoidForZeroParams, + CXPrintingPolicy_TerseOutput, + CXPrintingPolicy_PolishForDeclaration, + CXPrintingPolicy_Half, + CXPrintingPolicy_MSWChar, + CXPrintingPolicy_IncludeNewlines, + CXPrintingPolicy_MSVCFormatting, + CXPrintingPolicy_ConstantsAsWritten, + CXPrintingPolicy_SuppressImplicitBase, + CXPrintingPolicy_FullyQualifiedName +}; + +/** + * \brief Get a property value for the given printing policy. + */ +unsigned +clang_PrintingPolicy_getProperty(CXPrintingPolicy Policy, + enum CXPrintingPolicyProperty Property); + +/** + * \brief Set a property value for the given printing policy. + */ +void clang_PrintingPolicy_setProperty(CXPrintingPolicy Policy, + enum CXPrintingPolicyProperty Property, + unsigned Value); + +/** + * \brief Retrieve the default policy for the cursor. + * + * The policy should be released after use with \c + * clang_PrintingPolicy_dispose. + */ +CINDEX_LINKAGE CXPrintingPolicy clang_getCursorPrintingPolicy(CXCursor); + +/** + * \brief Release a printing policy. + */ +CINDEX_LINKAGE void clang_PrintingPolicy_dispose(CXPrintingPolicy Policy); + +/** + * \brief Pretty print declarations. + * + * \param Cursor The cursor representing a declaration. + * + * \param Policy The policy to control the entities being printed. If + * NULL, a default policy is used. + * + * \returns The pretty printed declaration or the empty string for + * other cursors. + */ +CINDEX_LINKAGE CXString clang_getCursorPrettyPrinted(CXCursor Cursor, + CXPrintingPolicy Policy); + /** * \brief Retrieve the display name for the entity referenced by this cursor. * Index: test/Index/print-display-names.cpp =================================================================== --- test/Index/print-display-names.cpp +++ test/Index/print-display-names.cpp @@ -12,9 +12,20 @@ template<> void g(ClassTmpl); -// RUN: c-index-test -test-load-source all-display %s | FileCheck %s -// CHECK: print-display-names.cpp:2:7: ClassTemplate=ClassTmpl:2:7 -// CHECK: print-display-names.cpp:6:16: ClassDecl=ClassTmpl:6:16 (Definition) -// CHECK: print-display-names.cpp:8:6: FunctionDecl=f(ClassTmpl):8:6 -// CHECK: print-display-names.cpp:11:6: FunctionTemplate=g(ClassTmpl):11:6 -// CHECK: print-display-names.cpp:13:17: FunctionDecl=g<>(ClassTmpl):13:17 [Specialization of g:11:6] +// RUN: c-index-test -test-load-source all-display %s | FileCheck %s --check-prefix=DISPLAY_NAME +// DISPLAY_NAME: print-display-names.cpp:2:7: ClassTemplate=ClassTmpl:2:7 +// DISPLAY_NAME: print-display-names.cpp:6:16: ClassDecl=ClassTmpl:6:16 (Definition) +// DISPLAY_NAME: print-display-names.cpp:8:6: FunctionDecl=f(ClassTmpl):8:6 +// DISPLAY_NAME: print-display-names.cpp:11:6: FunctionTemplate=g(ClassTmpl):11:6 +// DISPLAY_NAME: print-display-names.cpp:13:17: FunctionDecl=g<>(ClassTmpl):13:17 [Specialization of g:11:6] + +// RUN: env CINDEXTEST_PRINTINGPOLICY_TERSEOUTPUT=1 c-index-test -test-load-source all-pretty %s | FileCheck %s --check-prefix=PRETTY +// PRETTY: print-display-names.cpp:2:7: ClassTemplate=template class ClassTmpl {}:2:7 (Definition) Extent=[1:1 - 2:20] +// PRETTY: print-display-names.cpp:4:13: TypedefDecl=typedef int Integer:4:13 (Definition) Extent=[4:1 - 4:20] +// PRETTY: print-display-names.cpp:6:16: ClassDecl=template<> class ClassTmpl {}:6:16 (Definition) [Specialization of ClassTmpl:2:7] Extent=[6:1 - 6:43] +// PRETTY: print-display-names.cpp:8:6: FunctionDecl=void f(ClassTmpl p):8:6 Extent=[8:1 - 8:36] +// PRETTY: print-display-names.cpp:8:34: ParmDecl=ClassTmpl p:8:34 (Definition) Extent=[8:8 - 8:35] +// PRETTY: print-display-names.cpp:11:6: FunctionTemplate=template void g(ClassTmpl):11:6 Extent=[10:1 - 11:24] +// PRETTY: print-display-names.cpp:11:23: ParmDecl=ClassTmpl:11:23 (Definition) Extent=[11:8 - 11:23] +// PRETTY: print-display-names.cpp:13:17: FunctionDecl=template<> void g(ClassTmpl):13:17 [Specialization of g:11:6] [Template arg 0: kind: 1, type: int] Extent=[13:1 - 13:44] +// PRETTY: print-display-names.cpp:13:43: ParmDecl=ClassTmpl:13:43 (Definition) Extent=[13:24 - 13:43] Index: tools/c-index-test/c-index-test.c =================================================================== --- tools/c-index-test/c-index-test.c +++ tools/c-index-test/c-index-test.c @@ -86,6 +86,68 @@ return options; } +static void ModifyPrintingPolicyAccordingToEnv(CXPrintingPolicy Policy) { + struct Mapping { + const char *name; + enum CXPrintingPolicyProperty property; + } mappings[] = { + {"CINDEXTEST_PRINTINGPOLICY_INDENTATION", CXPrintingPolicy_Indentation}, + {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSPECIFIERS", + CXPrintingPolicy_SuppressSpecifiers}, + {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSTAGKEYWORD", + CXPrintingPolicy_SuppressTagKeyword}, + {"CINDEXTEST_PRINTINGPOLICY_INCLUDETAGDEFINITION", + CXPrintingPolicy_IncludeTagDefinition}, + {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSCOPE", + CXPrintingPolicy_SuppressScope}, + {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSUNWRITTENSCOPE", + CXPrintingPolicy_SuppressUnwrittenScope}, + {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSINITIALIZERS", + CXPrintingPolicy_SuppressInitializers}, + {"CINDEXTEST_PRINTINGPOLICY_CONSTANTARRAYSIZEASWRITTEN", + CXPrintingPolicy_ConstantArraySizeAsWritten}, + {"CINDEXTEST_PRINTINGPOLICY_ANONYMOUSTAGLOCATIONS", + CXPrintingPolicy_AnonymousTagLocations}, + {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSTRONGLIFETIME", + CXPrintingPolicy_SuppressStrongLifetime}, + {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSLIFETIMEQUALIFIERS", + CXPrintingPolicy_SuppressLifetimeQualifiers}, + {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSTEMPLATEARGSINCXXCONSTRUCTORS", + CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors}, + {"CINDEXTEST_PRINTINGPOLICY_BOOL", CXPrintingPolicy_Bool}, + {"CINDEXTEST_PRINTINGPOLICY_RESTRICT", CXPrintingPolicy_Restrict}, + {"CINDEXTEST_PRINTINGPOLICY_ALIGNOF", CXPrintingPolicy_Alignof}, + {"CINDEXTEST_PRINTINGPOLICY_UNDERSCOREALIGNOF", + CXPrintingPolicy_UnderscoreAlignof}, + {"CINDEXTEST_PRINTINGPOLICY_USEVOIDFORZEROPARAMS", + CXPrintingPolicy_UseVoidForZeroParams}, + {"CINDEXTEST_PRINTINGPOLICY_TERSEOUTPUT", CXPrintingPolicy_TerseOutput}, + {"CINDEXTEST_PRINTINGPOLICY_POLISHFORDECLARATION", + CXPrintingPolicy_PolishForDeclaration}, + {"CINDEXTEST_PRINTINGPOLICY_HALF", CXPrintingPolicy_Half}, + {"CINDEXTEST_PRINTINGPOLICY_MSWCHAR", CXPrintingPolicy_MSWChar}, + {"CINDEXTEST_PRINTINGPOLICY_INCLUDENEWLINES", + CXPrintingPolicy_IncludeNewlines}, + {"CINDEXTEST_PRINTINGPOLICY_MSVCFORMATTING", + CXPrintingPolicy_MSVCFormatting}, + {"CINDEXTEST_PRINTINGPOLICY_CONSTANTSASWRITTEN", + CXPrintingPolicy_ConstantsAsWritten}, + {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSIMPLICITBASE", + CXPrintingPolicy_SuppressImplicitBase}, + {"CINDEXTEST_PRINTINGPOLICY_FULLYQUALIFIEDNAME", + CXPrintingPolicy_FullyQualifiedName}, + }; + + unsigned i; + for (i = 0; i < sizeof(mappings) / sizeof(struct Mapping); i++) { + char *value = getenv(mappings[i].name); + if (value) { + clang_PrintingPolicy_setProperty(Policy, mappings[i].property, + (unsigned)strtoul(value, 0L, 10)); + } + } +} + /** \brief Returns 0 in case of success, non-zero in case of a failure. */ static int checkForErrors(CXTranslationUnit TU); @@ -356,7 +418,11 @@ PrintExtent(stdout, begin_line, begin_column, end_line, end_column); } -int want_display_name = 0; +static enum DisplayType { + DisplayType_Spelling, + DisplayType_DisplayName, + DisplayType_Pretty +} wanted_display_type = DisplayType_Spelling; static void printVersion(const char *Prefix, CXVersion Version) { if (Version.Major < 0) @@ -656,6 +722,24 @@ return (int)lhs->col - (int)rhs->col; } +static CXString CursorToText(CXCursor Cursor) { + switch (wanted_display_type) { + case DisplayType_Spelling: + return clang_getCursorSpelling(Cursor); + case DisplayType_DisplayName: + return clang_getCursorDisplayName(Cursor); + case DisplayType_Pretty: + default: { + CXString text; + CXPrintingPolicy Policy = clang_getCursorPrintingPolicy(Cursor); + ModifyPrintingPolicyAccordingToEnv(Policy); + text = clang_getCursorPrettyPrinted(Cursor, Policy); + clang_PrintingPolicy_dispose(Policy); + return text; + } + } +} + static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) { CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor); if (clang_isInvalid(Cursor.kind)) { @@ -682,8 +766,7 @@ int I; ks = clang_getCursorKindSpelling(Cursor.kind); - string = want_display_name? clang_getCursorDisplayName(Cursor) - : clang_getCursorSpelling(Cursor); + string = CursorToText(Cursor); printf("%s=%s", clang_getCString(ks), clang_getCString(string)); clang_disposeString(ks); @@ -1686,7 +1769,12 @@ else if (!strcmp(filter, "all-display") || !strcmp(filter, "local-display")) { ck = NULL; - want_display_name = 1; + wanted_display_type = DisplayType_DisplayName; + } + else if (!strcmp(filter, "all-pretty") || + !strcmp(filter, "local-pretty")) { + ck = NULL; + wanted_display_type = DisplayType_Pretty; } else if (!strcmp(filter, "none")) K = (enum CXCursorKind) ~0; else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl; @@ -1754,8 +1842,11 @@ const char *InvocationPath; Idx = clang_createIndex(/* excludeDeclsFromPCH */ - (!strcmp(filter, "local") || - !strcmp(filter, "local-display"))? 1 : 0, + (!strcmp(filter, "local") || + !strcmp(filter, "local-display") || + !strcmp(filter, "local-pretty")) + ? 1 + : 0, /* displayDiagnostics=*/1); InvocationPath = getenv("CINDEXTEST_INVOCATION_EMISSION_PATH"); if (InvocationPath) Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -4706,6 +4706,195 @@ return cxstring::createSet(Manglings); } +CXPrintingPolicy clang_getCursorPrintingPolicy(CXCursor C) { + if (clang_Cursor_isNull(C)) + return 0; + return new PrintingPolicy(getCursorContext(C).getPrintingPolicy()); +} + +void clang_PrintingPolicy_dispose(CXPrintingPolicy Policy) { + if (Policy) + delete static_cast(Policy); +} + +unsigned +clang_PrintingPolicy_getProperty(CXPrintingPolicy Policy, + enum CXPrintingPolicyProperty Property) { + if (!Policy) + return 0; + + PrintingPolicy *P = static_cast(Policy); + switch (Property) { + case CXPrintingPolicy_Indentation: + return P->Indentation; + case CXPrintingPolicy_SuppressSpecifiers: + return P->SuppressSpecifiers; + case CXPrintingPolicy_SuppressTagKeyword: + return P->SuppressTagKeyword; + case CXPrintingPolicy_IncludeTagDefinition: + return P->IncludeTagDefinition; + case CXPrintingPolicy_SuppressScope: + return P->SuppressScope; + case CXPrintingPolicy_SuppressUnwrittenScope: + return P->SuppressUnwrittenScope; + case CXPrintingPolicy_SuppressInitializers: + return P->SuppressInitializers; + case CXPrintingPolicy_ConstantArraySizeAsWritten: + return P->ConstantArraySizeAsWritten; + case CXPrintingPolicy_AnonymousTagLocations: + return P->AnonymousTagLocations; + case CXPrintingPolicy_SuppressStrongLifetime: + return P->SuppressStrongLifetime; + case CXPrintingPolicy_SuppressLifetimeQualifiers: + return P->SuppressLifetimeQualifiers; + case CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors: + return P->SuppressTemplateArgsInCXXConstructors; + case CXPrintingPolicy_Bool: + return P->Bool; + case CXPrintingPolicy_Restrict: + return P->Restrict; + case CXPrintingPolicy_Alignof: + return P->Alignof; + case CXPrintingPolicy_UnderscoreAlignof: + return P->UnderscoreAlignof; + case CXPrintingPolicy_UseVoidForZeroParams: + return P->UseVoidForZeroParams; + case CXPrintingPolicy_TerseOutput: + return P->TerseOutput; + case CXPrintingPolicy_PolishForDeclaration: + return P->PolishForDeclaration; + case CXPrintingPolicy_Half: + return P->Half; + case CXPrintingPolicy_MSWChar: + return P->MSWChar; + case CXPrintingPolicy_IncludeNewlines: + return P->IncludeNewlines; + case CXPrintingPolicy_MSVCFormatting: + return P->MSVCFormatting; + case CXPrintingPolicy_ConstantsAsWritten: + return P->ConstantsAsWritten; + case CXPrintingPolicy_SuppressImplicitBase: + return P->SuppressImplicitBase; + case CXPrintingPolicy_FullyQualifiedName: + return P->FullyQualifiedName; + } + + assert(false && "Invalid CXPrintingPolicyProperty"); + return 0; +} + +void clang_PrintingPolicy_setProperty(CXPrintingPolicy Policy, + enum CXPrintingPolicyProperty Property, + unsigned Value) { + if (!Policy) + return; + + PrintingPolicy *P = static_cast(Policy); + switch (Property) { + case CXPrintingPolicy_Indentation: + P->Indentation = Value; + return; + case CXPrintingPolicy_SuppressSpecifiers: + P->SuppressSpecifiers = Value; + return; + case CXPrintingPolicy_SuppressTagKeyword: + P->SuppressTagKeyword = Value; + return; + case CXPrintingPolicy_IncludeTagDefinition: + P->IncludeTagDefinition = Value; + return; + case CXPrintingPolicy_SuppressScope: + P->SuppressScope = Value; + return; + case CXPrintingPolicy_SuppressUnwrittenScope: + P->SuppressUnwrittenScope = Value; + return; + case CXPrintingPolicy_SuppressInitializers: + P->SuppressInitializers = Value; + return; + case CXPrintingPolicy_ConstantArraySizeAsWritten: + P->ConstantArraySizeAsWritten = Value; + return; + case CXPrintingPolicy_AnonymousTagLocations: + P->AnonymousTagLocations = Value; + return; + case CXPrintingPolicy_SuppressStrongLifetime: + P->SuppressStrongLifetime = Value; + return; + case CXPrintingPolicy_SuppressLifetimeQualifiers: + P->SuppressLifetimeQualifiers = Value; + return; + case CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors: + P->SuppressTemplateArgsInCXXConstructors = Value; + return; + case CXPrintingPolicy_Bool: + P->Bool = Value; + return; + case CXPrintingPolicy_Restrict: + P->Restrict = Value; + return; + case CXPrintingPolicy_Alignof: + P->Alignof = Value; + return; + case CXPrintingPolicy_UnderscoreAlignof: + P->UnderscoreAlignof = Value; + return; + case CXPrintingPolicy_UseVoidForZeroParams: + P->UseVoidForZeroParams = Value; + return; + case CXPrintingPolicy_TerseOutput: + P->TerseOutput = Value; + return; + case CXPrintingPolicy_PolishForDeclaration: + P->PolishForDeclaration = Value; + return; + case CXPrintingPolicy_Half: + P->Half = Value; + return; + case CXPrintingPolicy_MSWChar: + P->MSWChar = Value; + return; + case CXPrintingPolicy_IncludeNewlines: + P->IncludeNewlines = Value; + return; + case CXPrintingPolicy_MSVCFormatting: + P->MSVCFormatting = Value; + return; + case CXPrintingPolicy_ConstantsAsWritten: + P->ConstantsAsWritten = Value; + return; + case CXPrintingPolicy_SuppressImplicitBase: + P->SuppressImplicitBase = Value; + return; + case CXPrintingPolicy_FullyQualifiedName: + P->FullyQualifiedName = Value; + return; + } + + assert(false && "Invalid CXPrintingPolicyProperty"); +} + +CXString clang_getCursorPrettyPrinted(CXCursor C, CXPrintingPolicy cxPolicy) { + if (clang_Cursor_isNull(C)) + return cxstring::createEmpty(); + + if (clang_isDeclaration(C.kind)) { + const Decl *D = getCursorDecl(C); + if (!D) + return cxstring::createEmpty(); + + SmallString<128> Str; + llvm::raw_svector_ostream OS(Str); + PrintingPolicy *UserPolicy = static_cast(cxPolicy); + D->print(OS, UserPolicy ? *UserPolicy + : getCursorContext(C).getPrintingPolicy()); + + return cxstring::createDup(OS.str()); + } + + return cxstring::createEmpty(); +} + CXString clang_getCursorDisplayName(CXCursor C) { if (!clang_isDeclaration(C.kind)) return clang_getCursorSpelling(C); Index: tools/libclang/libclang.exports =================================================================== --- tools/libclang/libclang.exports +++ tools/libclang/libclang.exports @@ -178,6 +178,8 @@ clang_getCursorCompletionString clang_getCursorDefinition clang_getCursorDisplayName +clang_getCursorPrintingPolicy +clang_getCursorPrettyPrinted clang_getCursorExtent clang_getCursorExceptionSpecificationType clang_getCursorKind @@ -359,3 +361,6 @@ clang_EvalResult_getAsDouble clang_EvalResult_getAsStr clang_EvalResult_dispose +clang_PrintingPolicy_getProperty +clang_PrintingPolicy_setProperty +clang_PrintingPolicy_dispose Index: unittests/libclang/LibclangTest.cpp =================================================================== --- unittests/libclang/LibclangTest.cpp +++ unittests/libclang/LibclangTest.cpp @@ -572,3 +572,26 @@ EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU)); DisplayDiagnostics(); } + +class LibclangPrintingPolicyTest : public LibclangParseTest { +public: + CXPrintingPolicy Policy = nullptr; + + void SetUp() override { + LibclangParseTest::SetUp(); + std::string File = "file.cpp"; + WriteFile(File, "int i;\n"); + ClangTU = clang_parseTranslationUnit(Index, File.c_str(), nullptr, 0, + nullptr, 0, TUFlags); + CXCursor TUCursor = clang_getTranslationUnitCursor(ClangTU); + Policy = clang_getCursorPrintingPolicy(TUCursor); + } + void TearDown() override { + clang_PrintingPolicy_dispose(Policy); + LibclangParseTest::TearDown(); + } +}; + +TEST_F(LibclangPrintingPolicyTest, GetProperty) { + EXPECT_EQ(2U, clang_PrintingPolicy_getProperty(Policy, CXPrintingPolicy_Indentation)); +}