Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

unittests: test_cmatch: add tests for sub()

Now that we have code for sub(), test it.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Message-ID: <b2621b0d378317f0db5eeb2408c794429dc9f70a.1773770483.git.mchehab+huawei@kernel.org>

authored by

Mauro Carvalho Chehab and committed by
Jonathan Corbet
c22aa12c 9aaeb817

+728 -2
+728 -2
tools/unittests/test_cmatch.py
··· 21 21 sys.path.insert(0, os.path.join(SRC_DIR, "../lib/python")) 22 22 23 23 from kdoc.c_lex import CMatch 24 - from kdoc.xforms_lists import CTransforms 24 + from kdoc.kdoc_re import KernRe 25 25 from unittest_helper import run_unittest 26 26 27 27 # ··· 75 75 76 76 def test_search_no_false_positive(self): 77 77 line = "call__acquires(foo); // should stay intact" 78 - result = ", ".join(CMatch(r"\b__acquires").search(line)) 78 + result = ", ".join(CMatch(r"__acquires").search(line)) 79 79 self.assertEqual(result, "") 80 80 81 81 def test_search_no_macro_remains(self): ··· 87 87 line = "something" 88 88 result = ", ".join(CMatch(line).search(line)) 89 89 self.assertEqual(result, "") 90 + 91 + # 92 + # Override unittest.TestCase to better compare diffs ignoring whitespaces 93 + # 94 + class TestCaseDiff(unittest.TestCase): 95 + """ 96 + Disable maximum limit on diffs and add a method to better 97 + handle diffs with whitespace differences. 98 + """ 99 + 100 + @classmethod 101 + def setUpClass(cls): 102 + """Ensure that there won't be limit for diffs""" 103 + cls.maxDiff = None 104 + 105 + def assertLogicallyEqual(self, a, b): 106 + """ 107 + Compare two results ignoring multiple whitespace differences. 108 + 109 + This is useful to check more complex matches picked from examples. 110 + On a plus side, we also don't need to use dedent. 111 + Please notice that line breaks still need to match. We might 112 + remove it at the regex, but this way, checking the diff is easier. 113 + """ 114 + a = re.sub(r"[\t ]+", " ", a.strip()) 115 + b = re.sub(r"[\t ]+", " ", b.strip()) 116 + 117 + a = re.sub(r"\s+\n", "\n", a) 118 + b = re.sub(r"\s+\n", "\n", b) 119 + 120 + a = re.sub(" ;", ";", a) 121 + b = re.sub(" ;", ";", b) 122 + 123 + self.assertEqual(a, b) 124 + 125 + # 126 + # Tests doing with different macros 127 + # 128 + 129 + class TestSubMultipleMacros(TestCaseDiff): 130 + """ 131 + Tests doing with different macros. 132 + 133 + Here, we won't use assertLogicallyEqual. Instead, we'll check if each 134 + of the expected patterns are present at the answer. 135 + """ 136 + 137 + def test_acquires_simple(self): 138 + """Simple replacement test with __acquires""" 139 + line = "__acquires(ctx) foo();" 140 + result = CMatch(r"__acquires").sub("REPLACED", line) 141 + 142 + self.assertEqual("REPLACED foo();", result) 143 + 144 + def test_acquires_multiple(self): 145 + """Multiple __acquires""" 146 + line = "__acquires(ctx) __acquires(other) bar();" 147 + result = CMatch(r"__acquires").sub("REPLACED", line) 148 + 149 + self.assertEqual("REPLACED REPLACED bar();", result) 150 + 151 + def test_acquires_nested_paren(self): 152 + """__acquires with nested pattern""" 153 + line = "__acquires((ctx1, ctx2)) baz();" 154 + result = CMatch(r"__acquires").sub("REPLACED", line) 155 + 156 + self.assertEqual("REPLACED baz();", result) 157 + 158 + def test_must_hold(self): 159 + """__must_hold with a pointer""" 160 + line = "__must_hold(&lock) do_something();" 161 + result = CMatch(r"__must_hold").sub("REPLACED", line) 162 + 163 + self.assertNotIn("__must_hold(", result) 164 + self.assertIn("do_something();", result) 165 + 166 + def test_must_hold_shared(self): 167 + """__must_hold with an upercase defined value""" 168 + line = "__must_hold_shared(RCU) other();" 169 + result = CMatch(r"__must_hold_shared").sub("REPLACED", line) 170 + 171 + self.assertNotIn("__must_hold_shared(", result) 172 + self.assertIn("other();", result) 173 + 174 + def test_no_false_positive(self): 175 + """ 176 + Ensure that unrelated text containing similar patterns is preserved 177 + """ 178 + line = "call__acquires(foo); // should stay intact" 179 + result = CMatch(r"\b__acquires").sub("REPLACED", line) 180 + 181 + self.assertLogicallyEqual(result, "call__acquires(foo);") 182 + 183 + def test_mixed_macros(self): 184 + """Add a mix of macros""" 185 + line = "__acquires(ctx) __releases(ctx) __must_hold(&lock) foo();" 186 + 187 + result = CMatch(r"__acquires").sub("REPLACED", line) 188 + result = CMatch(r"__releases").sub("REPLACED", result) 189 + result = CMatch(r"__must_hold").sub("REPLACED", result) 190 + 191 + self.assertNotIn("__acquires(", result) 192 + self.assertNotIn("__releases(", result) 193 + self.assertNotIn("__must_hold(", result) 194 + 195 + self.assertIn("foo();", result) 196 + 197 + def test_no_macro_remains(self): 198 + """Ensures that unmatched macros are untouched""" 199 + line = "do_something_else();" 200 + result = CMatch(r"__acquires").sub("REPLACED", line) 201 + 202 + self.assertEqual(result, line) 203 + 204 + def test_no_function(self): 205 + """Ensures that no functions will remain untouched""" 206 + line = "something" 207 + result = CMatch(line).sub("REPLACED", line) 208 + 209 + self.assertEqual(result, line) 210 + 211 + # 212 + # Check if the diff is logically equivalent. To simplify, the tests here 213 + # use a single macro name for all replacements. 214 + # 215 + 216 + class TestSubSimple(TestCaseDiff): 217 + """ 218 + Test argument replacements. 219 + 220 + Here, the function name can be anything. So, we picked __attribute__(), 221 + to mimic a macro found at the Kernel, but none of the replacements her 222 + has any relationship with the Kernel usage. 223 + """ 224 + 225 + MACRO = "__attribute__" 226 + 227 + @classmethod 228 + def setUpClass(cls): 229 + """Define a CMatch to be used for all tests""" 230 + cls.matcher = CMatch(cls.MACRO) 231 + 232 + def test_sub_with_capture(self): 233 + """Test all arguments replacement with a single arg""" 234 + line = f"{self.MACRO}(&ctx)\nfoo();" 235 + 236 + result = self.matcher.sub(r"ACQUIRED(\0)", line) 237 + 238 + self.assertLogicallyEqual("ACQUIRED(&ctx)\nfoo();", result) 239 + 240 + def test_sub_zero_placeholder(self): 241 + """Test all arguments replacement with a multiple args""" 242 + line = f"{self.MACRO}(arg1, arg2)\nbar();" 243 + 244 + result = self.matcher.sub(r"REPLACED(\0)", line) 245 + 246 + self.assertLogicallyEqual("REPLACED(arg1, arg2)\nbar();", result) 247 + 248 + def test_sub_single_placeholder(self): 249 + """Single replacement rule for \1""" 250 + line = f"{self.MACRO}(ctx, boo)\nfoo();" 251 + result = self.matcher.sub(r"ACQUIRED(\1)", line) 252 + 253 + self.assertLogicallyEqual("ACQUIRED(ctx)\nfoo();", result) 254 + 255 + def test_sub_multiple_placeholders(self): 256 + """Replacement rule for both \1 and \2""" 257 + line = f"{self.MACRO}(arg1, arg2)\nbar();" 258 + result = self.matcher.sub(r"REPLACE(\1, \2)", line) 259 + 260 + self.assertLogicallyEqual("REPLACE(arg1, arg2)\nbar();", result) 261 + 262 + def test_sub_mixed_placeholders(self): 263 + """Replacement rule for \0, \1 and additional text""" 264 + line = f"{self.MACRO}(foo, bar)\nbaz();" 265 + result = self.matcher.sub(r"ALL(\0) FIRST(\1)", line) 266 + 267 + self.assertLogicallyEqual("ALL(foo, bar) FIRST(foo)\nbaz();", result) 268 + 269 + def test_sub_no_placeholder(self): 270 + """Replacement without placeholders""" 271 + line = f"{self.MACRO}(arg)\nfoo();" 272 + result = self.matcher.sub(r"NO_BACKREFS()", line) 273 + 274 + self.assertLogicallyEqual("NO_BACKREFS()\nfoo();", result) 275 + 276 + def test_sub_count_parameter(self): 277 + """Verify that the algorithm stops after the requested count""" 278 + line = f"{self.MACRO}(a1) x();\n{self.MACRO}(a2) y();" 279 + result = self.matcher.sub(r"ONLY_FIRST(\1) ", line, count=1) 280 + 281 + self.assertLogicallyEqual(f"ONLY_FIRST(a1) x();\n{self.MACRO}(a2) y();", 282 + result) 283 + 284 + def test_strip_multiple_acquires(self): 285 + """Check if spaces between removed delimiters will be dropped""" 286 + line = f"int {self.MACRO}(1) {self.MACRO}(2 ) {self.MACRO}(3) foo;" 287 + result = self.matcher.sub("", line) 288 + 289 + self.assertLogicallyEqual(result, "int foo;") 290 + 291 + def test_rise_early_greedy(self): 292 + line = f"{self.MACRO}(a, b, c, d);" 293 + sub = r"\1, \2+, \3" 294 + 295 + with self.assertRaises(ValueError): 296 + result = self.matcher.sub(sub, line) 297 + 298 + def test_rise_multiple_greedy(self): 299 + line = f"{self.MACRO}(a, b, c, d);" 300 + sub = r"\1, \2+, \3+" 301 + 302 + with self.assertRaises(ValueError): 303 + result = self.matcher.sub(sub, line) 304 + 305 + # 306 + # Test replacements with slashrefs 307 + # 308 + 309 + 310 + class TestSubWithLocalXforms(TestCaseDiff): 311 + """ 312 + Test diferent usecase patterns found at the Kernel. 313 + 314 + Here, replacements using both CMatch and KernRe can be tested, 315 + as it will import the actual replacement rules used by kernel-doc. 316 + """ 317 + 318 + struct_xforms = [ 319 + (CMatch("__attribute__"), ' '), 320 + (CMatch('__aligned'), ' '), 321 + (CMatch('__counted_by'), ' '), 322 + (CMatch('__counted_by_(le|be)'), ' '), 323 + (CMatch('__guarded_by'), ' '), 324 + (CMatch('__pt_guarded_by'), ' '), 325 + 326 + (CMatch('__cacheline_group_(begin|end)'), ''), 327 + 328 + (CMatch('struct_group'), r'\2'), 329 + (CMatch('struct_group_attr'), r'\3'), 330 + (CMatch('struct_group_tagged'), r'struct \1 { \3+ } \2;'), 331 + (CMatch('__struct_group'), r'\4'), 332 + 333 + (CMatch('__ETHTOOL_DECLARE_LINK_MODE_MASK'), r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'), 334 + (CMatch('DECLARE_PHY_INTERFACE_MASK',), r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'), 335 + (CMatch('DECLARE_BITMAP'), r'unsigned long \1[BITS_TO_LONGS(\2)]'), 336 + 337 + (CMatch('DECLARE_HASHTABLE'), r'unsigned long \1[1 << ((\2) - 1)]'), 338 + (CMatch('DECLARE_KFIFO'), r'\2 *\1'), 339 + (CMatch('DECLARE_KFIFO_PTR'), r'\2 *\1'), 340 + (CMatch('(?:__)?DECLARE_FLEX_ARRAY'), r'\1 \2[]'), 341 + (CMatch('DEFINE_DMA_UNMAP_ADDR'), r'dma_addr_t \1'), 342 + (CMatch('DEFINE_DMA_UNMAP_LEN'), r'__u32 \1'), 343 + (CMatch('VIRTIO_DECLARE_FEATURES'), r'union { u64 \1; u64 \1_array[VIRTIO_FEATURES_U64S]; }'), 344 + ] 345 + 346 + function_xforms = [ 347 + (CMatch('__printf'), ""), 348 + (CMatch('__(?:re)?alloc_size'), ""), 349 + (CMatch("__diagnose_as"), ""), 350 + (CMatch("DECL_BUCKET_PARAMS"), r"\1, \2"), 351 + 352 + (CMatch("__cond_acquires"), ""), 353 + (CMatch("__cond_releases"), ""), 354 + (CMatch("__acquires"), ""), 355 + (CMatch("__releases"), ""), 356 + (CMatch("__must_hold"), ""), 357 + (CMatch("__must_not_hold"), ""), 358 + (CMatch("__must_hold_shared"), ""), 359 + (CMatch("__cond_acquires_shared"), ""), 360 + (CMatch("__acquires_shared"), ""), 361 + (CMatch("__releases_shared"), ""), 362 + (CMatch("__attribute__"), ""), 363 + ] 364 + 365 + var_xforms = [ 366 + (CMatch('__guarded_by'), ""), 367 + (CMatch('__pt_guarded_by'), ""), 368 + (CMatch("LIST_HEAD"), r"struct list_head \1"), 369 + ] 370 + 371 + #: Transforms main dictionary used at apply_transforms(). 372 + xforms = { 373 + "struct": struct_xforms, 374 + "func": function_xforms, 375 + "var": var_xforms, 376 + } 377 + 378 + @classmethod 379 + def apply_transforms(cls, xform_type, text): 380 + """ 381 + Mimic the behavior of kdoc_parser.apply_transforms() method. 382 + 383 + For each element of STRUCT_XFORMS, apply apply_transforms. 384 + 385 + There are two parameters: 386 + 387 + - ``xform_type`` 388 + Can be ``func``, ``struct`` or ``var``; 389 + - ``text`` 390 + The text where the sub patterns from CTransforms will be applied. 391 + """ 392 + for search, subst in cls.xforms.get(xform_type): 393 + text = search.sub(subst, text) 394 + 395 + return text.strip() 396 + 397 + cls.matcher = CMatch(r"struct_group[\w\_]*") 398 + 399 + def test_struct_group(self): 400 + """ 401 + Test struct_group using a pattern from 402 + drivers/net/ethernet/asix/ax88796c_main.h. 403 + """ 404 + line = """ 405 + struct tx_pkt_info { 406 + struct_group(tx_overhead, 407 + struct tx_sop_header sop; 408 + struct tx_segment_header seg; 409 + ); 410 + struct tx_eop_header eop; 411 + u16 pkt_len; 412 + u16 seq_num; 413 + }; 414 + """ 415 + expected = """ 416 + struct tx_pkt_info { 417 + struct tx_sop_header sop; 418 + struct tx_segment_header seg; 419 + struct tx_eop_header eop; 420 + u16 pkt_len; 421 + u16 seq_num; 422 + }; 423 + """ 424 + 425 + result = self.apply_transforms("struct", line) 426 + self.assertLogicallyEqual(result, expected) 427 + 428 + def test_struct_group_attr(self): 429 + """ 430 + Test two struct_group_attr using patterns from fs/smb/client/cifspdu.h. 431 + """ 432 + line = """ 433 + typedef struct smb_com_open_rsp { 434 + struct smb_hdr hdr; /* wct = 34 BB */ 435 + __u8 AndXCommand; 436 + __u8 AndXReserved; 437 + __le16 AndXOffset; 438 + __u8 OplockLevel; 439 + __u16 Fid; 440 + __le32 CreateAction; 441 + struct_group_attr(common_attributes,, 442 + __le64 CreationTime; 443 + __le64 LastAccessTime; 444 + __le64 LastWriteTime; 445 + __le64 ChangeTime; 446 + __le32 FileAttributes; 447 + ); 448 + __le64 AllocationSize; 449 + __le64 EndOfFile; 450 + __le16 FileType; 451 + __le16 DeviceState; 452 + __u8 DirectoryFlag; 453 + __u16 ByteCount; /* bct = 0 */ 454 + } OPEN_RSP; 455 + typedef struct { 456 + struct_group_attr(common_attributes,, 457 + __le64 CreationTime; 458 + __le64 LastAccessTime; 459 + __le64 LastWriteTime; 460 + __le64 ChangeTime; 461 + __le32 Attributes; 462 + ); 463 + __u32 Pad1; 464 + __le64 AllocationSize; 465 + __le64 EndOfFile; 466 + __le32 NumberOfLinks; 467 + __u8 DeletePending; 468 + __u8 Directory; 469 + __u16 Pad2; 470 + __le32 EASize; 471 + __le32 FileNameLength; 472 + union { 473 + char __pad; 474 + DECLARE_FLEX_ARRAY(char, FileName); 475 + }; 476 + } FILE_ALL_INFO; /* level 0x107 QPathInfo */ 477 + """ 478 + expected = """ 479 + typedef struct smb_com_open_rsp { 480 + struct smb_hdr hdr; 481 + __u8 AndXCommand; 482 + __u8 AndXReserved; 483 + __le16 AndXOffset; 484 + __u8 OplockLevel; 485 + __u16 Fid; 486 + __le32 CreateAction; 487 + __le64 CreationTime; 488 + __le64 LastAccessTime; 489 + __le64 LastWriteTime; 490 + __le64 ChangeTime; 491 + __le32 FileAttributes; 492 + __le64 AllocationSize; 493 + __le64 EndOfFile; 494 + __le16 FileType; 495 + __le16 DeviceState; 496 + __u8 DirectoryFlag; 497 + __u16 ByteCount; 498 + } OPEN_RSP; 499 + typedef struct { 500 + __le64 CreationTime; 501 + __le64 LastAccessTime; 502 + __le64 LastWriteTime; 503 + __le64 ChangeTime; 504 + __le32 Attributes; 505 + __u32 Pad1; 506 + __le64 AllocationSize; 507 + __le64 EndOfFile; 508 + __le32 NumberOfLinks; 509 + __u8 DeletePending; 510 + __u8 Directory; 511 + __u16 Pad2; 512 + __le32 EASize; 513 + __le32 FileNameLength; 514 + union { 515 + char __pad; 516 + char FileName[]; 517 + }; 518 + } FILE_ALL_INFO; 519 + """ 520 + 521 + result = self.apply_transforms("struct", line) 522 + self.assertLogicallyEqual(result, expected) 523 + 524 + def test_raw_struct_group(self): 525 + """ 526 + Test a __struct_group pattern from include/uapi/cxl/features.h. 527 + """ 528 + line = """ 529 + struct cxl_mbox_get_sup_feats_out { 530 + __struct_group(cxl_mbox_get_sup_feats_out_hdr, hdr, /* empty */, 531 + __le16 num_entries; 532 + __le16 supported_feats; 533 + __u8 reserved[4]; 534 + ); 535 + struct cxl_feat_entry ents[] __counted_by_le(num_entries); 536 + } __attribute__ ((__packed__)); 537 + """ 538 + expected = """ 539 + struct cxl_mbox_get_sup_feats_out { 540 + __le16 num_entries; 541 + __le16 supported_feats; 542 + __u8 reserved[4]; 543 + struct cxl_feat_entry ents[]; 544 + }; 545 + """ 546 + 547 + result = self.apply_transforms("struct", line) 548 + self.assertLogicallyEqual(result, expected) 549 + 550 + def test_raw_struct_group_tagged(self): 551 + r""" 552 + Test cxl_regs with struct_group_tagged patterns from drivers/cxl/cxl.h. 553 + 554 + NOTE: 555 + 556 + This one has actually a violation from what kernel-doc would 557 + expect: Kernel-doc regex expects only 3 members, but this is 558 + actually defined as:: 559 + 560 + #define struct_group_tagged(TAG, NAME, MEMBERS...) 561 + 562 + The replace expression there is:: 563 + 564 + struct \1 { \3 } \2; 565 + 566 + but it should be really something like:: 567 + 568 + struct \1 { \3 \4 \5 \6 \7 \8 ... } \2; 569 + 570 + a later fix would be needed to address it. 571 + 572 + """ 573 + line = """ 574 + struct cxl_regs { 575 + struct_group_tagged(cxl_component_regs, component, 576 + void __iomem *hdm_decoder; 577 + void __iomem *ras; 578 + ); 579 + 580 + 581 + /* This is actually a violation: too much commas */ 582 + struct_group_tagged(cxl_device_regs, device_regs, 583 + void __iomem *status, *mbox, *memdev; 584 + ); 585 + 586 + struct_group_tagged(cxl_pmu_regs, pmu_regs, 587 + void __iomem *pmu; 588 + ); 589 + 590 + struct_group_tagged(cxl_rch_regs, rch_regs, 591 + void __iomem *dport_aer; 592 + ); 593 + 594 + struct_group_tagged(cxl_rcd_regs, rcd_regs, 595 + void __iomem *rcd_pcie_cap; 596 + ); 597 + }; 598 + """ 599 + expected = """ 600 + struct cxl_regs { 601 + struct cxl_component_regs { 602 + void __iomem *hdm_decoder; 603 + void __iomem *ras; 604 + } component; 605 + 606 + struct cxl_device_regs { 607 + void __iomem *status, *mbox, *memdev; 608 + } device_regs; 609 + 610 + struct cxl_pmu_regs { 611 + void __iomem *pmu; 612 + } pmu_regs; 613 + 614 + struct cxl_rch_regs { 615 + void __iomem *dport_aer; 616 + } rch_regs; 617 + 618 + struct cxl_rcd_regs { 619 + void __iomem *rcd_pcie_cap; 620 + } rcd_regs; 621 + }; 622 + """ 623 + 624 + result = self.apply_transforms("struct", line) 625 + self.assertLogicallyEqual(result, expected) 626 + 627 + def test_struct_group_tagged_with_private(self): 628 + """ 629 + Replace struct_group_tagged with private, using the same regex 630 + for the replacement as what happens in xforms_lists.py. 631 + 632 + As the private removal happens outside NestedGroup class, we manually 633 + dropped the remaining part of the struct, to simulate what happens 634 + at kdoc_parser. 635 + 636 + Taken from include/net/page_pool/types.h 637 + """ 638 + line = """ 639 + struct page_pool_params { 640 + struct_group_tagged(page_pool_params_slow, slow, 641 + struct net_device *netdev; 642 + unsigned int queue_idx; 643 + unsigned int flags; 644 + /* private: only under "slow" struct */ 645 + unsigned int ignored; 646 + ); 647 + /* Struct below shall not be ignored */ 648 + struct_group_tagged(page_pool_params_fast, fast, 649 + unsigned int order; 650 + unsigned int pool_size; 651 + int nid; 652 + struct device *dev; 653 + struct napi_struct *napi; 654 + enum dma_data_direction dma_dir; 655 + unsigned int max_len; 656 + unsigned int offset; 657 + ); 658 + }; 659 + """ 660 + expected = """ 661 + struct page_pool_params { 662 + struct page_pool_params_slow { 663 + struct net_device *netdev; 664 + unsigned int queue_idx; 665 + unsigned int flags; 666 + } slow; 667 + struct page_pool_params_fast { 668 + unsigned int order; 669 + unsigned int pool_size; 670 + int nid; 671 + struct device *dev; 672 + struct napi_struct *napi; 673 + enum dma_data_direction dma_dir; 674 + unsigned int max_len; 675 + unsigned int offset; 676 + } fast; 677 + }; 678 + """ 679 + 680 + result = self.apply_transforms("struct", line) 681 + self.assertLogicallyEqual(result, expected) 682 + 683 + def test_struct_kcov(self): 684 + """ 685 + """ 686 + line = """ 687 + struct kcov { 688 + refcount_t refcount; 689 + spinlock_t lock; 690 + enum kcov_mode mode __guarded_by(&lock); 691 + unsigned int size __guarded_by(&lock); 692 + void *area __guarded_by(&lock); 693 + struct task_struct *t __guarded_by(&lock); 694 + bool remote; 695 + unsigned int remote_size; 696 + int sequence; 697 + }; 698 + """ 699 + expected = """ 700 + """ 701 + 702 + result = self.apply_transforms("struct", line) 703 + self.assertLogicallyEqual(result, expected) 704 + 705 + 706 + def test_struct_kcov(self): 707 + """ 708 + Test a struct from kernel/kcov.c. 709 + """ 710 + line = """ 711 + struct kcov { 712 + refcount_t refcount; 713 + spinlock_t lock; 714 + enum kcov_mode mode __guarded_by(&lock); 715 + unsigned int size __guarded_by(&lock); 716 + void *area __guarded_by(&lock); 717 + struct task_struct *t __guarded_by(&lock); 718 + bool remote; 719 + unsigned int remote_size; 720 + int sequence; 721 + }; 722 + """ 723 + expected = """ 724 + struct kcov { 725 + refcount_t refcount; 726 + spinlock_t lock; 727 + enum kcov_mode mode; 728 + unsigned int size; 729 + void *area; 730 + struct task_struct *t; 731 + bool remote; 732 + unsigned int remote_size; 733 + int sequence; 734 + }; 735 + """ 736 + 737 + result = self.apply_transforms("struct", line) 738 + self.assertLogicallyEqual(result, expected) 739 + 740 + def test_vars_stackdepot(self): 741 + """ 742 + Test guarded_by on vars from lib/stackdepot.c. 743 + """ 744 + line = """ 745 + size_t pool_offset __guarded_by(&pool_lock) = DEPOT_POOL_SIZE; 746 + __guarded_by(&pool_lock) LIST_HEAD(free_stacks); 747 + void **stack_pools __pt_guarded_by(&pool_lock); 748 + """ 749 + expected = """ 750 + size_t pool_offset = DEPOT_POOL_SIZE; 751 + struct list_head free_stacks; 752 + void **stack_pools; 753 + """ 754 + 755 + result = self.apply_transforms("var", line) 756 + self.assertLogicallyEqual(result, expected) 757 + 758 + def test_functions_with_acquires_and_releases(self): 759 + """ 760 + Test guarded_by on vars from lib/stackdepot.c. 761 + """ 762 + line = """ 763 + bool prepare_report_consumer(unsigned long *flags, 764 + const struct access_info *ai, 765 + struct other_info *other_info) \ 766 + __cond_acquires(true, &report_lock); 767 + 768 + int tcp_sigpool_start(unsigned int id, struct tcp_sigpool *c) \ 769 + __cond_acquires(0, RCU_BH); 770 + 771 + bool undo_report_consumer(unsigned long *flags, 772 + const struct access_info *ai, 773 + struct other_info *other_info) \ 774 + __cond_releases(true, &report_lock); 775 + 776 + void debugfs_enter_cancellation(struct file *file, 777 + struct debugfs_cancellation *c) \ 778 + __acquires(cancellation); 779 + 780 + void debugfs_leave_cancellation(struct file *file, 781 + struct debugfs_cancellation *c) \ 782 + __releases(cancellation); 783 + 784 + acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp) \ 785 + __acquires(lockp); 786 + 787 + void acpi_os_release_lock(acpi_spinlock lockp, 788 + acpi_cpu_flags not_used) \ 789 + __releases(lockp) 790 + """ 791 + expected = """ 792 + bool prepare_report_consumer(unsigned long *flags, 793 + const struct access_info *ai, 794 + struct other_info *other_info); 795 + 796 + int tcp_sigpool_start(unsigned int id, struct tcp_sigpool *c); 797 + 798 + bool undo_report_consumer(unsigned long *flags, 799 + const struct access_info *ai, 800 + struct other_info *other_info); 801 + 802 + void debugfs_enter_cancellation(struct file *file, 803 + struct debugfs_cancellation *c); 804 + 805 + void debugfs_leave_cancellation(struct file *file, 806 + struct debugfs_cancellation *c); 807 + 808 + acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp); 809 + 810 + void acpi_os_release_lock(acpi_spinlock lockp, 811 + acpi_cpu_flags not_used) 812 + """ 813 + 814 + result = self.apply_transforms("func", line) 815 + self.assertLogicallyEqual(result, expected) 90 816 91 817 # 92 818 # Run all tests