diff options
author | 2017-10-21 04:07:24 +0200 | |
---|---|---|
committer | 2017-10-23 17:16:19 +0200 | |
commit | db1426b75d7721554a8b139696b5b4c400a260a5 (patch) | |
tree | 03d407f62851fa8e179e1f6c2745ad5826d71a4c /src/tools | |
parent | 9cc97513839442ac13fe10ab84e103e127e36987 (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')
-rw-r--r-- | src/tools/singlejar/BUILD | 1 | ||||
-rw-r--r-- | src/tools/singlejar/combiners.cc | 137 | ||||
-rw-r--r-- | src/tools/singlejar/combiners.h | 57 | ||||
-rw-r--r-- | src/tools/singlejar/combiners_test.cc | 71 | ||||
-rw-r--r-- | src/tools/singlejar/desugar_checking.cc | 153 | ||||
-rw-r--r-- | src/tools/singlejar/desugar_checking.h | 85 | ||||
-rw-r--r-- | src/tools/singlejar/desugar_checking_test.cc | 102 | ||||
-rw-r--r-- | src/tools/singlejar/output_jar.cc | 11 | ||||
-rw-r--r-- | src/tools/singlejar/output_jar.h | 2 | ||||
-rw-r--r-- | src/tools/singlejar/singlejar_main.cc | 9 |
10 files changed, 353 insertions, 275 deletions
diff --git a/src/tools/singlejar/BUILD b/src/tools/singlejar/BUILD index e986ab06c6..1b0cfd2444 100644 --- a/src/tools/singlejar/BUILD +++ b/src/tools/singlejar/BUILD @@ -286,7 +286,6 @@ cc_library( ], hdrs = ["combiners.h"], deps = [ - "//src/main/protobuf:desugar_deps_cc_proto", "//third_party/zlib", ], ) diff --git a/src/tools/singlejar/combiners.cc b/src/tools/singlejar/combiners.cc index aaddd79aaa..8fd2a0fdfe 100644 --- a/src/tools/singlejar/combiners.cc +++ b/src/tools/singlejar/combiners.cc @@ -14,7 +14,6 @@ #include "src/tools/singlejar/combiners.h" #include "src/tools/singlejar/diag.h" -#include "src/main/protobuf/desugar_deps.pb.h" Combiner::~Combiner() {} @@ -175,139 +174,3 @@ PropertyCombiner::~PropertyCombiner() {} bool PropertyCombiner::Merge(const CDH *cdh, const LH *lh) { return false; // This should not be called. } - -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; -} diff --git a/src/tools/singlejar/combiners.h b/src/tools/singlejar/combiners.h index f7d4cc7be9..4963d336b3 100644 --- a/src/tools/singlejar/combiners.h +++ b/src/tools/singlejar/combiners.h @@ -136,61 +136,4 @@ class PropertyCombiner : public Concatenator { } }; -// Combiner that checks META-INF/desugar_deps files (b/65645388) to ensure -// correct bytecode desugaring, specifically of default and static interface -// methods, across an entire binary. Two checks are performed: -// 1. Make sure that any dependency assumed by the desugaring process is in -// fact part of the binary. This protects against ill-advised uses of -// neverlink, where a library is only on the compile-time classpath but not -// the runtime classpath. -// 2. To paper over incomplete classpaths during desugaring (b/65211436), check -// that interfaces that couldn't be found don't declare or inherit default -// methods. Desugar emits extra metadata to avoid us having to open up and -// parse .class files for this purpose. -class Java8DesugarDepsChecker : public Combiner { - public: - Java8DesugarDepsChecker(std::function<bool(const std::string &)> known_member, - bool verbose) - : Java8DesugarDepsChecker(std::move(known_member), verbose, true) {} - ~Java8DesugarDepsChecker() override {} - - bool Merge(const CDH *cdh, const LH *lh) override; - - void *OutputEntry(bool compress) override; - - private: - Java8DesugarDepsChecker(std::function<bool(const std::string &)> known_member, - bool verbose, bool fail_on_error) - : known_member_(std::move(known_member)), - verbose_(verbose), - fail_on_error_(fail_on_error), - error_(false) {} - /// Computes and caches whether the given interface has default methods. - /// \param interface_name interface name as it would appear in bytecode, e.g., - /// "java/lang/Runnable" - bool HasDefaultMethods(const std::string &interface_name); - - const std::function<bool(const std::string &)> known_member_; - const bool verbose_; - const bool fail_on_error_; // For testing - - std::unique_ptr<TransientBytes> buffer_; - std::unique_ptr<Inflater> inflater_; - /// Reverse mapping from needed dependencies to one of the users. - std::map<std::string, std::string> needed_deps_; - /// Reverse mapping from missing interfaces to one of the classes that missed - /// them. - std::map<std::string, std::string> missing_interfaces_; - std::unordered_map<std::string, std::vector<std::string> > - extended_interfaces_; - /// Cache of interfaces known to definitely define or inherit default methods - /// or definitely not define and not inherit default methods. Merge() - /// populates initial entries and HasDefaultMethods() adds to the cache as - /// needed. - std::unordered_map<std::string, bool> has_default_methods_; - bool error_; - - friend class CombinersTest; -}; - #endif // SRC_TOOLS_SINGLEJAR_COMBINERS_H_ diff --git a/src/tools/singlejar/combiners_test.cc b/src/tools/singlejar/combiners_test.cc index effdf265be..b1dd75f7b1 100644 --- a/src/tools/singlejar/combiners_test.cc +++ b/src/tools/singlejar/combiners_test.cc @@ -19,6 +19,8 @@ #include "src/tools/singlejar/zlib_interface.h" #include "gtest/gtest.h" +namespace { + static const char kTag1Contents[] = "<tag1>Contents1</tag1>"; static const char kTag2Contents[] = "<tag2>Contents2</tag2>"; static const char kCombinedXmlContents[] = @@ -49,67 +51,6 @@ class CombinersTest : public ::testing::Test { } return true; } - - static void TestJava8DesugarDepsChecker_HasDefaultMethods() { - Java8DesugarDepsChecker checker([](const std::string &) { return false; }, - /*verbose=*/false); - checker.has_default_methods_["a"] = true; - checker.extended_interfaces_["c"] = {"b", "a"}; - - // Induce cycle (shouldn't happen but make sure we don't crash) - checker.extended_interfaces_["d"] = {"e"}; - checker.extended_interfaces_["e"] = {"d", "a"}; - - EXPECT_TRUE(checker.HasDefaultMethods("a")); - EXPECT_FALSE(checker.HasDefaultMethods("b")); - EXPECT_TRUE(checker.HasDefaultMethods("c")); // Transitivly through a - EXPECT_TRUE(checker.HasDefaultMethods("d")); // Transitivly through a - EXPECT_FALSE(checker.error_); - } - - static void TestJava8DesugarDepsChecker_OutputEntry() { - bool checkedA = false; - Java8DesugarDepsChecker checker( - [&checkedA](const std::string &binary_name) { - checkedA = true; - return binary_name == "a$$CC.class"; - }, - /*verbose=*/false); - checker.has_default_methods_["a"] = true; - checker.extended_interfaces_["b"] = {"c", "d"}; - checker.extended_interfaces_["c"] = {"e"}; - checker.needed_deps_["a$$CC.class"] = "f"; - checker.missing_interfaces_["b"] = "g"; - EXPECT_EQ(nullptr, checker.OutputEntry(/*compress=*/true)); - EXPECT_TRUE(checkedA); - - // Make sure we checked b and its extended interfaces for default methods - EXPECT_FALSE(checker.has_default_methods_.at("b")); // should be cached - EXPECT_FALSE(checker.has_default_methods_.at("c")); // should be cached - EXPECT_FALSE(checker.has_default_methods_.at("d")); // should be cached - EXPECT_FALSE(checker.has_default_methods_.at("e")); // should be cached - EXPECT_FALSE(checker.error_); - } - - static void TestJava8DesugarDepsChecker_NeededDepMissing() { - Java8DesugarDepsChecker checker([](const std::string &) { return false; }, - /*verbose=*/false, - /*fail_on_error=*/false); - checker.needed_deps_["a$$CC.class"] = "b"; - EXPECT_EQ(nullptr, checker.OutputEntry(/*compress=*/true)); - EXPECT_TRUE(checker.error_); - } - - static void TestJava8DesugarDepsChecker_MissedDefaultMethods() { - Java8DesugarDepsChecker checker([](const std::string &) { return true; }, - /*verbose=*/false, - /*fail_on_error=*/false); - checker.has_default_methods_["b"] = true; - checker.extended_interfaces_["a"] = {"b", "a"}; - checker.missing_interfaces_["a"] = "g"; - EXPECT_EQ(nullptr, checker.OutputEntry(/*compress=*/true)); - EXPECT_TRUE(checker.error_); - } }; // Test Concatenator. @@ -305,10 +246,4 @@ TEST_F(CombinersTest, PropertyCombiner) { free(reinterpret_cast<void *>(entry)); } -TEST_F(CombinersTest, Java8DesugarDepsChecker) { - // Tests are instance methods of CombinersTest to avoid gUnit dep in .h file. - TestJava8DesugarDepsChecker_HasDefaultMethods(); - TestJava8DesugarDepsChecker_OutputEntry(); - TestJava8DesugarDepsChecker_NeededDepMissing(); - TestJava8DesugarDepsChecker_MissedDefaultMethods(); -} +} // anonymous namespace 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; +} diff --git a/src/tools/singlejar/desugar_checking.h b/src/tools/singlejar/desugar_checking.h new file mode 100644 index 0000000000..0f913a7816 --- /dev/null +++ b/src/tools/singlejar/desugar_checking.h @@ -0,0 +1,85 @@ +// 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. + +#ifndef SRC_TOOLS_SINGLEJAR_DESUGAR_CHECKING_H_ +#define SRC_TOOLS_SINGLEJAR_DESUGAR_CHECKING_H_ 1 + +#include <functional> +#include <map> +#include <string> +#include <unordered_map> +#include <vector> + +#include "src/tools/singlejar/combiners.h" +#include "src/tools/singlejar/transient_bytes.h" +#include "src/tools/singlejar/zip_headers.h" + +// Combiner that checks META-INF/desugar_deps files (b/65645388) to ensure +// correct bytecode desugaring, specifically of default and static interface +// methods, across an entire binary. Two checks are performed: +// 1. Make sure that any dependency assumed by the desugaring process is in +// fact part of the binary. This protects against ill-advised uses of +// neverlink, where a library is only on the compile-time classpath but not +// the runtime classpath. +// 2. To paper over incomplete classpaths during desugaring (b/65211436), check +// that interfaces that couldn't be found don't declare or inherit default +// methods. Desugar emits extra metadata to avoid us having to open up and +// parse .class files for this purpose. +class Java8DesugarDepsChecker : public Combiner { + public: + Java8DesugarDepsChecker(std::function<bool (const std::string&)> known_member, + bool verbose) + : Java8DesugarDepsChecker(std::move(known_member), verbose, true) {} + ~Java8DesugarDepsChecker() override {} + + bool Merge(const CDH *cdh, const LH *lh) override; + + void *OutputEntry(bool compress) override; + + private: + Java8DesugarDepsChecker(std::function<bool (const std::string&)> known_member, + bool verbose, bool fail_on_error) + : known_member_(std::move(known_member)), + verbose_(verbose), + fail_on_error_(fail_on_error), + error_(false) {} + /// Computes and caches whether the given interface has default methods. + /// \param interface_name interface name as it would appear in bytecode, e.g., + /// "java/lang/Runnable" + bool HasDefaultMethods(const std::string &interface_name); + + const std::function<bool (const std::string&)> known_member_; + const bool verbose_; + const bool fail_on_error_; // For testing + + std::unique_ptr<TransientBytes> buffer_; + std::unique_ptr<Inflater> inflater_; + /// Reverse mapping from needed dependencies to one of the users. + std::map<std::string, std::string> needed_deps_; + /// Reverse mapping from missing interfaces to one of the classes that missed + /// them. + std::map<std::string, std::string> missing_interfaces_; + std::unordered_map<std::string, std::vector<std::string> > + extended_interfaces_; + /// Cache of interfaces known to definitely define or inherit default methods + /// or definitely not define and not inherit default methods. Merge() + /// populates initial entries and HasDefaultMethods() adds to the cache as + /// needed. + std::unordered_map<std::string, bool> has_default_methods_; + bool error_; + + friend class Java8DesugarDepsCheckerTest; +}; + +#endif // SRC_TOOLS_SINGLEJAR_DESUGAR_CHECKING_H_ diff --git a/src/tools/singlejar/desugar_checking_test.cc b/src/tools/singlejar/desugar_checking_test.cc new file mode 100644 index 0000000000..faa6686178 --- /dev/null +++ b/src/tools/singlejar/desugar_checking_test.cc @@ -0,0 +1,102 @@ +// 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/input_jar.h" +#include "src/tools/singlejar/zip_headers.h" +#include "src/tools/singlejar/zlib_interface.h" +#include "gtest/gtest.h" + +// A test fixture is used because friend access to class under test is needed. +// Tests are instance methods to avoid gUnit dep in .h file. +class Java8DesugarDepsCheckerTest : public ::testing::Test { + protected: + static void TestHasDefaultMethods() { + Java8DesugarDepsChecker checker([](const std::string &) { return false; }, + /*verbose=*/false); + checker.has_default_methods_["a"] = true; + checker.extended_interfaces_["c"] = {"b", "a"}; + + // Induce cycle (shouldn't happen but make sure we don't crash) + checker.extended_interfaces_["d"] = {"e"}; + checker.extended_interfaces_["e"] = {"d", "a"}; + + EXPECT_TRUE(checker.HasDefaultMethods("a")); + EXPECT_FALSE(checker.HasDefaultMethods("b")); + EXPECT_TRUE(checker.HasDefaultMethods("c")); // Transitivly through a + EXPECT_TRUE(checker.HasDefaultMethods("d")); // Transitivly through a + EXPECT_FALSE(checker.error_); + } + + static void TestOutputEntry() { + bool checkedA = false; + Java8DesugarDepsChecker checker( + [&checkedA](const std::string &binary_name) { + checkedA = true; + return binary_name == "a$$CC.class"; + }, + /*verbose=*/false); + checker.has_default_methods_["a"] = true; + checker.extended_interfaces_["b"] = {"c", "d"}; + checker.extended_interfaces_["c"] = {"e"}; + checker.needed_deps_["a$$CC.class"] = "f"; + checker.missing_interfaces_["b"] = "g"; + EXPECT_EQ(nullptr, checker.OutputEntry(/*compress=*/true)); + EXPECT_TRUE(checkedA); + + // Make sure we checked b and its extended interfaces for default methods + EXPECT_FALSE(checker.has_default_methods_.at("b")); // should be cached + EXPECT_FALSE(checker.has_default_methods_.at("c")); // should be cached + EXPECT_FALSE(checker.has_default_methods_.at("d")); // should be cached + EXPECT_FALSE(checker.has_default_methods_.at("e")); // should be cached + EXPECT_FALSE(checker.error_); + } + + static void TestNeededDepMissing() { + Java8DesugarDepsChecker checker([](const std::string &) { return false; }, + /*verbose=*/false, + /*fail_on_error=*/false); + checker.needed_deps_["a$$CC.class"] = "b"; + EXPECT_EQ(nullptr, checker.OutputEntry(/*compress=*/true)); + EXPECT_TRUE(checker.error_); + } + + static void TestMissedDefaultMethods() { + Java8DesugarDepsChecker checker([](const std::string &) { return true; }, + /*verbose=*/false, + /*fail_on_error=*/false); + checker.has_default_methods_["b"] = true; + checker.extended_interfaces_["a"] = {"b", "a"}; + checker.missing_interfaces_["a"] = "g"; + EXPECT_EQ(nullptr, checker.OutputEntry(/*compress=*/true)); + EXPECT_TRUE(checker.error_); + } +}; + +TEST_F(Java8DesugarDepsCheckerTest, HasDefaultMethods) { + TestHasDefaultMethods(); +} + +TEST_F(Java8DesugarDepsCheckerTest, OutputEntry) { + TestOutputEntry(); +} + +TEST_F(Java8DesugarDepsCheckerTest, NeededDepMissing) { + TestNeededDepMissing(); +} + +TEST_F(Java8DesugarDepsCheckerTest, MissingDefaultMethods) { + TestMissedDefaultMethods(); +} diff --git a/src/tools/singlejar/output_jar.cc b/src/tools/singlejar/output_jar.cc index 3674d27aee..df158749a6 100644 --- a/src/tools/singlejar/output_jar.cc +++ b/src/tools/singlejar/output_jar.cc @@ -89,17 +89,6 @@ int OutputJar::Doit(Options *options) { EntryInfo{&build_properties_}); } - // Process or drop Java 8 desugaring metadata, see b/65645388. We don't want - // or need these files afterwards so make sure we drop them either way. - Combiner *desugar_checker = options_->check_desugar_deps - ? new Java8DesugarDepsChecker( - [this](const std::string &filename) { - return !NewEntry(filename); - }, - options_->verbose) - : (Combiner *)new NullCombiner(); - ExtraCombiner("META-INF/desugar_deps", desugar_checker); - build_properties_.AddProperty("build.target", options_->output_jar.c_str()); if (options_->verbose) { fprintf(stderr, "combined_file_name=%s\n", options_->output_jar.c_str()); diff --git a/src/tools/singlejar/output_jar.h b/src/tools/singlejar/output_jar.h index 58ae09150a..5917c864e1 100644 --- a/src/tools/singlejar/output_jar.h +++ b/src/tools/singlejar/output_jar.h @@ -34,7 +34,7 @@ class OutputJar { // Constructor. OutputJar(); // Do all that needs to be done. Can be called only once. - int Doit(Options *options); + virtual int Doit(Options *options); // Destructor. virtual ~OutputJar(); // Add a combiner to handle the entries with given name. OutputJar will diff --git a/src/tools/singlejar/singlejar_main.cc b/src/tools/singlejar/singlejar_main.cc index 12c52aa094..bc7100f55b 100644 --- a/src/tools/singlejar/singlejar_main.cc +++ b/src/tools/singlejar/singlejar_main.cc @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "src/tools/singlejar/combiners.h" +#include "src/tools/singlejar/diag.h" #include "src/tools/singlejar/options.h" #include "src/tools/singlejar/output_jar.h" @@ -19,5 +21,12 @@ int main(int argc, char *argv[]) { Options options; options.ParseCommandLine(argc - 1, argv + 1); OutputJar output_jar; + // TODO(b/67733424): support desugar deps checking in Bazel + if (options.check_desugar_deps) { + diag_errx(1, "%s:%d: Desugar checking not currently supported in Bazel.", + __FILE__, __LINE__); + } else { + output_jar.ExtraCombiner("META-INF/desugar_deps", new NullCombiner()); + } return output_jar.Doit(&options); } |