public QueryMetadata parse(String queryString) {
        if (Strings.isNullOrEmpty(queryString)) {
            return QueryMetadata.empty();
        }

        Map<String, List<SubstringMultilinePosition>> positions = new LinkedHashMap<>();

        final String[] lines = queryString.split("\n");

        for (int line = 0; line < lines.length; line++) {
            final String currentLine = lines[line];
            final Matcher matcher = PLACEHOLDER_PATTERN.matcher(currentLine);
            while (matcher.find()) {
                final String name = matcher.group(1);
                if (!positions.containsKey(name)) {
                    positions.put(name, new ArrayList<>());
                }
                positions.get(name).add(SubstringMultilinePosition.create(line + 1, matcher.start(), matcher.end()));
            }
        }
        final ImmutableSet<QueryParam> params = positions.entrySet().stream()
                .map(entry -> QueryParam.create(entry.getKey(), entry.getValue()))
                .collect(ImmutableSet.toImmutableSet());

        return QueryMetadata.builder()
                .usedParameters(params)
                .build();
    }
@Test
    void testRepeatedParamUsage() {
        assertThat(parse("foo:$bar$ AND lorem:$bar")).containsExactly("bar");
    }