Repository: xd009642/tarpaulin
Pull request #1384 (2023-09-16 11:49:28)

Ignore attributes on functions
<!--- When contributing to tarpaulin all contributions should branch off the -->
<!--- develop branch as master is only used for releases. --> 

<!--- Check CONTRIBUTING.md for more information-->

<!--- Please describe the changes in the PR and them motivation below -->



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e5731c2..7e60d26 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,13 +3,14 @@
 From 2019 onwards, all notable changes to tarpaulin will be documented in this
 file.
 
-## [Unreleased]
+## [0.27.0] 2023-09-17
 ### Added
 - Added `--fail-immediately` flag to abort execution the moment the first test failure occurs
 
 ### Changed
 - Upgraded from clap v2 to v4. This has a few changes, notably any arguments which can be specified more
 than once require multiple entries so `--run-types doc test` needs to be turned into `--run-types doc --run-types test`
+- Ignore attributes on methods, functions and trait methods
 
 ## [0.26.1] 2023-07-02
 ### Changed
diff --git a/Cargo.lock b/Cargo.lock
index bad51aa..c83ae2d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -151,7 +151,7 @@ dependencies = [
 
 [[package]]
 name = "cargo-tarpaulin"
-version = "0.26.1"
+version = "0.27.0"
 dependencies = [
  "cargo_metadata",
  "cfg-if",
diff --git a/Cargo.toml b/Cargo.toml
index 44e4d82..21be4bf 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cargo-tarpaulin"
-version = "0.26.1"
+version = "0.27.0"
 authors = ["Daniel McKenna <danielmckenna93@gmail.com>"]
 description = "Cargo-Tarpaulin is a tool to determine code coverage achieved via tests"
 repository = "https://github.com/xd009642/tarpaulin"
diff --git a/README.md b/README.md
index f4a0a7d..d9fd301 100644
--- a/README.md
+++ b/README.md
@@ -29,10 +29,9 @@ Below is the help-text for a thorough explanation of the flags and features
 available:
 
 ```
-cargo-tarpaulin version: 0.26.1
 Cargo-Tarpaulin is a tool to determine code coverage achieved via tests
 
-Usage: cargo [OPTIONS] [-- <ARGS>...]
+Usage: cargo tarpaulin [OPTIONS] [-- <ARGS>...]
 
 Arguments:
   [ARGS]...  Arguments to be passed to the test executables can be used to filter or skip certain tests
@@ -105,6 +104,7 @@ Options:
   -r, --root <DIR>                 Calculates relative paths to root directory. If --manifest-path isn't specified it will look for a Cargo.toml in root
       --manifest-path <PATH>       Path to Cargo.toml
       --ciserver <SERVICE>         CI server being used, if unspecified tarpaulin may automatically infer for coveralls uploads
+      --fail-immediately           Option to fail immediately after a single test fails
   -h, --help                       Print help
   -V, --version                    Print version
 ```
diff --git a/src/source_analysis/items.rs b/src/source_analysis/items.rs
index 0a07ac9..babad14 100644
--- a/src/source_analysis/items.rs
+++ b/src/source_analysis/items.rs
@@ -143,6 +143,13 @@ impl SourceAnalysis {
             self.visit_generics(&func.sig.generics, ctx);
             let analysis = self.get_line_analysis(ctx.file.to_path_buf());
             let line_number = func.sig.fn_token.span().start().line;
+            let mut start_line = line_number;
+            for attr in &func.attrs {
+                start_line = start_line.min(attr.span().start().line);
+            }
+            if start_line < line_number {
+                analysis.add_to_ignore(start_line..line_number);
+            }
             analysis.ignore.remove(&Lines::Line(line_number));
             // Ignore multiple lines of fn decl
             let decl_start = func.sig.fn_token.span().start().line + 1;


Test patch:
diff --git a/src/source_analysis/tests.rs b/src/source_analysis/tests.rs
index 9c9c22e..fa0337c 100644
--- a/src/source_analysis/tests.rs
+++ b/src/source_analysis/tests.rs
@@ -1550,3 +1550,39 @@ fn ignore_comment() {
     assert!(lines.ignore.contains(&Lines::Line(11)));
     assert!(lines.ignore.contains(&Lines::Line(12)));
 }
+
+#[test]
+fn py_attr() {
+    let config = Config::default();
+    let ctx = Context {
+        config: &config,
+        file_contents: "use pyo3::prelude::{pyfunction, PyResult};
+
+            #[pyfunction]
+            pub fn print_something() -> PyResult<()> {
+                println!(\"foo\");
+                Ok(())
+            }
+            
+            struct Blah;
+            
+            #[pyimpl]
+            impl Blah {
+                #[pyfunction]
+                fn blah() -> Self {
+                    Self
+                }
+            }
+        ",
+        file: Path::new(""),
+        ignore_mods: RefCell::new(HashSet::new()),
+    };
+    let parser = parse_file(ctx.file_contents).unwrap();
+    let mut analysis = SourceAnalysis::new();
+    analysis.process_items(&parser.items, &ctx);
+    let lines = &analysis.lines[Path::new("")];
+    assert!(lines.ignore.contains(&Lines::Line(1)));
+    assert!(lines.ignore.contains(&Lines::Line(3)));
+    assert!(lines.ignore.contains(&Lines::Line(11)));
+    assert!(lines.ignore.contains(&Lines::Line(13)));
+}