Repository: dotnet/roslyn
File: src/Compilers/Core/MSBuildTask/ManagedCompiler.cs (C#)

Code before:
        {
            if (taskItems is null)
                return;

            foreach (var item in taskItems)
            {
                item.ItemSpec = Utilities.GetFullPathNoThrow(item.ItemSpec);
            }
        }

        /// <summary>
        /// Transforms source file paths to avoid misinterpretation as command-line switches.
        /// On Unix, source files that would be misinterpreted as options (e.g., those starting 
        /// with '/' without another '/' after the first character) are transformed to start 
        /// with '/./' to prevent them from being interpreted as switches.
        /// This uses the same heuristic as the compiler's CommandLineParser.TryParseOption.
        /// </summary>
        /// <param name="sources">The source files to transform</param>
        /// <returns>Array of source file paths as strings, or null if no transformation needed</returns>
        private string[]? GetTransformedSourcesForCommandLine(ITaskItem[]? sources)
        {
            if (sources is null || sources.Length == 0)
                return null;

            // On Windows, no transformation is needed
            if (Path.DirectorySeparatorChar == '\\')
                return null;

            // Go over sources once and lazily initialize transformedSources if needed
            string[]? transformedSources = null;
            for (int i = 0; i < sources.Length; i++)
            {
                var itemSpec = sources[i].ItemSpec;
                // Check if this path needs transformation using the compiler's heuristic:
                // A path starting with '/' is treated as an option unless it contains 
                // another '/' after the first character (e.g., "/dir/file.cs" is safe)
                if (itemSpec.Length > 1 && itemSpec[0] == '/' && itemSpec.IndexOf('/', 1) < 0)
                {
                    // Lazy initialization: create the array on first transformation
                    if (transformedSources == null)
                    {
                        transformedSources = new string[sources.Length];
                        // Copy all items processed so far
                        for (int j = 0; j < i; j++)
                        {
                            transformedSources[j] = sources[j].ItemSpec;
                        }
                    }
                    // Transform this path to prevent misinterpretation as an option
                    transformedSources[i] = "/." + itemSpec;
                }

Review comment (suggestion):
```suggestion
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
```

Believe that works across the frameworks. If not existing code is fine.

Code after:
        private void NormalizePaths(ITaskItem[]? taskItems)
        {
            if (taskItems is null)
                return;

            foreach (var item in taskItems)
            {
                item.ItemSpec = Utilities.GetFullPathNoThrow(item.ItemSpec);
            }
        }

        /// <summary>
        /// Transforms source file paths to avoid misinterpretation as command-line switches.
        /// On Unix, source files that would be misinterpreted as options (e.g., those starting 
        /// with '/' without another '/' after the first character) are transformed to start 
        /// with '/./' to prevent them from being interpreted as switches.
        /// This uses the same heuristic as the compiler's CommandLineParser.TryParseOption.
        /// </summary>
        /// <param name="sources">The source files to transform</param>
        /// <returns>Array of source file paths as strings, or null if no transformation needed</returns>
        private string[]? GetTransformedSourcesForCommandLine(ITaskItem[]? sources)
        {
            if (sources is null || sources.Length == 0)
                return null;

            // On Windows, no transformation is needed
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                return null;

            // Go over sources once and lazily initialize transformedSources if needed
            string[]? transformedSources = null;
            for (int i = 0; i < sources.Length; i++)
            {
                var itemSpec = sources[i].ItemSpec;

                // Check if this path needs transformation using the compiler's heuristic:
                // A path starting with '/' is treated as an option unless it contains 
                // another '/' after the first character (e.g., "/dir/file.cs" is safe)
                if (itemSpec.Length > 1 && itemSpec[0] == '/' && itemSpec.IndexOf('/', 1) < 0)
                {
                    // Lazy initialization: create the array on first transformation
                    if (transformedSources == null)
                    {
                        transformedSources = new string[sources.Length];
                        // Copy all items processed so far
                        for (int j = 0; j < i; j++)
                        {
                            transformedSources[j] = sources[j].ItemSpec;
                        }
                    }