1
+ //! Intermediate representation for attributes.
2
+ use std:: str;
3
+
4
+ use clang:: Cursor ;
5
+ use clang_sys:: { CXCursor_UnexposedAttr , CXChildVisit_Continue } ;
6
+ use cexpr:: token:: { Token , Kind } ;
7
+
8
+ use super :: context:: BindgenContext ;
9
+
10
+ /// The special attribute
11
+ #[ derive( Clone , Debug ) ]
12
+ pub enum Attribute {
13
+ /// This attribute results in a warning if the type is used anywhere in the source file.
14
+ Deprecated ( Option < String > ) ,
15
+ /// This attribute means that variables of that type are meant to appear possibly unused.
16
+ Unused ,
17
+ /// This attribute attached to a function, means that code must be emitted for the function
18
+ /// even if it appears that the function is not referenced.
19
+ Used ,
20
+ /// This attribute on functions is used to inform the compiler that the function is unlikely to be executed.
21
+ Cold ,
22
+ /// Many functions do not examine any values except their arguments,
23
+ /// and have no effects except the return value.
24
+ Const ,
25
+ /// This attribute causes the function to be called automatically before execution enters main ().
26
+ Constructor ( Option < isize > ) ,
27
+ /// This attribute causes the function to be called automatically after main () completes or exit () is called.
28
+ Destructor ( Option < isize > ) ,
29
+ /// This attribute specifies a minimum alignment (in bytes)
30
+ Aligned ( Vec < Token > ) ,
31
+ /// An attribute whose specific kind is not exposed via this interface.
32
+ Unexposed ( String , Vec < Token > )
33
+ }
34
+
35
+ impl Attribute {
36
+ /// Construct a new `Attribute`.
37
+ pub fn new ( tokens : Vec < Token > ) -> Self {
38
+ // https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html#Attribute-Syntax
39
+ assert ! ( !tokens. is_empty( ) ) ;
40
+
41
+ let ( token, args) = tokens. split_first ( ) . unwrap ( ) ;
42
+
43
+ assert_eq ! ( token. kind, Kind :: Identifier ) ;
44
+
45
+ let name = unsafe { str:: from_utf8_unchecked ( & token. raw ) } ;
46
+
47
+ debug ! ( "__attribute__(({}({:?})))" , name, args) ;
48
+
49
+ match name {
50
+ "deprecated" => {
51
+ let text = if args. len ( ) == 3 &&
52
+ args[ 0 ] . kind == Kind :: Punctuation && args[ 0 ] . raw . as_ref ( ) == b"(" &&
53
+ args[ 1 ] . kind == Kind :: Literal &&
54
+ args[ 2 ] . kind == Kind :: Punctuation && args[ 2 ] . raw . as_ref ( ) == b")" {
55
+ str:: from_utf8 ( args[ 1 ] . raw . as_ref ( ) ) . ok ( ) . map ( String :: from)
56
+ } else {
57
+ None
58
+ } ;
59
+
60
+ Attribute :: Deprecated ( text)
61
+ }
62
+ "unused" => Attribute :: Unused ,
63
+ "used" => Attribute :: Used ,
64
+ "cold" => Attribute :: Cold ,
65
+ "const" => Attribute :: Const ,
66
+ "constructor" => {
67
+ let priority = if args. len ( ) == 3 &&
68
+ args[ 0 ] . kind == Kind :: Punctuation && args[ 0 ] . raw . as_ref ( ) == b"(" &&
69
+ args[ 1 ] . kind == Kind :: Literal &&
70
+ args[ 2 ] . kind == Kind :: Punctuation && args[ 2 ] . raw . as_ref ( ) == b")" {
71
+ str:: from_utf8 ( args[ 1 ] . raw . as_ref ( ) ) . ok ( ) . and_then ( |s| s. parse :: < isize > ( ) . ok ( ) )
72
+ } else {
73
+ None
74
+ } ;
75
+
76
+ Attribute :: Constructor ( priority)
77
+ }
78
+ "destructor" => {
79
+ let priority = if args. len ( ) == 3 &&
80
+ args[ 0 ] . kind == Kind :: Punctuation && args[ 0 ] . raw . as_ref ( ) == b"(" &&
81
+ args[ 1 ] . kind == Kind :: Literal &&
82
+ args[ 2 ] . kind == Kind :: Punctuation && args[ 2 ] . raw . as_ref ( ) == b")" {
83
+ str:: from_utf8 ( args[ 1 ] . raw . as_ref ( ) ) . ok ( ) . and_then ( |s| s. parse :: < isize > ( ) . ok ( ) )
84
+ } else {
85
+ None
86
+ } ;
87
+
88
+ Attribute :: Destructor ( priority)
89
+ }
90
+ "aligned" => Attribute :: Aligned ( Vec :: from ( args) ) ,
91
+ _ => Attribute :: Unexposed ( String :: from ( name) , Vec :: from ( args) ) ,
92
+ }
93
+ }
94
+
95
+ /// Parse a `Cursor` for `Vec<Attribute>`.
96
+ pub fn parse ( cur : & Cursor , ctx : & BindgenContext ) -> Vec < Self > {
97
+ let mut attributes = vec ! [ ] ;
98
+
99
+ if let Some ( tokens) = ctx. translation_unit ( ) . cexpr_tokens ( & cur) {
100
+ let mut c = 0 ;
101
+ let mut iter = tokens. iter ( ) ;
102
+
103
+ while c >= 0 {
104
+ let tokens = iter. by_ref ( ) . take_while ( |ref token| {
105
+ if token. kind == Kind :: Punctuation {
106
+ c += match token. raw . as_ref ( ) {
107
+ b"(" => 1 ,
108
+ b")" => -1 ,
109
+ b"," if c == 0 => return false ,
110
+ _ => 0 ,
111
+ }
112
+ }
113
+
114
+ c >= 0
115
+ } ) . map ( |token| token. clone ( ) ) . collect :: < Vec < Token > > ( ) ;
116
+
117
+ if tokens. is_empty ( ) {
118
+ break
119
+ } else {
120
+ attributes. push ( Attribute :: new ( tokens) ) ;
121
+ }
122
+ }
123
+ }
124
+
125
+ attributes
126
+ }
127
+
128
+ /// Extract `Vec<Attribute>` from cursor's children.
129
+ pub fn extract ( cur : & Cursor , ctx : & BindgenContext ) -> Vec < Self > {
130
+ let mut attributes = vec ! [ ] ;
131
+
132
+ cur. visit ( |cur| {
133
+ match cur. kind ( ) {
134
+ CXCursor_UnexposedAttr => {
135
+ attributes. append ( & mut Attribute :: parse ( & cur, ctx) )
136
+ }
137
+ _ => { }
138
+ }
139
+ CXChildVisit_Continue
140
+ } ) ;
141
+
142
+ attributes
143
+ }
144
+
145
+ /// Whether this attribute whose specific kind is not exposed.
146
+ pub fn is_unexposed ( & self ) -> bool {
147
+ match * self {
148
+ Attribute :: Unexposed ( ..) |
149
+ Attribute :: Aligned ( ..) => true ,
150
+ _ => false ,
151
+ }
152
+ }
153
+ }
0 commit comments