Skip to content

Commit

Permalink
[libclang/python] Add python bindings for PrintingPolicy (#120494)
Browse files Browse the repository at this point in the history
This allows changing the way pretty-printed code is formatted.
  • Loading branch information
efriedma-quic authored Jan 9, 2025
1 parent 3caa68a commit e6d061a
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 0 deletions.
83 changes: 83 additions & 0 deletions clang/bindings/python/clang/cindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -1770,6 +1770,16 @@ def spelling(self):

return self._spelling

def pretty_printed(self, policy):
"""
Pretty print declarations.
Parameters:
policy -- The policy to control the entities being printed.
"""
return _CXString.from_result(
conf.lib.clang_getCursorPrettyPrinted(self, policy)
)

@property
def displayname(self):
"""
Expand Down Expand Up @@ -3699,6 +3709,72 @@ def write_main_file_to_stdout(self):
conf.lib.clang_CXRewriter_writeMainFileToStdOut(self)


class PrintingPolicyProperty(BaseEnumeration):

"""
A PrintingPolicyProperty identifies a property of a PrintingPolicy.
"""

Indentation = 0
SuppressSpecifiers = 1
SuppressTagKeyword = 2
IncludeTagDefinition = 3
SuppressScope = 4
SuppressUnwrittenScope = 5
SuppressInitializers = 6
ConstantArraySizeAsWritten = 7
AnonymousTagLocations = 8
SuppressStrongLifetime = 9
SuppressLifetimeQualifiers = 10
SuppressTemplateArgsInCXXConstructors = 11
Bool = 12
Restrict = 13
Alignof = 14
UnderscoreAlignof = 15
UseVoidForZeroParams = 16
TerseOutput = 17
PolishForDeclaration = 18
Half = 19
MSWChar = 20
IncludeNewlines = 21
MSVCFormatting = 22
ConstantsAsWritten = 23
SuppressImplicitBase = 24
FullyQualifiedName = 25


class PrintingPolicy(ClangObject):
"""
The PrintingPolicy is a wrapper class around clang::PrintingPolicy
It allows specifying how declarations, expressions, and types should be
pretty-printed.
"""

@staticmethod
def create(cursor):
"""
Creates a new PrintingPolicy
Parameters:
cursor -- Any cursor for a translation unit.
"""
return PrintingPolicy(conf.lib.clang_getCursorPrintingPolicy(cursor))

def __init__(self, ptr):
ClangObject.__init__(self, ptr)

def __del__(self):
conf.lib.clang_PrintingPolicy_dispose(self)

def get_property(self, property):
"""Get a property value for the given printing policy."""
return conf.lib.clang_PrintingPolicy_getProperty(self, property.value)

def set_property(self, property, value):
"""Set a property value for the given printing policy."""
conf.lib.clang_PrintingPolicy_setProperty(self, property.value, value)


# Now comes the plumbing to hook up the C library.

# Register callback types
Expand Down Expand Up @@ -3801,6 +3877,8 @@ def write_main_file_to_stdout(self):
("clang_getCursorExtent", [Cursor], SourceRange),
("clang_getCursorLexicalParent", [Cursor], Cursor),
("clang_getCursorLocation", [Cursor], SourceLocation),
("clang_getCursorPrettyPrinted", [Cursor, PrintingPolicy], _CXString),
("clang_getCursorPrintingPolicy", [Cursor], c_object_p),
("clang_getCursorReferenced", [Cursor], Cursor),
("clang_getCursorReferenceNameRange", [Cursor, c_uint, c_uint], SourceRange),
("clang_getCursorResultType", [Cursor], Type),
Expand Down Expand Up @@ -3924,6 +4002,9 @@ def write_main_file_to_stdout(self):
("clang_Cursor_isAnonymousRecordDecl", [Cursor], bool),
("clang_Cursor_isBitField", [Cursor], bool),
("clang_Location_isInSystemHeader", [SourceLocation], bool),
("clang_PrintingPolicy_dispose", [PrintingPolicy]),
("clang_PrintingPolicy_getProperty", [PrintingPolicy, c_int], c_uint),
("clang_PrintingPolicy_setProperty", [PrintingPolicy, c_int, c_uint]),
("clang_Type_getAlignOf", [Type], c_longlong),
("clang_Type_getClassType", [Type], Type),
("clang_Type_getNumTemplateArguments", [Type], c_int),
Expand Down Expand Up @@ -4104,6 +4185,8 @@ def function_exists(self, name: str) -> bool:
"FixIt",
"Index",
"LinkageKind",
"PrintingPolicy",
"PrintingPolicyProperty",
"RefQualifierKind",
"SourceLocation",
"SourceRange",
Expand Down
14 changes: 14 additions & 0 deletions clang/bindings/python/tests/cindex/test_cursor.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
BinaryOperator,
Config,
CursorKind,
PrintingPolicy,
PrintingPolicyProperty,
StorageClass,
TemplateArgumentKind,
TranslationUnit,
Expand Down Expand Up @@ -981,3 +983,15 @@ def test_from_result_null(self):
def test_from_cursor_result_null(self):
tu = get_tu("")
self.assertEqual(tu.cursor.semantic_parent, None)

def test_pretty_print(self):
tu = get_tu("struct X { int x; }; void f(bool x) { }", lang="cpp")
f = get_cursor(tu, "f")

self.assertEqual(f.displayname, "f(bool)")
pp = PrintingPolicy.create(f)
self.assertEqual(pp.get_property(PrintingPolicyProperty.Bool), True)
self.assertEqual(f.pretty_printed(pp), "void f(bool x) {\n}\n")
pp.set_property(PrintingPolicyProperty.Bool, False)
self.assertEqual(pp.get_property(PrintingPolicyProperty.Bool), False)
self.assertEqual(f.pretty_printed(pp), "void f(_Bool x) {\n}\n")
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,8 @@ Sanitizers
Python Binding Changes
----------------------
- Fixed an issue that led to crashes when calling ``Type.get_exception_specification_kind``.
- Added bindings for ``clang_getCursorPrettyPrinted`` and related functions,
which allow changing the formatting of pretty-printed code.
- Added binding for ``clang_Cursor_isAnonymousRecordDecl``, which allows checking if
a declaration is an anonymous union or anonymous struct.

Expand Down

0 comments on commit e6d061a

Please sign in to comment.