Skip to content

fix: handle types without a namespace or assembly in reside-in checks - #501

Open
iamAdarshh wants to merge 1 commit into
TNG:mainfrom
iamAdarshh:fix/null-namespace-function-pointer
Open

iamAdarshh wants to merge 1 commit into
TNG:mainfrom
iamAdarshh:fix/null-namespace-function-pointer

Conversation

@iamAdarshh

@iamAdarshh iamAdarshh commented Sep 28, 2026 •

Copy link
Copy Markdown

Function pointer types (Cecil FunctionPointerType) are created by DomainResolver with a null Namespace and a null Assembly. They only show up in ReferencedTypes, so Types() rules work, but any namespace/assembly predicate on Types(true) throws a NullReferenceException, as reported in #492:

Types(true).That().ResideInNamespace("System").GetObjects(architecture) // NRE on System.Private.CoreLib

This follows Option 1 from the issue, as the maintainer suggested: null-guard the helpers instead of dropping function pointers from the type set.

Changes

  • TypeExtensions: ResidesInNamespace, ResidesInNamespaceMatching, ResidesInAssembly and ResidesInAssemblyMatching return false for a type without a namespace/assembly.
  • TypeConditionsDefinition:
    • SimpleCondition builds the failure description eagerly, even for passing objects, so every ResideIn*/NotResideIn* condition dereferenced Namespace.FullName/Assembly.FullName. Those messages now go through two small helpers that fall back to "does not reside in a namespace" / "does not reside in an assembly".
    • The System.Reflection.Assembly overloads of ResideInAssembly/NotResideInAssembly compared with ruleType.Assembly.Equals(...). They now use the static Equals(a, b).
  • Tests: FunctionPointerTests adds a class with a delegate*<int, void> field and covers the extension methods, the predicates (ResideIn*/DoNotResideIn*) and the conditions for both namespace and assembly. All of them failed with an NRE before this change.
  • ArchLoaderTests.SameFullNameInMultipleAssemblies filters the shared test architecture's ReferencedTypes by type.Namespace.FullName. The new fixture puts a function pointer there, so that filter is now ?..

I also ran the exact snippet from the issue against System.Private.CoreLib. The 32 null-namespace referenced types are still present, and Types(true).That().ResideInNamespace("System") now returns results instead of throwing.

The issue only mentions the namespace helpers. I included the assembly side because function pointers have a null Assembly too, and ResideInAssembly on Types(true) fails the same way. If you'd rather keep this PR to the namespace fix, I'm happy to split it out.

dotnet build, dotnet test and mise run check pass locally.

Resolves #492

@codecov-commenter

codecov-commenter commented Sep 28, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.39%. Comparing base (dcf76a3) to head (fcefb43).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #501      +/-   ##
==========================================
+ Coverage   86.33%   86.39%   +0.05%     
==========================================
  Files         260      260              
  Lines       12496    12506      +10     
  Branches     1216     1222       +6     
==========================================
+ Hits        10789    10804      +15     
+ Misses       1372     1364       -8     
- Partials      335      338       +3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Function pointer types are created by the DomainResolver with a null
Namespace and a null Assembly. They only ever appear as referenced types,
so rules on Types() were unaffected, but any namespace or assembly
predicate on Types(true) dereferenced the null and threw a
NullReferenceException, e.g.

    Types(true).That().ResideInNamespace("System")

on System.Private.CoreLib.

Guard ResidesInNamespace(Matching) and ResidesInAssembly(Matching) so a
type without a namespace or assembly simply does not reside in one. The
corresponding conditions had the same problem in two more places: the
assembly-object overloads compared via ruleType.Assembly.Equals(...), and
every ResideIn*/NotResideIn* condition builds its failure description
eagerly from Namespace.FullName or Assembly.FullName. Compare with the
static Equals and describe such types as "does not reside in a namespace"
or "does not reside in an assembly".

The new fixture adds a function pointer to the shared test architecture,
which made ArchLoaderTests.SameFullNameInMultipleAssemblies trip over the
same null while filtering ReferencedTypes; make that filter null-safe.

Resolves TNG#492

Signed-off-by: Adarsh Choudhary <adarshchoudhary087@gmail.com>
@iamAdarshh
iamAdarshh force-pushed the fix/null-namespace-function-pointer branch from 8de0137 to fcefb43 Compare September 28, 2026 14:09

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: NullReferenceException in ResidesInNamespace when using Types(true)

2 participants