aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/singlejar/desugar_checking.cc
diff options
context:
space:
mode:
authorGravatar kmb <kmb@google.com>2017-10-21 04:07:24 +0200
committerGravatar Dmitry Lomov <dslomov@google.com>2017-10-23 17:16:19 +0200
commitdb1426b75d7721554a8b139696b5b4c400a260a5 (patch)
tree03d407f62851fa8e179e1f6c2745ad5826d71a4c /src/tools/singlejar/desugar_checking.cc
parent9cc97513839442ac13fe10ab84e103e127e36987 (diff)
Exclude Android dependency checking from Bazel's singlejar build.
This should also address https://github.com/bazelbuild/bazel/issues/3903 RELNOTES: None. PiperOrigin-RevId: 172963663
Diffstat (limited to 'src/tools/singlejar/desugar_checking.cc')
-rw-r--r--src/tools/singlejar/desugar_checking.cc153
1 files changed, 153 insertions, 0 deletions
diff --git a/src/tools/singlejar/desugar_checking.cc b/src/tools/singlejar/desugar_checking.cc
new file mode 100644
index 0000000000..13f45f9583
--- /dev/null
+++ b/src/tools/singlejar/desugar_checking.cc
@@ -0,0 +1,153 @@
+// Copyright 2017 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.
+
+#include "src/tools/singlejar/desugar_checking.h"
+#include "src/tools/singlejar/diag.h"
+#include "src/main/protobuf/desugar_deps.pb.h"
+
+bool Java8DesugarDepsChecker::Merge(const CDH *cdh, const LH *lh) {
+ // Throw away anything previously read, no need to concatenate
+ buffer_.reset(new TransientBytes());
+ if (Z_NO_COMPRESSION == lh->compression_method()) {
+ buffer_->ReadEntryContents(lh);
+ } else if (Z_DEFLATED == lh->compression_method()) {
+ if (!inflater_.get()) {
+ inflater_.reset(new Inflater());
+ }
+ buffer_->DecompressEntryContents(cdh, lh, inflater_.get());
+ } else {
+ errx(2, "META-INF/desugar_deps is neither stored nor deflated");
+ }
+
+ // TODO(kmb): Wrap buffer_ as ZeroCopyInputStream to avoid copying out.
+ // Note we only copy one file at a time, so overhead should be modest.
+ uint32_t checksum;
+ const size_t data_size = buffer_->data_size();
+ uint8_t *buf = reinterpret_cast<uint8_t *>(malloc(data_size));
+ buffer_->CopyOut(reinterpret_cast<uint8_t *>(buf), &checksum);
+ buffer_.reset(); // release buffer eagerly
+
+ bazel::tools::desugar::DesugarDepsInfo deps_info;
+ google::protobuf::io::CodedInputStream content(buf, data_size);
+ if (!deps_info.ParseFromCodedStream(&content)) {
+ errx(2, "META-INF/desugar_deps: unable to parse");
+ }
+ if (!content.ConsumedEntireMessage()) {
+ errx(2, "META-INF/desugar_deps: unexpected trailing content");
+ }
+ free(buf);
+
+ for (const auto &assume_present : deps_info.assume_present()) {
+ // This means we need file named <target>.class in the output. Remember
+ // the first origin of this requirement for error messages, drop others.
+ needed_deps_.emplace(assume_present.target().binary_name() + ".class",
+ assume_present.origin().binary_name());
+ }
+
+ for (const auto &missing : deps_info.missing_interface()) {
+ // Remember the first origin of this requirement for error messages, drop
+ // subsequent ones.
+ missing_interfaces_.emplace(missing.target().binary_name(),
+ missing.origin().binary_name());
+ }
+
+ for (const auto &extends : deps_info.interface_with_supertypes()) {
+ // Remember interface hierarchy the first time we see this interface, drop
+ // subsequent ones for consistency with how singlejar will keep the first
+ // occurrence of the file defining the interface. We'll lazily derive
+ // whether missing_interfaces_ inherit default methods with this data later.
+ if (extends.extended_interface_size() > 0) {
+ std::vector<std::string> extended;
+ extended.reserve(extends.extended_interface_size());
+ for (const auto &itf : extends.extended_interface()) {
+ extended.push_back(itf.binary_name());
+ }
+ extended_interfaces_.emplace(extends.origin().binary_name(),
+ std::move(extended));
+ }
+ }
+
+ for (const auto &companion : deps_info.interface_with_companion()) {
+ // Only remember interfaces that definitely have default methods for now.
+ // For all other interfaces we'll transitively check extended interfaces
+ // in HasDefaultMethods.
+ if (companion.num_default_methods() > 0) {
+ has_default_methods_[companion.origin().binary_name()] = true;
+ }
+ }
+ return true;
+}
+
+void *Java8DesugarDepsChecker::OutputEntry(bool compress) {
+ if (verbose_) {
+ fprintf(stderr, "Needed deps: %lu\n", needed_deps_.size());
+ fprintf(stderr, "Interfaces to check: %lu\n", missing_interfaces_.size());
+ fprintf(stderr, "Sub-interfaces: %lu\n", extended_interfaces_.size());
+ fprintf(stderr, "Interfaces w/ default methods: %lu\n",
+ has_default_methods_.size());
+ }
+ for (auto needed : needed_deps_) {
+ if (verbose_) {
+ fprintf(stderr, "Looking for %s\n", needed.first.c_str());
+ }
+ if (!known_member_(needed.first)) {
+ if (fail_on_error_) {
+ errx(2, "%s referenced by %s but not found. Is the former defined in "
+ "a neverlink library?",
+ needed.first.c_str(), needed.second.c_str());
+ } else {
+ error_ = true;
+ }
+ }
+ }
+
+ for (auto missing : missing_interfaces_) {
+ if (verbose_) {
+ fprintf(stderr, "Checking %s\n", missing.first.c_str());
+ }
+ if (HasDefaultMethods(missing.first)) {
+ if (fail_on_error_) {
+ errx(2, "%s needed on the classpath for desugaring %s. Please add the "
+ "missing dependency to the target containing the latter.",
+ missing.first.c_str(), missing.second.c_str());
+ } else {
+ error_ = true;
+ }
+ }
+ }
+
+ // We don't want these files in the output, just check them for consistency
+ return nullptr;
+}
+
+bool Java8DesugarDepsChecker::HasDefaultMethods(
+ const std::string &interface_name) {
+ auto cached = has_default_methods_.find(interface_name);
+ if (cached != has_default_methods_.end()) {
+ return cached->second;
+ }
+
+ // Prime with false in case there's a cycle. We'll update with the true value
+ // (ignoring the cycle) below.
+ has_default_methods_.emplace(interface_name, false);
+
+ for (const std::string &extended : extended_interfaces_[interface_name]) {
+ if (HasDefaultMethods(extended)) {
+ has_default_methods_[interface_name] = true;
+ return true;
+ }
+ }
+ has_default_methods_[interface_name] = false;
+ return false;
+}