tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit f7628a0557f7773fcdcd12accc6c8f3d80ea2d41
parent 8aab9af3ce53b438bd95671b7427f555833d9565
Author: serge-sans-paille <sguelton@mozilla.com>
Date:   Fri, 14 Nov 2025 08:19:47 +0000

Bug 1995522 - New Linter - ensure we don't include unnecessary mfbt headers r=glandium,linter-reviewers,ahal

This linter has no knowledge about C or C++. The abstract API of mfbt is
described in tools/lint/includes/api.yml, then we use it to grep for
each symbol from each header when such header are included. If a header
is included but none of its API symbol is referenced, we issue an error.

This is very unlikely to provide a false positive (some macro
shenanigan could though) and may provide false negative, but in
practice it found more than 2k unused headers in the codebase, so the
approach is just pragmatic.

Differential Revision: https://phabricator.services.mozilla.com/D269384

Diffstat:
Adocs/code-quality/lint/linters/includes.rst | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amfbt/api.yml | 993+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtaskcluster/kinds/source-test/mozlint.yml | 21+++++++++++++++++++++
Atools/lint/includes.yml | 11+++++++++++
Atools/lint/includes/__init__.py | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools/lint/test/files/includes/correct_assert.h | 5+++++
Atools/lint/test/files/includes/correct_literal.h | 3+++
Atools/lint/test/files/includes/incorrect_assert.h | 5+++++
Atools/lint/test/files/includes/incorrect_literal.h | 4++++
Mtools/lint/test/python.toml | 2++
Atools/lint/test/test_includes.py | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11 files changed, 1303 insertions(+), 0 deletions(-)

diff --git a/docs/code-quality/lint/linters/includes.rst b/docs/code-quality/lint/linters/includes.rst @@ -0,0 +1,64 @@ +Includes +======== + +This linter checks for unused mfbt headers across the code base. +It is preprocessor-agnostic and mostly language-agnostic. +It should have no false positive, and allows for false negative. + +Principle +--------- + +This linter works by looking for mfbt headers included in any C, Objective-C or +C++ file. For each of this header, it consults an abstract API description file +and checks if any symbol (be it macro, function, global variable, type +definition, operator) described in the API is actually used in the source. If +not it reports the error. + +The lookup for symbol is textual, which makes it very fast (no build required), +preprocessor-agnostic (all configuration are honored, no header generation +required), at the expense of including comments etc. + +API Description +--------------- + +The description file is manually maintained in :searchfox:`API Description (YAML) +<tools/lint/includes/api.yml>`. +It is basically a mapping from header name to a set of symbols, classified by +type (macro, function etc). + +The symbols are named independently of their namespace or argument type. +Any symbol that is not be used by third-party (e.g. from the ``detail`` +namespace, or some auxiliary macro) should not be listed. + +Some checks are done to avoid it from getting out-of-sync, they are performed +through:: + +.. parsed-literal:: + + $ mach test tools/lint/test/test_includes.py + +Some of the changes that would make ``api.yml`` get out-of-sync (e.g., renaming +a header or removing a symbol) are detected by this test and will break CI. + +Run Locally +----------- + +The mozlint integration of this linter can be run using ``mach``: + +.. parsed-literal:: + + $ mach lint --linter includes <file paths> + + +Autofix +------- + +The ``includes`` linter provides a ``--fix`` option. + + +Sources +------- + +* :searchfox:`Linter Configuration (YAML) <tools/lint/includes.yml>` +* :searchfox:`API Description (YAML) <tools/lint/includes/api.yml>` +* :searchfox:`Source <tools/lint/includes/__init__.py>` diff --git a/mfbt/api.yml b/mfbt/api.yml @@ -0,0 +1,993 @@ +--- + +Algorithm.h: + functions: + - AllOf + - AnyOf + - TransformIfAbortOnErr + - TransformAbortOnErr + +Alignment.h: + types: + - AlignedElem + - AlignedStorage2 + +AllocPolicy.h: + types: + - MallocAllocPolicy + - NeverAllocPolicy + +AlreadyAddRefed.h: + types: + - unused_t + - already_AddRefed + +Array.h: + types: + - Array + +ArrayUtils.h: + functions: + - PointerRangeSize + - ArrayEqual + - IsInRange + +Assertions.h: + functions: + - MakeCompilerAssumeUnreachableFakeValue + - InvalidArrayIndex_CRASH + - MOZ_CrashPrintf + - MOZ_Crash + - MOZ_NoReturn + - TerminateProcess + macros: + - MOZ_ASSUME_UNREACHABLE_MARKER + - MOZ_CRASH_UNLESS_FUZZING + - MOZ_ASSERT_UNLESS_FUZZING + - MOZ_ALWAYS_ERR + - MOZ_ALWAYS_OK + - MOZ_ALWAYS_FALSE + - MOZ_ALWAYS_TRUE + - MOZ_FALLTHROUGH_ASSERT + - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE + - MOZ_ASSERT_UNREACHABLE + - MOZ_DIAGNOSTIC_ASSERT_IF + - MOZ_ASSERT_IF + - MOZ_ASSERT_DEBUG_OR_FUZZING + - MOZ_DIAGNOSTIC_ASSERT + - MOZ_ASSERT + - MOZ_RELEASE_ASSERT + - MOZ_CRASH_UNSAFE_FMT + - MOZ_CRASH_UNSAFE_PRINTF + - MOZ_DIAGNOSTIC_CRASH + - MOZ_CRASH + - MOZ_CRASH_WRITE_ADDR + +AtomicBitfields.h: + macros: + - MOZ_ATOMIC_BITFIELDS + +Atomics.h: + types: + - MemoryOrdering + - Atomic + functions: + - cpu_pause + +Attributes.h: + macros: + - MOZ_ALWAYS_INLINE_EVEN_DEBUG + - MOZ_NO_UNIQUE_ADDRESS + - MOZ_ALWAYS_INLINE + - MOZ_NEVER_INLINE + - MOZ_NEVER_INLINE_DEBUG + - MOZ_NOPROFILE + - MOZ_NORETURN_PTR + - MOZ_NOINSTRUMENT + - MOZ_NAKED + - MOZ_COLD + - MOZ_NOMERGE + - MOZ_NONNULL + - MOZ_NONNULL_RETURN + - MOZ_RAII + - MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS + - MOZ_ASAN_IGNORE + - MOZ_TSAN_IGNORE + - MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW + - MOZ_NO_SANITIZE_SIGNED_OVERFLOW + - MOZ_ALLOCATOR + - MOZ_INFALLIBLE_ALLOCATOR + - MOZ_NO_STACK_PROTECTOR + - MOZ_GSL_OWNER + - MOZ_GSL_POINTER + - MOZ_LIFETIME_BOUND + - MOZ_LIFETIME_CAPTURE_BY + - MOZ_STANDALONE_DEBUG + - MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS + - MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS + - MOZ_CAN_RUN_SCRIPT + - MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION + - MOZ_CAN_RUN_SCRIPT_BOUNDARY + - MOZ_MUST_OVERRIDE + - MOZ_STATIC_CLASS + - MOZ_RUNINIT + - MOZ_GLOBINIT + - MOZ_STATIC_LOCAL_CLASS + - MOZ_STACK_CLASS + - MOZ_NONHEAP_CLASS + - MOZ_HEAP_CLASS + - MOZ_NON_TEMPORARY_CLASS + - MOZ_TEMPORARY_CLASS + - MOZ_TRIVIAL_CTOR_DTOR + - MOZ_ALLOW_TEMPORARY + - MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS + - MOZ_IMPLICIT + - MOZ_IS_SMARTPTR_TO_REFCOUNTED + - MOZ_IS_REFPTR + - MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT + - MOZ_HEAP_ALLOCATOR + - MOZ_OWNING_REF + - MOZ_NON_OWNING_REF + - MOZ_UNSAFE_REF + - MOZ_NO_ADDREF_RELEASE_ON_RETURN + - MOZ_NEEDS_NO_VTABLE_TYPE + - MOZ_NON_MEMMOVABLE + - MOZ_NEEDS_MEMMOVABLE_TYPE + - MOZ_NEEDS_MEMMOVABLE_MEMBERS + - MOZ_NO_DANGLING_ON_TEMPORARIES + - MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS + - MOZ_INIT_OUTSIDE_CTOR + - MOZ_IS_CLASS_INIT + - MOZ_NON_PARAM + - MOZ_NON_AUTOABLE + - MOZ_REQUIRED_BASE_METHOD + - MOZ_MUST_RETURN_FROM_CALLER_IF_THIS_IS_ARG + - MOZ_MAY_CALL_AFTER_MUST_RETURN + - MOZ_KNOWN_LIVE + - MOZ_UNANNOTATED + - MOZ_ANNOTATED + - MOZ_FORMAT_PRINTF + - MOZ_FORMAT_WPRINTF + - MOZ_XPCOM_ABI + - MOZ_EMPTY_BASES + - MOZ_CONSTINIT + - MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA + +BinarySearch.h: + functions: + - BinarySearchIf + - BinarySearch + - LowerBound + - UpperBound + - EqualRange + +BitSet.h: + types: + - BitSet + +BloomFilter.h: + types: + - BitBloomFilter + - CountingBloomFilter + +BoundedMPSCQueue.h: + variables: + - MPSC_DEBUG + types: + - MPSCRingBufferBase + - BoundedMPSCQueue + +Buffer.h: + types: + - Buffer + +BufferList.h: + types: + - BufferList + +Casting.h: + functions: + - BitwiseCast + - AssertedCast + - ReleaseAssertedCast + - SaturatingCast + - LazyAssertedCast + +ChaosMode.h: + types: + - ChaosFeature + - ChaosMode + +Char16.h: + macros: + - MOZ_USE_CHAR16_WRAPPER + types: + - char16ptr_t + +CheckedArithmetic.h: + functions: + - SafeAdd + - SafeSub + - SafeMul + +CheckedInt.h: + functions: + - castToCheckedInt + types: + - CheckedInt + - CheckedInt8 + - CheckedUint8 + - CheckedInt16 + - CheckedUint16 + - CheckedInt32 + - CheckedUint32 + - CheckedInt64 + - CheckedUint64 + +CompactPair.h: + types: + - CompactPair + functions: + - MakeCompactPair + +Compiler.h: + macros: + - MOZ_IS_GCC + - MOZ_GCC_VERSION_AT_LEAST + - MOZ_GCC_VERSION_AT_MOST + +DbgMacro.h: + macros: + - MOZ_DBG + - MOZ_DEFINE_DBG + functions: + - DebugValue + +DebugOnly.h: + types: + - DebugOnly + +DefineEnum.h: + macros: + - MOZ_DEFINE_ENUM + - MOZ_DEFINE_ENUM_WITH_BASE + - MOZ_DEFINE_ENUM_CLASS + - MOZ_DEFINE_ENUM_CLASS_WITH_BASE + - MOZ_DEFINE_ENUM_CLASS_AT_CLASS_SCOPE + - MOZ_DEFINE_ENUM_CLASS_WITH_BASE_AND_TOSTRING + - MOZ_DEFINE_ENUM_WITH_TOSTRING_AT_CLASS_SCOPE + - MOZ_DEFINE_ENUM_CLASS_WITH_BASE_AND_TOSTRING_AT_CLASS_SCOPE + - MOZ_DEFINE_ENUM_WITH_BASE_AND_TOSTRING_AT_CLASS_SCOPE + - MOZ_DEFINE_ENUM_WITH_BASE_AND_TOSTRING + - MOZ_DEFINE_ENUM_CLASS_WITH_BASE_AT_CLASS_SCOPE + - MOZ_DEFINE_ENUM_CLASS_WITH_TOSTRING + - MOZ_DEFINE_ENUM_CLASS_WITH_TOSTRING_AT_CLASS_SCOPE + - MOZ_DEFINE_ENUM_AT_CLASS_SCOPE + - MOZ_DEFINE_ENUM_WITH_BASE_AT_CLASS_SCOPE + - MOZ_DEFINE_ENUM_TO_ENUM_TEXT + - MOZ_DEFINE_ENUM_TOSTRING_FUNC + - MOZ_DEFINE_ENUM_TOSTRING_FUNC_IN_CLASS + +DoublyLinkedList.h: + types: + - DoublyLinkedListElement + - GetDoublyLinkedListElement + - DoublyLinkedList + - SafeDoublyLinkedList + +EndianUtils.h: + macros: + - MOZ_LITTLE_ENDIAN + - MOZ_BIG_ENDIAN + + functions: + - byteswap + + types: + - LittleEndian + - BigEndian + - NetworkEndian + - NativeEndian + +EnumeratedArray.h: + types: + - EnumeratedArray + +EnumeratedRange.h: + functions: + - MakeEnumeratedRange + - MakeInclusiveEnumeratedRange + +EnumSet.h: + types: + - EnumSet + +EnumTypeTraits.h: + types: + - EnumTypeFitsWithin + - MinContiguousEnumValue + - MaxContiguousEnumValue + - MaxEnumValue + - ContiguousEnumValues + - ContiguousEnumSize + + functions: + - UnderlyingValue + +FastBernoulliTrial.h: + types: + - FastBernoulliTrial + +FloatingPoint.h: + types: + - FloatingPoint + - FloatingPointTrait + - InfinityBits + - SpecificNaNBits + - SpecificFloatingPointBits + - FuzzyEqualsEpsilon + + functions: + - IsNegative + - IsNegativeZero + - IsPositiveZero + - ToZeroIfNonfinite + - ExponentComponent + - PositiveInfinity + - NegativeInfinity + - SpecificNaN + - MinNumberValue + - MaxNumberValue + - NumberIsInt32 + - NumberIsInt64 + - NumberEqualsInt32 + - NumberEqualsInt64 + - UnspecifiedNaN + - NumbersAreIdentical + - NumbersAreBitwiseIdentical + - EqualOrBothNaN + - NaNSafeMin + - NaNSafeMax + - FuzzyEqualsAdditive + - FuzzyEqualsMultiplicative + - IsFloat32Representable +# +FStream.h: + types: + - IFStream + - OFStream + +FunctionRef.h: + types: + - FunctionRef + +FunctionTypeTraits.h: + types: + - FunctionTypeTraits + +Fuzzing.h: + macros: + - MOZ_FUZZING_NYX_RELEASE + - MOZ_FUZZING_NYX_GUARD + - MOZ_FUZZING_NYX_PRINT + - MOZ_FUZZING_NYX_PRINTF + - MOZ_FUZZING_NYX_DEBUG + - MOZ_FUZZING_NYX_ABORT + - MOZ_FUZZING_HANDLE_CRASH_EVENT2 + - MOZ_FUZZING_HANDLE_CRASH_EVENT4 + +HashFunctions.h: + types: + - HashNumber + - HashCodeScrambler + variables: + - kHashNumberBits + - kGoldenRatioU32 + functions: + - ScrambleHashCode + - AddToHash + - HashGeneric + - HashStringUntilZero + - HashStringKnownLength + - HashString + - HashBytes + +HashTable.h: + types: + - HashMapEntry + - Generation + - HashMap + - HashSet + - PointerHasher + - DefaultHasher + - FallibleHashMethods + + functions: + - MaybeGetHash + - EnsureHash + +HelperMacros.h: + macros: + - MOZ_STRINGIFY + - MOZ_STRINGIFY_NO_EXPANSION + +InitializedOnce.h: + types: + - InitializedOnce + - InitializedOnceNotNull + - LazyInitializedOnce + - LazyInitializedOnceNotNull + - LazyInitializedOnceEarlyDestructible + - LazyInitializedOnceNotNullEarlyDestructible + functions: + - do_Init + +IntegerRange.h: + functions: + - IntegerRange + +IntegerTypeTraits.h: + types: + - UnsignedStdintTypeForSize + - SignedStdintTypeForSize + - PositionOfSignBit + +JSONWriter.h: + types: + - JSONWriter + functions: + - JSONWriteFunc + +JsRust.h: + macros: + - MOZ_HAS_JSRUST + +Latin1.h: + functions: + - IsNonAsciiLatin1 + - IsUtf16Latin1 + - IsUtf8Latin1 + - UnsafeIsValidUtf8Latin1 + - Utf8Latin1UpTo + - UnsafeValidUtf8Lati1UpTo + - LossyConvertUtf16toLatin1 + - LossyConvertUtf8toLatin1 + - ConvertLatin1toUtf8 + - ConvertLatin1toUtf8Partial + - ConvertLatin1toUtf16 + +Likely.h: + macros: + - MOZ_LIKELY + - MOZ_UNLIKELY + +LinkedList.h: + types: + - LinkedList + - LinkedListElement + - AutoCleanLinkedList + functions: + - RangeSizeEstimate + +Literals.h: + literals: + - _KiB + - _MiB + - _percent + +MacroArgs.h: + macros: + - MOZ_CONCAT + - MOZ_ARG_COUNT + - MOZ_PASTE_PREFIX_AND_ARG_COUNT + - MOZ_ARGS_AFTER_1 + - MOZ_ARGS_AFTER_2 + - MOZ_ARG_1 + - MOZ_ARG_2 + - MOZ_ARG_3 + - MOZ_ARG_4 + - MOZ_ARG_5 + - MOZ_ARG_6 + - MOZ_ARG_7 + - MOZ_ARG_8 + - MOZ_ARG_9 + +MacroForEach.h: + macros: + - MOZ_FOR_EACH + - MOZ_FOR_EACH_SEPARATED + +MathAlgorithms.h: + functions: + - DeprecatedAbs + - Abs + - CountLeadingZeroes32 + - CountTrailingZeroes32 + - CountPopulation32 + - CountPopulation64 + - CountLeadingZeroes64 + - CountTrailingZeroes64 + - CeilingLog2 + - CeilingLog2Size + - FindMostSignificantBit + - FloorLog2 + - FloorLog2Size + - RoundUpPow2 + - RotateLeft + - RotateRight + - IsPowerOfTwo + - CountTrailingZeroes + - GCD + +Maybe.h: + types: + - Nothing + - Maybe + functions: + - Some + - SomeRef + - ToMaybeRef + - ToMaybe + +MaybeOneOf.h: + types: + - MaybeOneOf + +MaybeStorageBase.h: + types: + - MaybeStorageBase + variables: + - IsTriviallyDestructibleAndCopyable + +MemoryChecking.h: + macros: + - MOZ_HAVE_MEM_CHECKS + - MOZ_ASAN_VISIBILITY + - MOZ_MAKE_MEM_NOACCESS + - MOZ_MAKE_MEM_UNDEFINED + - MOZ_MAKE_MEM_DEFINED + - MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT + +MemoryReporting.h: + types: + - MallocSizeOf + - MozMallocSizeOf + +MoveOnlyFunction.h: + macros: + - FU2_WITH_LIMITED_EMPTY_PROPAGATION + types: + - MoveOnlyFunction + +MruCache.h: + types: + - MruCache + +NeverDestroyed.h: + types: + - NeverDestroyed + +NonDereferenceable.h: + types: + - NonDereferenceable + +NotNull.h: + types: + - MovingNotNull + - NotNull + functions: + - WrapNotNull + - WrapNotNullUnchecked + - WrapMovingNotNull + - WrapMovingNotNullUnchecked + - MakeNotNull + +Opaque.h: + types: + - Opaque + +OperatorNewExtensions.h: + types: + - NotNullTag + - KnownNotNull + +PairHash.h: + functions: + - HashPair + - HashCompactPair + types: + - PairHasher + - CompactPairHasher + +Path.h: + types: + - Path + +PodOperations.h: + functions: + - PodZero + - PodArrayZero + - PodCopy + - PodArrayCopy + - PodMove + +Poison.h: + variables: + - gMozillaPoisonValue + - gMozillaPoisonBase + - gMozillaPoisonSize + functions: + - mozPoisonValue + - mozWritePoison + types: + - CorruptionCanary + - CorruptionCanaryForStatics + +RandomNum.h: + functions: + - GenerateRandomBytesFromOS + - RandomUint64 + - RandomUint64OrDie + +RangedArray.h: + types: + - RangedArray + +RangedPtr.h: + types: + - RangedPtr + +Range.h: + types: + - Range + +ReentrancyGuard.h: + types: + - ReentrancyGuard + +RefCounted.h: + macros: + - MOZ_REFCOUNTED_LEAK_CHECKING + - MOZ_DECLARE_REFCOUNTED_TYPENAME + types: + - RefCounted + - AtomicRefCounted + +RefCountType.h: + types: + - MozRefCountType + - MozExternalRefCountType + +RefPtr.h: + types: + - RefPtrTraits + - RefPtr + - nsCycleCollectionTraversalCallback + - RefPtrGetterAddRefs + functions: + - CycleCollectionNoteChild + - ImplCycleCollectionUnlink + - ImplCycleCollectionTraverse + - address_of + - getter_AddRefs + - do_AddRef + - MakeAndAddRef + - MakeRefPtr + +ResultExtensions.h: + types: + - Result + - GenericErrorResult + - ResultTypeTraits + + functions: + - ToResult + - ToResultInvoke + - ToResultInvokeMember + + macros: + - MOZ_TO_RESULT_INVOKE_MEMBER + - MOZ_TO_RESULT_INVOKE_MEMBER_TYPED + +Result.h: + types: + - Ok + - ErrorPropagationTag + - Result + - GenericErrorResult + - PackingStrategy + functions: + - ToResult + - Err + +ResultVariant.h: + types: + - Result + - Variant + +ReverseIterator.h: + types: + - IteratorRange + - ReverseIterator + functions: + - Reversed + +RollingMean.h: + types: + - RollingMean + +Saturate.h: + types: + - SaturateInt8 + - SaturateInt16 + - SaturateInt32 + - SaturateIntPtr + - SaturateUint8 + - SaturateUint16 + - SaturateUint32 + - SaturateUintPtr + +ScopeExit.h: + types: + - ScopeExit + functions: + - MakeScopeExit + +SegmentedVector.h: + types: + - SegmentedVector + +SHA1.h: + types: + - SHA1Sum + +SharedLibrary.h: + functions: + - LoadLibraryWithFlags + +SmallPointerArray.h: + types: + - SmallPointerArray + +Span.h: + functions: + - narrow_cast + - AsBytes + - AsChars + - AsWritableBytes + - AsWritableChars + - MakeStringSpan + variables: + - dynamic_extent + types: + - Span + - calculate_byte_size + +SplayTree.h: + types: + - SplayTree + - SplayTreeNode + +SPSCQueue.h: + types: + - SPSCRingBufferBase + - SPSCQueue + +StaticAnalysisFunctions.h: + macros: + - MOZ_CONSTEXPR + - MOZ_CHECK_ASSERT_ASSIGNMENT + - MOZ_KnownLive + functions: + - MOZ_KnownLive + - MOZ_AssertAssignmentTest + +StringBuffer.h: + types: + - StringBuffer + +TaggedAnonymousMemory.h: + functions: + - MozTagAnonymousMemory + - MozTaggedAnonymousMmap + +Tainting.h: + types: + - Tainted + macros: + - MOZ_VALIDATE_AND_GET + - MOZ_IS_VALID + - MOZ_VALIDATE_OR + - MOZ_FIND_AND_VALIDATE + - MOZ_NO_VALIDATE + +TextUtils.h: + functions: + - encoding_ascii_valid_up_to + - IsAscii + - IsAsciiNullTerminated + - AsciiValidUpTo + - Utf16ValidUpTo + - EnsureUtf16ValiditySpan + - ConvertAsciitoUtf16 + - IsAsciiWhitespace + - IsAsciiLowercaseAlpha + - IsAsciiUppercaseAlpha + - IsAsciiAlpha + - IsAsciiDigit + - IsAsciiHexDigit + - IsAsciiAlphanumeric + - AsciiAlphanumericToNumber + +ThreadLocal.h: + macros: + - MOZ_THREAD_LOCAL + +ThreadSafety.h: + macros: + - MOZ_PUSH_IGNORE_THREAD_SAFETY + - MOZ_POP_THREAD_SAFETY + - MOZ_GUARDED_BY + - MOZ_GUARDED_VAR + - MOZ_PT_GUARDED_BY + - MOZ_PT_GUARDED_VAR + - MOZ_ACQUIRED_AFTER + - MOZ_ACQUIRED_BEFORE + - MOZ_REQUIRES + - MOZ_REQUIRES_SHARED + - MOZ_EXCLUDES + - MOZ_RETURN_CAPABILITY + - MOZ_CAPABILITY + - MOZ_SCOPED_CAPABILITY + - MOZ_CAPABILITY_ACQUIRE + - MOZ_EXCLUSIVE_RELEASE + - MOZ_ACQUIRE_SHARED + - MOZ_TRY_ACQUIRE + - MOZ_SHARED_TRYLOCK_FUNCTION + - MOZ_CAPABILITY_RELEASE + - MOZ_NO_THREAD_SAFETY_ANALYSIS + - MOZ_ASSERT_CAPABILITY + - MOZ_ASSERT_SHARED_CAPABILITY + - MOZ_RELEASE_SHARED + - MOZ_RELEASE_GENERIC + - MOZ_SCOPED_UNLOCK_RELEASE + - MOZ_SCOPED_UNLOCK_REACQUIRE + +ThreadSafeWeakPtr.h: + types: + - ThreadSafeWeakPtr + - SupportsThreadSafeWeakPtr + +ToString.h: + functions: + - ToString + +Try.h: + macros: + - MOZ_TRY + +TypedEnumBits.h: + types: + - CastableTypedEnumResult + macros: + - MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS + +Types.h: + macros: + - MOZ_EXPORT + - MOZ_IMPORT_API + - MOZ_IMPORT_DATA + - MFBT_API + - MFBT_DATA + - MOZ_BEGIN_EXTERN_C + - MOZ_END_EXTERN_C + +UniquePtrExtensions.h: + functions: + - MakeUniqueFallible + - MakeUniqueForOverwrite + - MakeUniqueForOverwriteFallible + - DuplicateFileHandle + - RetainMachSendRight + - getter_Transfers + types: + - UniqueFreePtr + - UniqueFileHandle + - UniqueMachSendRight + - UniqueMachReceiveRight + - UniqueMachPortSet + +UniquePtr.h: + types: + - DefaultDelete + - UniquePtr + functions: + - MakeUnique + - WrapUnique + - TempPtrToSetter + +Utf8.h: + functions: + - encoding_utf8_valid_up_to + - Utf8AsUnsignedChars + - IsAscii + - IsUtf8 + - Utf8ValidUpTo + - ConvertUtf16toUtf8 + - ConvertUtf16toUtf8Partial + - ConvertUtf8toUtf16 + - UnsafeConvertValidUtf8toUtf16 + - ConvertUtf8toUtf16WithoutReplacement + - IsTrailingUnit + - DecodeOneUtf8CodePointInline + - DecodeOneUtf8CodePoint + types: + - Utf8Unit + +Variant.h: + types: + - Variant + - VariantType + - VariantIndex + functions: + - AsVariant + +Vector.h: + types: + - Vector + macros: + - MOZ_REENTRANCY_GUARD_ET_AL + +WasiAtomic.h: + types: + - atomic + - memory_order + - atomic_uint8_t + - atomic_uint16_t + - atomic_uint32_t + - atomic_uint64_t + variables: + - memory_order_relaxed + - memory_order_consume + - memory_order_acquire + - memory_order_release + - memory_order_acq_rel + - memory_order_seq_cst + +WeakPtr.h: + macros: + - MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK + - MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK + - MOZ_WEAKPTR_ASSERT_THREAD_SAFETY + - MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED + - MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF + - MOZ_WEAKPTR_THREAD_SAFETY_CHECKING + - NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR + - NS_IMPL_CYCLE_COLLECTION_WEAK_PTR + - NS_IMPL_CYCLE_COLLECTION_WEAK_PTR_INHERITED + + types: + - WeakPtr + - SupportsWeakPtr + - MainThreadWeakPtr + +WindowsVersion.h: + functions: + - IsWindows10BuildOrLater + - IsWin10AnniversaryUpdateOrLater + - IsWin10CreatorsUpdateOrLater + - IsWin10FallCreatorsUpdateOrLater + - IsWin10Sep2018UpdateOrLater + - IsWin11OrLater + - IsWin1122H2OrLater + +WrappingOperations.h: + functions: + - WrapToSigned + - WrappingAdd + - WrappingSubtract + - WrappingMultiply + +XorShift128PlusRNG.h: + types: + - XorShift128PlusRNG diff --git a/taskcluster/kinds/source-test/mozlint.yml b/taskcluster/kinds/source-test/mozlint.yml @@ -795,6 +795,27 @@ ignorefile-test: - '.gitignore' - '.hgignore' + +c-includes: + description: Remove unused mfbt includes from the codebase + treeherder: + symbol: cpp(includes) + run: + mach: lint -l includes -f treeherder -f json:/builds/worker/mozlint.json . + when: + files-changed: + - '**/*.c' + - '**/*.cc' + - '**/*.cpp' + - '**/*.cxx' + - '**/*.h' + - '**/*.hpp' + - '**/*.m' + - '**/*.mm' + - 'tools/lint/includes.yml' + - 'tools/lint/includes/**' + - 'mfbt/api.yml' + gecko-trace: description: Check that all `gecko-trace.yaml` files are correct treeherder: diff --git a/tools/lint/includes.yml b/tools/lint/includes.yml @@ -0,0 +1,11 @@ +--- +includes: + description: > + "Ensure we only include MFBT headers we actually use" + extensions: ['c', 'cc', 'cpp', 'cxx', 'h', 'hpp', 'm', 'mm'] + include: ['.'] + exclude: + - js/src/tests/style/BadIncludesOrder-inl.h + type: external + payload: includes:lint + support-files: ['tools/lint/includes/**'] diff --git a/tools/lint/includes/__init__.py b/tools/lint/includes/__init__.py @@ -0,0 +1,111 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import difflib +import os +import re + +import yaml +from mozlint import result +from mozlint.pathutils import expand_exclusions + +here = os.path.dirname(__file__) +with open(os.path.join(here, "..", "..", "..", "mfbt", "api.yml")) as fd: + description = yaml.safe_load(fd) + + +def generate_diff(path, raw_content, line_to_delete): + prev_content = raw_content.split("\n") + new_content = [ + raw_line + for lineno, raw_line in enumerate(prev_content, start=1) + if lineno != line_to_delete + ] + diff = "\n".join( + difflib.unified_diff(prev_content, new_content, fromfile=path, tofile=path) + ) + return diff + + +def fix(path, raw_content, line_to_delete): + prev_content = raw_content.split("\n") + new_content = [ + raw_line + for lineno, raw_line in enumerate(prev_content, start=1) + if lineno != line_to_delete + ] + with open(path, "w") as outfd: + outfd.write("\n".join(new_content)) + + +symbol_pattern = r"\b{}\b" +literal_pattern = r'[0-9."\']{}\b' + +categories_pattern = { + "variables": symbol_pattern, + "functions": symbol_pattern, + "macros": symbol_pattern, + "types": symbol_pattern, + "literals": literal_pattern, +} + + +def lint(paths, config, **lintargs): + results = {"results": [], "fixed": 0} + + paths = list(expand_exclusions(paths, config, lintargs["root"])) + + for path in paths: + try: + with open(path) as fd: + raw_content = fd.read() + except UnicodeDecodeError: + continue + + supported_keys = "variables", "functions", "macros", "types", "literals" + + for header, categories in description.items(): + assert set(categories.keys()).issubset(supported_keys) + + if path.endswith(f"mfbt/{header}") or path.endswith( + f"mfbt/{header[:-1]}.cpp" + ): + continue + + headerline = rf'#\s*include "mozilla/{header}"' + if not re.search(headerline, raw_content): + continue + + content = raw_content.replace(f'"mozilla/{header}"', "") + + for category, pattern in categories_pattern.items(): + identifiers = categories.get(category, []) + if any( + re.search(pattern.format(identifier), content) + for identifier in identifiers + ): + break + else: + msg = f"{path} includes {header} but does not reference any of its API" + for lineno, raw_line in enumerate(raw_content.split("\n"), start=1): + if re.search(headerline, raw_line): + break + + if lintargs.get("fix"): + fix(path, raw_content, lineno) + results["fixed"] += 1 + else: + diff = generate_diff(path, raw_content, lineno) + + results["results"].append( + result.from_config( + config, + path=path, + message=msg, + level="error", + lineno=lineno, + diff=diff, + ) + ) + return results diff --git a/tools/lint/test/files/includes/correct_assert.h b/tools/lint/test/files/includes/correct_assert.h @@ -0,0 +1,5 @@ +#include "mozilla/Assertions.h" + +void foo() { + MOZ_ASSERT(1 == 1); +} diff --git a/tools/lint/test/files/includes/correct_literal.h b/tools/lint/test/files/includes/correct_literal.h @@ -0,0 +1,3 @@ +#include "mozilla/Literals.h" + +auto const v = 12_KiB; diff --git a/tools/lint/test/files/includes/incorrect_assert.h b/tools/lint/test/files/includes/incorrect_assert.h @@ -0,0 +1,5 @@ +#include "mozilla/Assertions.h" + +void foo() { + static_assert(1 == 1); +} diff --git a/tools/lint/test/files/includes/incorrect_literal.h b/tools/lint/test/files/includes/incorrect_literal.h @@ -0,0 +1,4 @@ +#include "mozilla/Literals.h" + +auto const v = "KiB"; + diff --git a/tools/lint/test/python.toml b/tools/lint/test/python.toml @@ -40,6 +40,8 @@ skip-if = ["os == 'win'"] ["test_ignorefile.py"] +["test_includes.py"] + ["test_lintpref.py"] ["test_manifest_toml.py"] diff --git a/tools/lint/test/test_includes.py b/tools/lint/test/test_includes.py @@ -0,0 +1,84 @@ +import os +import re + +import mozunit +import yaml + +LINTER = "includes" + +topsrcdir = os.path.join(os.path.dirname(__file__), "..", "..", "..") +api_yaml = os.path.join(topsrcdir, "mfbt", "api.yml") +assert os.path.exists(api_yaml), f"includes linter configuration missing in {api_yaml}" + + +def check_symbols_unicity(symbols): + sorted_symbols = sorted(symbols) + sorted_symbols_set = sorted(set(symbols)) + if sorted_symbols != sorted_symbols_set: + # Not the most efficient implementation, but it rarely happens and it's readable. + duplicates = [x for x in sorted_symbols_set if sorted_symbols.count(x) > 1] + raise AssertionError( + f"symbol{'s' if len(duplicates) > 1 else ''} listed more than once: {', '.join(duplicates)}" + ) + + +def test_lint_api_yml(lint): + + with open(api_yaml) as fd: + description = yaml.safe_load(fd) + + category_re = { + "variables": r"\b{}\b", + "functions": r"\b{}\b", + "macros": r"\b{}\b", + "types": r"\b{}\b", + "literal": r'\boperator""{}\b', + } + + # Ensure all listed file exist and contain the described symbols + mfbt_dir = os.path.join(topsrcdir, "mfbt") + for header, categories in description.items(): + header_path = os.path.join(mfbt_dir, header) + assert os.path.exists( + header_path + ), f"{header} described in {api_yaml}, but missing in mfbt/" + + with open(header_path) as fd: + header_content = fd.read() + + # NOTE: This detects removal of symbols in mfbt/* not reflected in + # api.yml, but not addition of symbols. + for category in ("variables", "functions", "macros", "types", "literal"): + symbols = categories.get(category, []) + check_symbols_unicity(symbols) + for symbol in symbols: + symbol_found = re.search( + category_re[category].format(symbol), header_content + ) + assert ( + symbol_found + ), f"{symbol} described as a {category} available in {header}, but cannot be found there" + + +def test_lint_includes(lint, paths): + results = lint(paths("correct_assert.h")) + assert not results + + results = lint(paths("incorrect_assert.h")) + assert len(results) == 1 + assert results[0].message.endswith( + "incorrect_assert.h includes Assertions.h but does not reference any of its API" + ) + + results = lint(paths("correct_literal.h")) + assert not results + + results = lint(paths("incorrect_literal.h")) + assert len(results) == 1 + assert results[0].message.endswith( + "incorrect_literal.h includes Literals.h but does not reference any of its API" + ) + + +if __name__ == "__main__": + mozunit.main()