// Copyright 2014 The Bazel Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.devtools.build.lib.packages; import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.util.Preconditions; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import javax.annotation.Nullable; /** * Checked exception for analysis-time errors, which can store the errors for later reporting. * * <p>It's more robust for a method to throw this exception than expecting a * {@link RuleErrorConsumer} object (which may be null). */ public final class AnalysisIssues extends Exception { /** * An error entry. * * <p>{@link AnalysisIssues} can accumulate multiple of these, and report all of them at once. */ public static final class Entry { private final String attribute; private final String messageTemplate; private final Object[] arguments; private Entry(@Nullable String attribute, String messageTemplate, Object... arguments) { this.attribute = attribute; this.messageTemplate = messageTemplate; this.arguments = arguments; } private void reportTo(RuleErrorConsumer errors) { String msg = String.format(messageTemplate, arguments); if (attribute == null) { errors.ruleError(msg); } else { errors.attributeError(attribute, msg); } } private void reportTo(StringBuilder sb) { String msg = String.format(messageTemplate, arguments); if (attribute == null) { sb.append("ERROR: ").append(msg); } else { sb.append("ERROR: in attribute \"").append(attribute).append("\": ").append(msg); } } @Override public String toString() { if (attribute == null) { return String.format("ERROR: " + messageTemplate, arguments); } else { List<Object> args = new ArrayList<>(); args.add(attribute); Collections.addAll(args, arguments); return String.format("ERROR in '%s': " + messageTemplate, args.toArray()); } } } private final ImmutableList<Entry> entries; public AnalysisIssues(Entry entry) { this.entries = ImmutableList.of(Preconditions.checkNotNull(entry)); } public AnalysisIssues(Collection<Entry> entries) { this.entries = ImmutableList.copyOf(Preconditions.checkNotNull(entries)); } /** * Creates a attribute error entry that will be added to a {@link AnalysisIssues} later. */ public static Entry attributeError(String attribute, String messageTemplate, Object... arguments) { return new Entry(attribute, messageTemplate, arguments); } public static Entry ruleError(String messageTemplate, Object... arguments) { return new Entry(null, messageTemplate, arguments); } /** * Report all accumulated errors and warnings to the given consumer object. */ public void reportTo(RuleErrorConsumer errors) { Preconditions.checkNotNull(errors); for (Entry e : entries) { e.reportTo(errors); } } @Nullable private String asString() { if (entries == null) { return null; } StringBuilder sb = new StringBuilder(); for (Entry e : entries) { e.reportTo(sb); } return sb.toString(); } @Override public String getMessage() { return asString(); } @Override public String toString() { String s = asString(); return s == null ? "" : s; } }