1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use std::collections::HashMap;
6use std::io::Write;
7
8use syn::ext::IdentExt;
9
10use crate::bindgen::cdecl;
11use crate::bindgen::config::{Config, Language, Layout};
12use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver;
13use crate::bindgen::dependencies::Dependencies;
14use crate::bindgen::ir::{
15 AnnotationSet, Cfg, ConditionWrite, DeprecatedNoteKind, Documentation, GenericPath, Path,
16 ToCondition, Type,
17};
18use crate::bindgen::library::Library;
19use crate::bindgen::monomorph::Monomorphs;
20use crate::bindgen::rename::{IdentifierType, RenameRule};
21use crate::bindgen::reserved;
22use crate::bindgen::utilities::IterHelpers;
23use crate::bindgen::writer::{Source, SourceWriter};
24
25#[derive(Debug, Clone)]
26pub struct FunctionArgument {
27 pub name: Option<String>,
28 pub ty: Type,
29 pub array_length: Option<String>,
30}
31
32#[derive(Debug, Clone)]
33pub struct Function {
34 pub path: Path,
35 /// Path to the self-type of the function
36 /// If the function is a method, this will contain the path of the type in the impl block
37 pub self_type_path: Option<Path>,
38 pub ret: Type,
39 pub args: Vec<FunctionArgument>,
40 pub extern_decl: bool,
41 pub cfg: Option<Cfg>,
42 pub annotations: AnnotationSet,
43 pub documentation: Documentation,
44 pub never_return: bool,
45}
46
47impl Function {
48 pub fn load(
49 path: Path,
50 self_type_path: Option<&Path>,
51 sig: &syn::Signature,
52 extern_decl: bool,
53 attrs: &[syn::Attribute],
54 mod_cfg: Option<&Cfg>,
55 ) -> Result<Function, String> {
56 let mut args = sig.inputs.iter().try_skip_map(|x| x.as_argument())?;
57
58 let (mut ret, never_return) = Type::load_from_output(&sig.output)?;
59
60 if let Some(self_path) = self_type_path {
61 for arg in &mut args {
62 arg.ty.replace_self_with(self_path);
63 }
64 ret.replace_self_with(self_path);
65 }
66
67 Ok(Function {
68 path,
69 self_type_path: self_type_path.cloned(),
70 ret,
71 args,
72 extern_decl,
73 cfg: Cfg::append(mod_cfg, Cfg::load(attrs)),
74 annotations: AnnotationSet::load(attrs)?,
75 documentation: Documentation::load(attrs),
76 never_return,
77 })
78 }
79
80 pub fn swift_name(&self, config: &Config) -> Option<String> {
81 if config.language == Language::Cython {
82 return None;
83 }
84 // If the symbol name starts with the type name, separate the two components with '.'
85 // so that Swift recognises the association between the method and the type
86 let (ref type_prefix, ref type_name) = match self.self_type_path {
87 Some(ref type_name) => {
88 let type_name = type_name.to_string();
89 if !self.path.name().starts_with(&type_name) {
90 return Some(self.path.to_string());
91 }
92 (format!("{}.", type_name), type_name)
93 }
94 None => ("".to_string(), "".to_string()),
95 };
96
97 let item_name = self
98 .path
99 .name()
100 .trim_start_matches(type_name)
101 .trim_start_matches('_');
102
103 let item_args = {
104 let mut items = Vec::with_capacity(self.args.len());
105 for arg in self.args.iter() {
106 items.push(format!("{}:", arg.name.as_ref()?.as_str()));
107 }
108 items.join("")
109 };
110 Some(format!("{}{}({})", type_prefix, item_name, item_args))
111 }
112
113 pub fn path(&self) -> &Path {
114 &self.path
115 }
116
117 pub fn simplify_standard_types(&mut self, config: &Config) {
118 self.ret.simplify_standard_types(config);
119 for arg in &mut self.args {
120 arg.ty.simplify_standard_types(config);
121 }
122 }
123
124 pub fn add_dependencies(&self, library: &Library, out: &mut Dependencies) {
125 self.ret.add_dependencies(library, out);
126 for arg in &self.args {
127 arg.ty.add_dependencies(library, out);
128 }
129 }
130
131 pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) {
132 self.ret.add_monomorphs(library, out);
133 for arg in &self.args {
134 arg.ty.add_monomorphs(library, out);
135 }
136 }
137
138 pub fn mangle_paths(&mut self, monomorphs: &Monomorphs) {
139 self.ret.mangle_paths(monomorphs);
140 for arg in &mut self.args {
141 arg.ty.mangle_paths(monomorphs);
142 }
143 }
144
145 pub fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) {
146 self.ret.resolve_declaration_types(resolver);
147 for arg in &mut self.args {
148 arg.ty.resolve_declaration_types(resolver);
149 }
150 }
151
152 pub fn rename_for_config(&mut self, config: &Config) {
153 // Rename the types used in arguments
154 let generic_params = Default::default();
155 self.ret.rename_for_config(config, &generic_params);
156
157 // Apply rename rules to argument names
158 let rules = self
159 .annotations
160 .parse_atom::<RenameRule>("rename-all")
161 .unwrap_or(config.function.rename_args);
162
163 if let Some(r) = rules.not_none() {
164 let args = std::mem::take(&mut self.args);
165 self.args = args
166 .into_iter()
167 .map(|arg| {
168 let name = arg
169 .name
170 .map(|n| r.apply(&n, IdentifierType::FunctionArg).into_owned());
171 FunctionArgument {
172 name,
173 ty: arg.ty,
174 array_length: None,
175 }
176 })
177 .collect()
178 }
179
180 // Escape C/C++ reserved keywords used in argument names, and
181 // recursively rename argument types.
182 for arg in &mut self.args {
183 arg.ty.rename_for_config(config, &generic_params);
184 if let Some(ref mut name) = arg.name {
185 reserved::escape(name);
186 }
187 }
188
189 // Save the array length of the pointer arguments which need to use
190 // the C-array notation
191 if let Some(tuples) = self.annotations.list("ptrs-as-arrays") {
192 let mut ptrs_as_arrays: HashMap<String, String> = HashMap::new();
193 for str_tuple in tuples {
194 let parts: Vec<&str> = str_tuple[1..str_tuple.len() - 1]
195 .split(';')
196 .map(|x| x.trim())
197 .collect();
198 if parts.len() != 2 {
199 warn!(
200 "{:?} does not follow the correct syntax, so the annotation is being ignored",
201 parts
202 );
203 continue;
204 }
205 ptrs_as_arrays.insert(parts[0].to_string(), parts[1].to_string());
206 }
207
208 for arg in &mut self.args {
209 match arg.ty {
210 Type::Ptr { .. } => {}
211 _ => continue,
212 }
213 let name = match arg.name {
214 Some(ref name) => name,
215 None => continue,
216 };
217 arg.array_length = ptrs_as_arrays.get(name).cloned();
218 }
219 }
220 }
221}
222
223impl Source for Function {
224 fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
225 fn write_1<W: Write>(func: &Function, config: &Config, out: &mut SourceWriter<W>) {
226 let prefix = config.function.prefix(&func.annotations);
227 let postfix = config.function.postfix(&func.annotations);
228
229 let condition = func.cfg.to_condition(config);
230 condition.write_before(config, out);
231
232 func.documentation.write(config, out);
233
234 if func.extern_decl {
235 out.write("extern ");
236 } else {
237 if let Some(ref prefix) = prefix {
238 write!(out, "{} ", prefix);
239 }
240 if func.annotations.must_use(config) {
241 if let Some(ref anno) = config.function.must_use {
242 write!(out, "{} ", anno);
243 }
244 }
245 if let Some(note) = func
246 .annotations
247 .deprecated_note(config, DeprecatedNoteKind::Function)
248 {
249 write!(out, "{} ", note);
250 }
251 }
252 cdecl::write_func(out, func, Layout::Horizontal, config);
253
254 if !func.extern_decl {
255 if let Some(ref postfix) = postfix {
256 write!(out, " {}", postfix);
257 }
258 }
259
260 if let Some(ref swift_name_macro) = config.function.swift_name_macro {
261 if let Some(swift_name) = func.swift_name(config) {
262 write!(out, " {}({})", swift_name_macro, swift_name);
263 }
264 }
265
266 out.write(";");
267
268 condition.write_after(config, out);
269 }
270
271 fn write_2<W: Write>(func: &Function, config: &Config, out: &mut SourceWriter<W>) {
272 let prefix = config.function.prefix(&func.annotations);
273 let postfix = config.function.postfix(&func.annotations);
274
275 let condition = func.cfg.to_condition(config);
276
277 condition.write_before(config, out);
278
279 func.documentation.write(config, out);
280
281 if func.extern_decl {
282 out.write("extern ");
283 } else {
284 if let Some(ref prefix) = prefix {
285 write!(out, "{}", prefix);
286 out.new_line();
287 }
288 if func.annotations.must_use(config) {
289 if let Some(ref anno) = config.function.must_use {
290 write!(out, "{}", anno);
291 out.new_line();
292 }
293 }
294 if let Some(note) = func
295 .annotations
296 .deprecated_note(config, DeprecatedNoteKind::Function)
297 {
298 write!(out, "{}", note);
299 out.new_line();
300 }
301 }
302 cdecl::write_func(out, func, Layout::Vertical, config);
303 if !func.extern_decl {
304 if let Some(ref postfix) = postfix {
305 out.new_line();
306 write!(out, "{}", postfix);
307 }
308 }
309
310 if let Some(ref swift_name_macro) = config.function.swift_name_macro {
311 if let Some(swift_name) = func.swift_name(config) {
312 write!(out, " {}({})", swift_name_macro, swift_name);
313 }
314 }
315
316 out.write(";");
317
318 condition.write_after(config, out);
319 }
320
321 match config.function.args {
322 Layout::Horizontal => write_1(self, config, out),
323 Layout::Vertical => write_2(self, config, out),
324 Layout::Auto => {
325 if !out.try_write(|out| write_1(self, config, out), config.line_length) {
326 write_2(self, config, out)
327 }
328 }
329 }
330 }
331}
332
333trait SynFnArgHelpers {
334 fn as_argument(&self) -> Result<Option<FunctionArgument>, String>;
335}
336
337fn gen_self_type(receiver: &syn::Receiver) -> Type {
338 let self_ty: Type = Type::Path(GenericPath::self_path());
339 if receiver.reference.is_none() {
340 return self_ty;
341 }
342
343 let is_const: bool = receiver.mutability.is_none();
344 Type::Ptr {
345 ty: Box::new(self_ty),
346 is_const,
347 is_nullable: false,
348 is_ref: false,
349 }
350}
351
352impl SynFnArgHelpers for syn::FnArg {
353 fn as_argument(&self) -> Result<Option<FunctionArgument>, String> {
354 match *self {
355 syn::FnArg::Typed(syn::PatType {
356 ref pat, ref ty, ..
357 }) => {
358 let name = match **pat {
359 syn::Pat::Wild(..) => None,
360 syn::Pat::Ident(syn::PatIdent { ref ident, .. }) => {
361 Some(ident.unraw().to_string())
362 }
363 _ => {
364 return Err(format!(
365 "Parameter has an unsupported argument name: {:?}",
366 pat
367 ))
368 }
369 };
370 let ty = match Type::load(ty)? {
371 Some(x) => x,
372 None => return Ok(None),
373 };
374 if let Type::Array(..) = ty {
375 return Err("Array as function arguments are not supported".to_owned());
376 }
377 Ok(Some(FunctionArgument {
378 name,
379 ty,
380 array_length: None,
381 }))
382 }
383 syn::FnArg::Receiver(ref receiver) => Ok(Some(FunctionArgument {
384 name: Some("self".to_string()),
385 ty: gen_self_type(receiver),
386 array_length: None,
387 })),
388 }
389 }
390}
391