| // Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| package com.android.tools.r8.utils; | |
| import com.android.tools.r8.DiagnosticsHandler; | |
| import com.android.tools.r8.SourceFileEnvironment; | |
| import com.android.tools.r8.SourceFileProvider; | |
| import com.google.common.collect.ImmutableMap; | |
| import java.util.Map; | |
| import java.util.Map.Entry; | |
| public class SourceFileTemplateProvider implements SourceFileProvider { | |
| private static final char VARIABLE_PREFIX = '%'; | |
| private static final Map<String, SourceFileProvider> HANDLERS = | |
| ImmutableMap.<String, SourceFileProvider>builder() | |
| .put(var("MAP_ID"), SourceFileEnvironment::getMapId) | |
| .put(var("MAP_HASH"), SourceFileEnvironment::getMapHash) | |
| .build(); | |
| private static String var(String name) { | |
| return VARIABLE_PREFIX + name; | |
| } | |
| private static int getMaxVariableLength() { | |
| int max = 0; | |
| for (String key : HANDLERS.keySet()) { | |
| max = Math.max(max, key.length()); | |
| } | |
| return max; | |
| } | |
| public static SourceFileProvider create(String template, DiagnosticsHandler handler) { | |
| String cleaned = template; | |
| for (String variable : HANDLERS.keySet()) { | |
| // Maintain the same size as template so indexing remains valid for error reporting. | |
| cleaned = cleaned.replace(variable, ' ' + variable.substring(1)); | |
| } | |
| assert template.length() == cleaned.length(); | |
| int unhandled = cleaned.indexOf(VARIABLE_PREFIX); | |
| if (unhandled >= 0) { | |
| while (unhandled >= 0) { | |
| int endIndex = Math.min(unhandled + getMaxVariableLength(), template.length()); | |
| String variablePrefix = template.substring(unhandled, endIndex); | |
| handler.error( | |
| new StringDiagnostic("Invalid template variable starting with " + variablePrefix)); | |
| unhandled = cleaned.indexOf(VARIABLE_PREFIX, unhandled + 1); | |
| } | |
| return null; | |
| } | |
| return new SourceFileTemplateProvider(template); | |
| } | |
| private final String template; | |
| private volatile String cachedValue = null; | |
| private SourceFileTemplateProvider(String template) { | |
| this.template = template; | |
| } | |
| @Override | |
| public String get(SourceFileEnvironment environment) { | |
| if (cachedValue == null) { | |
| synchronized (this) { | |
| if (cachedValue == null) { | |
| String temp = template; | |
| for (Entry<String, SourceFileProvider> entry : HANDLERS.entrySet()) { | |
| temp = temp.replace(entry.getKey(), entry.getValue().get(environment)); | |
| } | |
| cachedValue = temp; | |
| } | |
| } | |
| } | |
| return cachedValue; | |
| } | |
| } |