Skip to content

Commit 2f47ab0

Browse files
committed
Improve O2 linter
- Rename classes to match the test names better. - `std-prefix`: Simplify test. - `root-entity`: Rename to `root/entity`. - `magic-number`: Extend pattern. Fix false positves. Support multiple matches per line. - Add `root/lorentz-vector`. - Add `pdg/explicit-mass`.
1 parent ee1ae43 commit 2f47ab0

File tree

1 file changed

+89
-15
lines changed

1 file changed

+89
-15
lines changed

Scripts/o2_linter.py

Lines changed: 89 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -301,17 +301,15 @@ def test_line(self, line: str) -> bool:
301301
# Ignore matches inside strings.
302302
for match in matches:
303303
n_quotes_before = line.count('"', 0, match[0]) # Count quotation marks before the match.
304-
if n_quotes_before % 2: # If odd, we are inside a string and we should ignore this match.
305-
continue
306-
# We are not inside a string and this match is valid.
307-
return False
304+
if not n_quotes_before % 2: # If even, we are not inside a string and this match is valid.
305+
return False
308306
return True
309307

310308

311-
class TestROOT(TestSpec):
309+
class TestRootEntity(TestSpec):
312310
"""Detect unnecessary use of ROOT entities."""
313311

314-
name = "root-entity"
312+
name = "root/entity"
315313
message = "Replace ROOT entities with equivalents from standard C++ or from O2."
316314
suffixes = [".h", ".cxx"]
317315

@@ -329,6 +327,23 @@ def test_line(self, line: str) -> bool:
329327
return re.search(pattern, line) is None
330328

331329

330+
class TestRootLorentzVector(TestSpec):
331+
"""Detect use of TLorentzVector."""
332+
333+
name = "root/lorentz-vector"
334+
message = (
335+
"Do not use the TLorentzVector legacy class. "
336+
"Use std::array with RecoDecay methods or ROOT::Math::LorentzVector instead."
337+
)
338+
suffixes = [".h", ".cxx"]
339+
340+
def test_line(self, line: str) -> bool:
341+
if is_comment_cpp(line):
342+
return True
343+
line = remove_comment_cpp(line)
344+
return "TLorentzVector" not in line
345+
346+
332347
class TestPi(TestSpec):
333348
"""Detect use of external pi."""
334349

@@ -404,7 +419,7 @@ def test_line(self, line: str) -> bool:
404419
return "TDatabasePDG" not in line
405420

406421

407-
class TestPdgCode(TestSpec):
422+
class TestPdgExplicitCode(TestSpec):
408423
"""Detect use of hard-coded PDG codes."""
409424

410425
name = "pdg/explicit-code"
@@ -425,7 +440,7 @@ def test_line(self, line: str) -> bool:
425440
return True
426441

427442

428-
class TestPdgMass(TestSpec):
443+
class TestPdgKnownMass(TestSpec):
429444
"""Detect unnecessary call of Mass() for a known PDG code."""
430445

431446
name = "pdg/known-mass"
@@ -444,6 +459,49 @@ def test_line(self, line: str) -> bool:
444459
return True
445460

446461

462+
class TestPdgExplicitMass(TestSpec):
463+
"""Detect hard-coded particle masses."""
464+
465+
name = "pdg/explicit-mass"
466+
message = "Avoid hard-coded particle masses. Use o2::constants::physics::Mass... instead."
467+
suffixes = [".h", ".cxx"]
468+
masses: "list[str]" = [] # list of mass values to detect
469+
470+
def __init__(self) -> None:
471+
super().__init__()
472+
473+
# List of masses of commonly used particles
474+
self.masses.append(r"0\.000511") # e
475+
self.masses.append(r"0\.105") # μ
476+
self.masses.append(r"0\.139") # π+
477+
self.masses.append(r"0\.493") # K+
478+
self.masses.append(r"0\.497") # K0
479+
self.masses.append(r"0\.938") # p
480+
self.masses.append(r"0\.939") # n
481+
self.masses.append(r"1\.115") # Λ
482+
self.masses.append(r"1\.864") # D0
483+
self.masses.append(r"2\.286") # Λc
484+
self.masses.append(r"3\.096") # J/ψ
485+
486+
def test_line(self, line: str) -> bool:
487+
if is_comment_cpp(line):
488+
return True
489+
line = remove_comment_cpp(line)
490+
iterators = re.finditer(rf"(^|\D)({'|'.join(self.masses)})", line)
491+
matches = [(it.start(), it.group(2)) for it in iterators]
492+
if not matches:
493+
return True
494+
if '"' not in line: # Found a match which cannot be inside a string.
495+
return False
496+
# Ignore matches inside strings.
497+
for match in matches:
498+
n_quotes_before = line.count('"', 0, match[0]) # Count quotation marks before the match.
499+
if not n_quotes_before % 2: # If even, we are not inside a string and this match is valid.
500+
print(match[1])
501+
return False
502+
return True
503+
504+
447505
class TestLogging(TestSpec):
448506
"""Detect non-O2 logging."""
449507

@@ -598,16 +656,30 @@ class TestMagicNumber(TestSpec):
598656
name = "magic-number"
599657
message = "Avoid magic numbers in expressions. Assign the value to a clearly named variable or constant."
600658
suffixes = [".h", ".cxx", ".C"]
659+
pattern_compare = r"([<>]=?|[!=]=)"
660+
pattern_number = r"[\+-]?([\d\.]+)f?"
601661

602662
def test_line(self, line: str) -> bool:
603663
if is_comment_cpp(line):
604664
return True
605665
line = remove_comment_cpp(line)
606-
if not (match := re.search(r" ([<>]=?|[!=]=) [\+-]?([\d\.]+)", line)):
666+
iterators = re.finditer(
667+
rf" {self.pattern_compare} {self.pattern_number}|\W{self.pattern_number} {self.pattern_compare} ", line
668+
)
669+
matches = [(it.start(), it.group(2), it.group(3)) for it in iterators]
670+
if not matches:
607671
return True
608-
number = match.group(2)
609-
# Accept only 0 or 1 (int or float).
610-
return re.match(r"[01](\.0?)?$", number) is not None
672+
# Ignore matches inside strings.
673+
for match in matches:
674+
n_quotes_before = line.count('"', 0, match[0]) # Count quotation marks before the match.
675+
if n_quotes_before % 2: # If odd, we are inside a string and we should ignore this match.
676+
continue
677+
# We are not inside a string and this match is valid.
678+
for match_n in (match[1], match[2]):
679+
# Accept only 0 or 1 (int or float).
680+
if (match_n is not None) and (re.match(r"[01](\.0?)?$", match_n) is None):
681+
return False
682+
return True
611683

612684

613685
# Documentation
@@ -1442,13 +1514,15 @@ def main():
14421514
tests.append(TestUsingStd())
14431515
tests.append(TestUsingDirectives())
14441516
tests.append(TestStdPrefix())
1445-
tests.append(TestROOT())
1517+
tests.append(TestRootEntity())
1518+
tests.append(TestRootLorentzVector())
14461519
tests.append(TestPi())
14471520
tests.append(TestTwoPiAddSubtract())
14481521
tests.append(TestPiMultipleFraction())
14491522
tests.append(TestPdgDatabase())
1450-
tests.append(TestPdgCode())
1451-
tests.append(TestPdgMass())
1523+
tests.append(TestPdgExplicitCode())
1524+
tests.append(TestPdgKnownMass())
1525+
tests.append(TestPdgExplicitMass())
14521526
tests.append(TestLogging())
14531527
tests.append(TestConstRefInForLoop())
14541528
tests.append(TestConstRefInSubscription())

0 commit comments

Comments
 (0)