summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Poveda <christian.poveda@ferrous-systems.com>2022-09-01 11:26:47 -0500
committerEmilio Cobos Álvarez <emilio@crisal.io>2022-09-22 20:25:33 -1000
commit2251aed4d0a2422d7b94cceeafcfe9ac98a69ad6 (patch)
tree85118ce135d5273b4df7bf682365e7c8fada0ebe
parent3da6026afd5715715feeb4a8668a91024d71830e (diff)
find all attributes in a single pass
-rw-r--r--src/clang.rs83
-rw-r--r--src/ir/function.rs14
2 files changed, 55 insertions, 42 deletions
diff --git a/src/clang.rs b/src/clang.rs
index 4779e0b7..05ef5d05 100644
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -12,6 +12,27 @@ use std::hash::Hasher;
use std::os::raw::{c_char, c_int, c_longlong, c_uint, c_ulong, c_ulonglong};
use std::{mem, ptr, slice};
+pub struct Attribute {
+ name: &'static [u8],
+ kind: CXCursorKind,
+ token_kind: CXTokenKind,
+}
+
+impl Attribute {
+ pub const MUST_USE: Self = Self {
+ name: b"warn_unused_result",
+ // FIXME(emilio): clang-sys doesn't expose `CXCursor_WarnUnusedResultAttr` (from clang 9).
+ kind: 440,
+ token_kind: CXToken_Identifier,
+ };
+
+ pub const NO_RETURN: Self = Self {
+ name: b"_Noreturn",
+ kind: CXCursor_UnexposedAttr,
+ token_kind: CXToken_Keyword,
+ };
+}
+
/// A cursor into the Clang AST, pointing to an AST node.
///
/// We call the AST node pointed to by the cursor the cursor's "referent".
@@ -638,48 +659,38 @@ impl Cursor {
}
}
- /// Whether this cursor has the `warn_unused_result` attribute.
- pub fn has_warn_unused_result_attr(&self) -> bool {
- // FIXME(emilio): clang-sys doesn't expose this (from clang 9).
- const CXCursor_WarnUnusedResultAttr: CXCursorKind = 440;
- self.has_attr(
- "warn_unused_result",
- Some(CXCursor_WarnUnusedResultAttr),
- CXToken_Identifier,
- )
- }
-
- /// Check wether this cursor has the `_Noreturn` attribute.
- pub fn has_no_return_attr(&self) -> bool {
- self.has_attr("_Noreturn", None, CXToken_Keyword)
- }
-
- /// Does this cursor have the given attribute?
- ///
- /// `name` is checked against unexposed attributes.
- fn has_attr(
+ pub fn has_attrs<const N: usize>(
&self,
- name: &str,
- clang_kind: Option<CXCursorKind>,
- token_kind: CXTokenKind,
- ) -> bool {
- let mut found_attr = false;
+ attrs: &[Attribute; N],
+ ) -> [bool; N] {
+ let mut found_attrs = [false; N];
+ let mut found_count = 0;
+
self.visit(|cur| {
let kind = cur.kind();
- found_attr = clang_kind.map_or(false, |k| k == kind) ||
- (kind == CXCursor_UnexposedAttr &&
- cur.tokens().iter().any(|t| {
- t.kind == token_kind && t.spelling() == name.as_bytes()
- }));
-
- if found_attr {
- CXChildVisit_Break
- } else {
- CXChildVisit_Continue
+ for (idx, attr) in attrs.iter().enumerate() {
+ let found_attr = &mut found_attrs[idx];
+ if !*found_attr {
+ if kind == attr.kind &&
+ cur.tokens().iter().any(|t| {
+ t.kind == attr.token_kind &&
+ t.spelling() == attr.name
+ })
+ {
+ *found_attr = true;
+ found_count += 1;
+
+ if found_count == N {
+ return CXChildVisit_Break;
+ }
+ }
+ }
}
+
+ CXChildVisit_Continue
});
- found_attr
+ found_attrs
}
/// Given that this cursor's referent is a `typedef`, get the `Type` that is
diff --git a/src/ir/function.rs b/src/ir/function.rs
index b829e601..6ed3a503 100644
--- a/src/ir/function.rs
+++ b/src/ir/function.rs
@@ -6,7 +6,7 @@ use super::dot::DotAttributes;
use super::item::Item;
use super::traversal::{EdgeKind, Trace, Tracer};
use super::ty::TypeKind;
-use crate::clang;
+use crate::clang::{self, Attribute};
use crate::parse::{
ClangItemParser, ClangSubItemParser, ParseError, ParseResult,
};
@@ -382,9 +382,6 @@ impl FunctionSig {
use clang_sys::*;
debug!("FunctionSig::from_ty {:?} {:?}", ty, cursor);
- let is_divergent = ctx.options().enable_function_attribute_detection &&
- cursor.has_no_return_attr();
-
// Skip function templates
let kind = cursor.kind();
if kind == CXCursor_FunctionTemplate {
@@ -453,8 +450,13 @@ impl FunctionSig {
}
};
- let must_use = ctx.options().enable_function_attribute_detection &&
- cursor.has_warn_unused_result_attr();
+ let [must_use, is_divergent] =
+ if ctx.options().enable_function_attribute_detection {
+ cursor.has_attrs(&[Attribute::MUST_USE, Attribute::NO_RETURN])
+ } else {
+ Default::default()
+ };
+
let is_method = kind == CXCursor_CXXMethod;
let is_constructor = kind == CXCursor_Constructor;
let is_destructor = kind == CXCursor_Destructor;