public async Task UpdateHashesAsync(IEnumerable <SonarQubeIssue> issues,
                                            ISonarQubeService sonarQubeService,
                                            CancellationToken cancellationToken)
        {
            var secondaryLocations = GetSecondaryLocations(issues);

            if (!secondaryLocations.Any())
            {
                // This will be the normal case: most issues don't have secondary locations
                return;
            }

            var uniqueKeys = GetUniqueSecondaryLocationKeys(secondaryLocations);

            var map = new ModuleKeyToSourceMap();

            foreach (var key in uniqueKeys)
            {
                var sourceCode = await sonarQubeService.GetSourceCodeAsync(key, cancellationToken);

                Debug.Assert(sourceCode != null, "Not expecting the file contents to be null");
                map.AddSourceCode(key, sourceCode);
            }

            foreach (var location in GetSecondaryLocations(issues))
            {
                SetLineHash(map, location);
            }
        }
        private void SetLineHash(ModuleKeyToSourceMap map, IssueLocation location)
        {
            // Issue locations can span multiple lines, but only the first line is used
            // when calculating the hash
            var firstLineOfIssue = map.GetLineText(location.ModuleKey, location.TextRange.StartLine);

            if (firstLineOfIssue != null)
            {
                location.Hash = checksumCalculator.Calculate(firstLineOfIssue);
            }
        }