Skip to content

Commit bd4dfad

Browse files
neboozclaude
andcommitted
fix: avoid false positive error/warning detection from echoed source code
The `grepWarningsAndErrors` regex matched any line containing `error:` or `warning:`, which produced false positives when xcodebuild echoes Swift source lines during compilation (e.g. `var authError: Error?`, `private(set) var error: WalletError?`). Tighten the regex to require `error:`/`warning:` at the start of the line or after a file:line:col location prefix (`:<digits>: `), matching only real xcodebuild diagnostic output. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent c14c159 commit bd4dfad

2 files changed

Lines changed: 96 additions & 2 deletions

File tree

src/utils/__tests__/build-utils-suppress-warnings.test.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,95 @@ describe('executeXcodeBuildCommand - suppressWarnings', () => {
7575
expect(textContent).not.toContain('⚠️ Warning:');
7676
expect(textContent).toContain('❌ Error:');
7777
});
78+
79+
it('should not flag source code lines containing "error" or "warning" as diagnostics', async () => {
80+
sessionStore.setDefaults({ suppressWarnings: false });
81+
82+
// Swift source lines echoed during compilation that contain "error"/"warning" as substrings
83+
const buildOutput = [
84+
' var authError: Error?',
85+
' private(set) var error: WalletError?',
86+
' private(set) var lastError: Error?',
87+
' var loadError: Error?',
88+
' private(set) var error: String?',
89+
' var warningCount: Int = 0',
90+
' let isWarning: Bool',
91+
' fatalError("unexpected state")',
92+
].join('\n');
93+
94+
const mockExecutor = createMockExecutor({
95+
success: true,
96+
output: buildOutput,
97+
error: '',
98+
exitCode: 0,
99+
});
100+
101+
const result = await executeXcodeBuildCommand(
102+
{
103+
projectPath: '/test/project.xcodeproj',
104+
scheme: 'TestScheme',
105+
configuration: 'Debug',
106+
},
107+
{
108+
platform: XcodePlatform.macOS,
109+
logPrefix: 'Test',
110+
},
111+
false,
112+
'build',
113+
mockExecutor,
114+
);
115+
116+
expect(result.content).toBeDefined();
117+
const textContent = result.content
118+
?.filter((c) => c.type === 'text')
119+
.map((c) => (c as { text: string }).text)
120+
.join('\n');
121+
expect(textContent).not.toContain('❌ Error:');
122+
expect(textContent).not.toContain('⚠️ Warning:');
123+
});
124+
125+
it('should match real xcodebuild diagnostic lines', async () => {
126+
sessionStore.setDefaults({ suppressWarnings: false });
127+
128+
const buildOutput = [
129+
"/path/to/File.swift:42:10: error: cannot find 'foo' in scope",
130+
"/path/to/File.swift:15:5: warning: unused variable 'bar'",
131+
'error: build failed',
132+
'warning: deprecated API usage',
133+
'ld: warning: directory not found for option',
134+
'clang: error: linker command failed',
135+
'fatal error: too many errors emitted',
136+
"/path/to/header.h:1:9: fatal error: 'Header.h' file not found",
137+
].join('\n');
138+
139+
const mockExecutor = createMockExecutor({
140+
success: true,
141+
output: buildOutput,
142+
error: '',
143+
exitCode: 0,
144+
});
145+
146+
const result = await executeXcodeBuildCommand(
147+
{
148+
projectPath: '/test/project.xcodeproj',
149+
scheme: 'TestScheme',
150+
configuration: 'Debug',
151+
},
152+
{
153+
platform: XcodePlatform.macOS,
154+
logPrefix: 'Test',
155+
},
156+
false,
157+
'build',
158+
mockExecutor,
159+
);
160+
161+
expect(result.content).toBeDefined();
162+
const textContent = result.content
163+
?.filter((c) => c.type === 'text')
164+
.map((c) => (c as { text: string }).text)
165+
.join('\n');
166+
expect(textContent).toContain('❌ Error:');
167+
expect(textContent).toContain('⚠️ Warning:');
168+
});
78169
});

src/utils/build-utils.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,14 @@ export async function executeXcodeBuildCommand(
6060
// Collect warnings, errors, and stderr messages from the build output
6161
const buildMessages: { type: 'text'; text: string }[] = [];
6262
function grepWarningsAndErrors(text: string): { type: 'warning' | 'error'; content: string }[] {
63+
// Require "error:"/"warning:" at line start (with optional tool prefix like "ld: ")
64+
// or after a file:line:col location prefix, to avoid false positives from source
65+
// code like "var authError: Error?" echoed during compilation.
6366
return text
6467
.split('\n')
6568
.map((content) => {
66-
if (/warning:/i.test(content)) return { type: 'warning', content };
67-
if (/error:/i.test(content)) return { type: 'error', content };
69+
if (/(?:^(?:\w+:\s+)?|:\d+:\s+)warning:\s/i.test(content)) return { type: 'warning', content };
70+
if (/(?:^(?:\w+:\s+)?|:\d+:\s+)(?:fatal )?error:\s/i.test(content)) return { type: 'error', content };
6871
return null;
6972
})
7073
.filter(Boolean) as { type: 'warning' | 'error'; content: string }[];

0 commit comments

Comments
 (0)