Skip to content

fix(objc): do not report an @interface class extension as a function - #490

Open
Eljees wants to merge 2 commits into
terryyin:masterfrom
Eljees:fix/305-objc-interface-is-not-a-function
Open

Eljees wants to merge 2 commits into
terryyin:masterfrom
Eljees:fix/305-objc-interface-is-not-a-function

Conversation

@Eljees

@Eljees Eljees commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Refs #305 — this fixes the part of that report that is still reproducible today.

Where the report stands

Running the reporter's .mm file against master (0b97a9a) shows most of #305 has been
fixed since 2020: init, doSomethingWithCPPobj: and dealloc are found, and the bogus
if@20-23 entry is gone. One line of their output survives, though — the very first one:

$ python lizard.py OCCFile.mm
  NLOC    CCN   token  PARAM  length  location
     4      1      9      0       4 OCCFile@9-12@OCCFile.mm      <-- not a function
     8      2     22      0       8 init@18-25@OCCFile.mm
     5      1     25      0       5 doSomethingWithCPPobj:@27-31@OCCFile.mm
     5      1     11      0       6 dealloc@33-38@OCCFile.mm

Lines 9-12 are the class extension with its instance-variable block:

@interface OCCFile ()
{
    CppFile* mCppFile;
}
@end

Cause

ObjCStates has no notion of @interface / @protocol. The tokens are
['@', 'interface', 'OCCFile', '(', ')', '{', ...], which for the C-like states is
indistinguishable from a function definition OCCFile () { ... }, so a function is created.

The @interface Foo : NSObject { ... } form escapes by accident: the : knocks the machine
out of _state_function before the { arrives. That is why the bug is specific to class
extensions and categories — @interface Foo () and @interface Foo (Private).

Fix

A method body can only appear in @implementation; @interface and @protocol are pure
declarations. The reader now skips such a section up to its @end, so its contents never
reach the C-like states.

Tests

New Test_objc_interface in test/test_languages/testObjC.py:

  • class extension with instance variables;
  • category with instance variables;
  • a trimmed version of the reporter's file — expects exactly ["init", "dealloc"]; before the
    change it returned ["OCCFile", "init", "dealloc"];
  • a @protocol guard, which passed before the change too and is kept as a regression test.

Following .cursor/rules/issue.mdc, the whole suite was run before and after:
python -m pytest1313 passed, 7 skipped, 1 failed. The single failure,
test/testFilesFilter.py::TestFilesFilter::test_gitignore_filter, is pre-existing — it
fails on a clean checkout of 0b97a9a as well (checked with git stash) and is unrelated to
this change. pycodestyle lizard_languages/objc.py is clean.

I left the issue open rather than auto-closing it, in case you read the original report more
broadly than the output it quotes.


Prepared with AI assistance, following the workflow in .cursor/rules/. Every claim above was
verified by running it rather than assumed.

ObjCStates had no notion of @interface / @protocol, so the tokens of a class
extension -- Foo ( ) { ... } -- were indistinguishable from a C function
definition and the extension was reported as a function. A method body can only
appear in @implementation, so an @interface / @protocol section is now skipped
up to its @EnD.

Refs terryyin#305

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 617f13fee6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lizard_languages/objc.py Outdated
Signed-off-by: Eljees <3.14hell@gmail.com>
@Eljees

Eljees commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

Following up on the 13 August change — the three @protocol forms you raised now behave identically on 241374a and on current master, so the skip-until-@end state no longer swallows anything:

source master (3f9270d) this branch (241374a)
@protocol Foo; then @implementation Bar ['doIt'] ['doIt']
@protocol(NSObject) inside an expression ['f'] ['f']
real @protocol definition then @implementation ['qux'] ['qux']
@interface OCCFile () — the #305 case ['OCCFile', 'init'] ['init']

Only the last row differs: the bogus OCCFile entry is gone and nothing else moved. Suite is 1316 passed / 7 skipped, CI is green 4/4, and the branch still merges cleanly.

Ready whenever you have time to look.

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.

2 participants