krzysztofzablocki / Sourcery

Meta-programming for Swift, stop writing boilerplate code.
http://merowing.info
MIT License
7.58k stars 605 forks source link

[Bug] Annotations aren't being extracted from initializers #1311

Closed liamnichols closed 3 months ago

liamnichols commented 3 months ago

Bug Report

After updating to 2.1.8, we found that some annotations are no longer being picked up.. I reproduced this bug in the tests with the following example:

class Foo {
    // sourcery: annotation
    init() {
    }
}
failed - idx 0: rawMethods idx 0: annotations Different count, expected: 1, received: 0
Missing keys: annotation

What is strange is that this does not fail when the init() trailing brace is on the same line. For example, this works:

class Foo {
    // sourcery: annotation
    init() {}
}

I tried to replicate this with the foo() function test above, but the issue didn't surface

Bug Fix

Currently I don't have a fix.. I'm going to try and dig in later on if I get a chance.

art-divin commented 3 months ago

Hello @liamnichols ,

thank you very much for reporting. Indeed, 2.1.8 release has at least one bug fix related to the annotation parser, where trailing annotations were pretty much ignored by the parser and sometimes worked by accident.

It seems like this test was missing, and though every other test was green, at least this got broken for the init method.

art-divin commented 3 months ago

@liamnichols

I have investigated and here's a patch which solves this issue. If you could, please apply and let's make it happen 👍🏻

diff --git forkSrcPrefix/SourceryFramework/Sources/Parsing/Utils/AnnotationsParser.swift forkDstPrefix/SourceryFramework/Sources/Parsing/Utils/AnnotationsParser.swift
index 0dec0d896b58d2c964fb3fcb18034976ab753865..d0773ad3b51d3ff106ac119dc92791befdde84e5 100644
--- forkSrcPrefix/SourceryFramework/Sources/Parsing/Utils/AnnotationsParser.swift
+++ forkDstPrefix/SourceryFramework/Sources/Parsing/Utils/AnnotationsParser.swift
@@ -199,8 +199,10 @@ public struct AnnotationsParser {
         if prefix.isEmpty {
             shouldUsePositionBeforeTrailing = true
             (prefix, sourceLine) = findPrefix(positionBeforeTrailingTrivia, shouldUsePositionBeforeTrailing)
-            if shouldUsePositionBeforeTrailing {
+            if shouldUsePositionBeforeTrailing && !prefix.isEmpty {
                 position = positionBeforeTrailingTrivia
+            } else {
+                shouldUsePositionBeforeTrailing = false
             }
         }
         guard !prefix.isEmpty else { return ([:], shouldUsePositionBeforeTrailing) }

Details

Previously, a new feature of parsing "trailing annotations" (i.e. func method() // sourcery: annotation=this is a trailing annotation) was added. Now, there's a logic which first tries to search for an annotation in the beginning of the line, and if that fails, the logic at fault of this bug sets a variable which indicates the position of the annotation in the end of the line to true. But if there was no annotation in the end of that line, this eliminates other checks for annotation aggregation.

liamnichols commented 3 months ago

@art-divin, great! Thanks so much for the quick response and the suggestion 🙇 I ran the tests locally and also ran this branch against our project and everything looks good 🙏