diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/aapt2/Android.bp | 1 | ||||
| -rw-r--r-- | tools/aapt2/ResourceParser.cpp | 11 | ||||
| -rw-r--r-- | tools/aapt2/ResourceParser_test.cpp | 5 | ||||
| -rw-r--r-- | tools/aapt2/ResourceTable.cpp | 14 | ||||
| -rw-r--r-- | tools/aapt2/ResourceTable.h | 6 | ||||
| -rw-r--r-- | tools/aapt2/ResourceValues.cpp | 4 | ||||
| -rw-r--r-- | tools/aapt2/ResourceValues_test.cpp | 52 | ||||
| -rw-r--r-- | tools/aapt2/link/TableMerger.cpp | 10 | ||||
| -rw-r--r-- | tools/aapt2/link/TableMerger_test.cpp | 56 | ||||
| -rwxr-xr-x | tools/apilint/apilint | 147 | ||||
| -rw-r--r-- | tools/apilint/apilint.py | 57 | ||||
| -rw-r--r-- | tools/apilint/apilint_test.py | 18 | ||||
| -rw-r--r-- | tools/bit/main.cpp | 10 | ||||
| -rw-r--r-- | tools/incident_section_gen/main.cpp | 7 |
14 files changed, 367 insertions, 31 deletions
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp index 326c88d47064..53372bff3e67 100644 --- a/tools/aapt2/Android.bp +++ b/tools/aapt2/Android.bp @@ -41,6 +41,7 @@ cc_defaults { windows: { enabled: true, cflags: ["-Wno-maybe-uninitialized"], + ldflags: ["-static"], }, darwin: { cflags: ["-D_DARWIN_UNLIMITED_STREAMS"], diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index fe401e22c50e..45cea8190844 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -693,7 +693,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, // If the resource type was not recognized, write the error and return false. diag_->Error(DiagMessage(out_resource->source) - << "unknown resource type '" << parser->element_name() << "'"); + << "unknown resource type '" << resource_type << "'"); return false; } @@ -1712,7 +1712,14 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser, child_ref.SetSource(item_source); styleable->entries.push_back(std::move(child_ref)); - out_resource->child_resources.push_back(std::move(child_resource)); + // Do not add referenced attributes that do not define a format to the table. + CHECK(child_resource.value != nullptr); + Attribute* attr = ValueCast<Attribute>(child_resource.value.get()); + + CHECK(attr != nullptr); + if (attr->type_mask != android::ResTable_map::TYPE_ANY) { + out_resource->child_resources.push_back(std::move(child_resource)); + } } else if (!ShouldIgnoreElement(element_namespace, element_name)) { diag_->Error(DiagMessage(item_source) << "unknown tag <" diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp index 7c8b6d054cd5..464225fefb85 100644 --- a/tools/aapt2/ResourceParser_test.cpp +++ b/tools/aapt2/ResourceParser_test.cpp @@ -341,7 +341,7 @@ TEST_F(ResourceParserTest, ParseAttrAndDeclareStyleableUnderConfigButRecordAsNoC std::string input = R"( <attr name="foo" /> <declare-styleable name="bar"> - <attr name="baz" /> + <attr name="baz" format="reference"/> </declare-styleable>)"; ASSERT_TRUE(TestParse(input, watch_config)); @@ -589,8 +589,7 @@ TEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) { EXPECT_THAT(result.value().entry->visibility.level, Eq(Visibility::Level::kPublic)); Attribute* attr = test::GetValue<Attribute>(&table_, "attr/bar"); - ASSERT_THAT(attr, NotNull()); - EXPECT_TRUE(attr->IsWeak()); + ASSERT_THAT(attr, IsNull()); attr = test::GetValue<Attribute>(&table_, "attr/bat"); ASSERT_THAT(attr, NotNull()); diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp index 1773b5a8addf..836e199593fc 100644 --- a/tools/aapt2/ResourceTable.cpp +++ b/tools/aapt2/ResourceTable.cpp @@ -267,7 +267,8 @@ bool ResourceEntry::HasDefaultValue() const { // A DECL will override a USE without error. Two DECLs must match in their format for there to be // no error. ResourceTable::CollisionResult ResourceTable::ResolveValueCollision(Value* existing, - Value* incoming) { + Value* incoming, + bool overlay) { Attribute* existing_attr = ValueCast<Attribute>(existing); Attribute* incoming_attr = ValueCast<Attribute>(incoming); if (!incoming_attr) { @@ -281,7 +282,7 @@ ResourceTable::CollisionResult ResourceTable::ResolveValueCollision(Value* exist } // The existing and incoming values are strong, this is an error // if the values are not both attributes. - return CollisionResult::kConflict; + return overlay ? CollisionResult::kTakeNew : CollisionResult::kConflict; } if (!existing_attr) { @@ -292,7 +293,7 @@ ResourceTable::CollisionResult ResourceTable::ResolveValueCollision(Value* exist } // The existing value is not an attribute and it is strong, // so the incoming attribute value is an error. - return CollisionResult::kConflict; + return overlay ? CollisionResult::kTakeNew : CollisionResult::kConflict; } CHECK(incoming_attr != nullptr && existing_attr != nullptr); @@ -323,8 +324,9 @@ ResourceTable::CollisionResult ResourceTable::ResolveValueCollision(Value* exist return CollisionResult::kConflict; } -ResourceTable::CollisionResult ResourceTable::IgnoreCollision(Value* /** existing **/, - Value* /** incoming **/) { +ResourceTable::CollisionResult ResourceTable::IgnoreCollision(Value* /* existing */, + Value* /* incoming */, + bool /* overlay */) { return CollisionResult::kKeepBoth; } @@ -440,7 +442,7 @@ bool ResourceTable::AddResourceImpl(const ResourceNameRef& name, const ResourceI // Resource does not exist, add it now. config_value->value = std::move(value); } else { - switch (conflict_resolver(config_value->value.get(), value.get())) { + switch (conflict_resolver(config_value->value.get(), value.get(), false /* overlay */)) { case CollisionResult::kKeepBoth: // Insert the value ignoring for duplicate configurations entry->values.push_back(util::make_unique<ResourceConfigValue>(config, product)); diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h index 30ba1aed25f8..e8793800b148 100644 --- a/tools/aapt2/ResourceTable.h +++ b/tools/aapt2/ResourceTable.h @@ -228,13 +228,13 @@ class ResourceTable { enum class CollisionResult { kKeepBoth, kKeepOriginal, kConflict, kTakeNew }; - using CollisionResolverFunc = std::function<CollisionResult(Value*, Value*)>; + using CollisionResolverFunc = std::function<CollisionResult(Value*, Value*, bool)>; // When a collision of resources occurs, this method decides which value to keep. - static CollisionResult ResolveValueCollision(Value* existing, Value* incoming); + static CollisionResult ResolveValueCollision(Value* existing, Value* incoming, bool overlay); // When a collision of resources occurs, this method keeps both values - static CollisionResult IgnoreCollision(Value* existing, Value* incoming); + static CollisionResult IgnoreCollision(Value* existing, Value* incoming, bool overlay); bool AddResource(const ResourceNameRef& name, const android::ConfigDescription& config, const android::StringPiece& product, std::unique_ptr<Value> value, diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp index 34b46c552e0c..696012786e6d 100644 --- a/tools/aapt2/ResourceValues.cpp +++ b/tools/aapt2/ResourceValues.cpp @@ -574,6 +574,10 @@ bool Attribute::Equals(const Value* value) const { } bool Attribute::IsCompatibleWith(const Attribute& attr) const { + if (Equals(&attr)) { + return true; + } + // If the high bits are set on any of these attribute type masks, then they are incompatible. // We don't check that flags and enums are identical. if ((type_mask & ~android::ResTable_map::TYPE_ANY) != 0 || diff --git a/tools/aapt2/ResourceValues_test.cpp b/tools/aapt2/ResourceValues_test.cpp index c4a1108ac62a..dbf51143f720 100644 --- a/tools/aapt2/ResourceValues_test.cpp +++ b/tools/aapt2/ResourceValues_test.cpp @@ -284,8 +284,58 @@ TEST(ResourcesValuesTest, AttributeIsCompatible) { EXPECT_FALSE(attr_three.IsCompatibleWith(attr_one)); EXPECT_FALSE(attr_three.IsCompatibleWith(attr_two)); - EXPECT_FALSE(attr_three.IsCompatibleWith(attr_three)); + EXPECT_TRUE(attr_three.IsCompatibleWith(attr_three)); EXPECT_FALSE(attr_three.IsCompatibleWith(attr_four)); + + EXPECT_FALSE(attr_four.IsCompatibleWith(attr_one)); + EXPECT_FALSE(attr_four.IsCompatibleWith(attr_two)); + EXPECT_FALSE(attr_four.IsCompatibleWith(attr_three)); + EXPECT_TRUE(attr_four.IsCompatibleWith(attr_four)); +} + +TEST(ResourcesValuesTest, AttributeEnumIsCompatible) { + Attribute attr_one(TYPE_ENUM); + attr_one.symbols.push_back( + Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u}); + attr_one.symbols.push_back( + Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bar")), 0x07u}); + + Attribute attr_two(TYPE_ENUM); + attr_two.symbols.push_back( + Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u}); + attr_two.symbols.push_back( + Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bar")), 0x07u}); + EXPECT_TRUE(attr_one.IsCompatibleWith(attr_two)); +} + +TEST(ResourcesValuesTest, DifferentAttributeEnumDifferentNameIsNotCompatible) { + Attribute attr_one(TYPE_ENUM); + attr_one.symbols.push_back( + Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u}); + attr_one.symbols.push_back( + Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bar")), 0x07u}); + + Attribute attr_two(TYPE_ENUM); + attr_two.symbols.push_back( + Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u}); + attr_one.symbols.push_back( + Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/baz")), 0x07u}); + EXPECT_FALSE(attr_one.IsCompatibleWith(attr_two)); +} + +TEST(ResourcesValuesTest, DifferentAttributeEnumDifferentValueIsNotCompatible) { + Attribute attr_one(TYPE_ENUM); + attr_one.symbols.push_back( + Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u}); + attr_one.symbols.push_back( + Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bar")), 0x07u}); + + Attribute attr_two(TYPE_ENUM); + attr_two.symbols.push_back( + Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/foo")), 0x01u}); + attr_two.symbols.push_back( + Attribute::Symbol{Reference(test::ParseNameOrDie("android:id/bar")), 0x09u}); + EXPECT_FALSE(attr_one.IsCompatibleWith(attr_two)); } } // namespace aapt diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp index c0802e60103a..3f65e868505d 100644 --- a/tools/aapt2/link/TableMerger.cpp +++ b/tools/aapt2/link/TableMerger.cpp @@ -188,7 +188,7 @@ static ResourceTable::CollisionResult ResolveMergeCollision(Value* existing, Val } } // Delegate to the default handler. - return ResourceTable::ResolveValueCollision(existing, incoming); + return ResourceTable::ResolveValueCollision(existing, incoming, true /* overlay */); } static ResourceTable::CollisionResult MergeConfigValue(IAaptContext* context, @@ -206,15 +206,11 @@ static ResourceTable::CollisionResult MergeConfigValue(IAaptContext* context, if (overlay) { collision_result = ResolveMergeCollision(dst_value, src_value, pool); } else { - collision_result = ResourceTable::ResolveValueCollision(dst_value, src_value); + collision_result = ResourceTable::ResolveValueCollision(dst_value, src_value, + false /* overlay */); } if (collision_result == CollisionResult::kConflict) { - if (overlay) { - return CollisionResult::kTakeNew; - } - - // Error! context->GetDiagnostics()->Error(DiagMessage(src_value->GetSource()) << "resource '" << res_name << "' has a conflicting value for " << "configuration (" << src_config_value->config << ")"); diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp index 9dd31e682937..78d42a160e21 100644 --- a/tools/aapt2/link/TableMerger_test.cpp +++ b/tools/aapt2/link/TableMerger_test.cpp @@ -352,6 +352,62 @@ TEST_F(TableMergerTest, MergeAddResourceFromOverlayWithAutoAddOverlay) { ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/)); } +TEST_F(TableMergerTest, OverrideAttributeSameFormatsWithOverlay) { + std::unique_ptr<ResourceTable> base = + test::ResourceTableBuilder() + .SetPackageId("", 0x7f) + .AddValue("attr/foo", test::AttributeBuilder() + .SetTypeMask(android::ResTable_map::TYPE_STRING) + .SetWeak(false) + .Build()) + .Build(); + + std::unique_ptr<ResourceTable> overlay = + test::ResourceTableBuilder() + .SetPackageId("", 0x7f) + .AddValue("attr/foo", test::AttributeBuilder() + .SetTypeMask(android::ResTable_map::TYPE_STRING) + .SetWeak(false) + .Build()) + .Build(); + + ResourceTable final_table; + TableMergerOptions options; + options.auto_add_overlay = false; + TableMerger merger(context_.get(), &final_table, options); + + ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/)); + ASSERT_TRUE(merger.Merge({}, overlay.get(), true /*overlay*/)); +} + +TEST_F(TableMergerTest, FailToOverrideConflictingAttributeFormatsWithOverlay) { + std::unique_ptr<ResourceTable> base = + test::ResourceTableBuilder() + .SetPackageId("", 0x7f) + .AddValue("attr/foo", test::AttributeBuilder() + .SetTypeMask(android::ResTable_map::TYPE_ANY) + .SetWeak(false) + .Build()) + .Build(); + + std::unique_ptr<ResourceTable> overlay = + test::ResourceTableBuilder() + .SetPackageId("", 0x7f) + .AddValue("attr/foo", test::AttributeBuilder() + .SetTypeMask(android::ResTable_map::TYPE_STRING) + .SetWeak(false) + .Build()) + .Build(); + + ResourceTable final_table; + TableMergerOptions options; + options.auto_add_overlay = false; + TableMerger merger(context_.get(), &final_table, options); + + ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/)); + ASSERT_FALSE(merger.Merge({}, overlay.get(), true /*overlay*/)); +} + TEST_F(TableMergerTest, FailToMergeNewResourceWithoutAutoAddOverlay) { std::unique_ptr<ResourceTable> table_a = test::ResourceTableBuilder().SetPackageId("", 0x7f).Build(); diff --git a/tools/apilint/apilint b/tools/apilint/apilint new file mode 100755 index 000000000000..e42857f1a190 --- /dev/null +++ b/tools/apilint/apilint @@ -0,0 +1,147 @@ +#!/bin/bash + +# Copyright (C) 2019 The Android Open Source Project +# +# 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. + +if [ "$1" == "--help" -o "$1" == "-h" ]; then +echo "Usage: apilint [FILTERS...]" +echo " Shows lint from currently open files (as diffed from HEAD), i.e. errors" +echo " you will receive if you upload this CL." +echo +echo "Usage: apilint --all [FILTERS...]" +echo " Shows all lint errors present in the current working directory, regardless" +echo " of when they were added." +echo +echo "Usage: apilint --level API_LEVEL [FILTERS...]" +echo " Shows lint as it stands in API_LEVEL" +echo +echo "Usage: apilint --shal SHA [FILTERS...]" +echo " Shows lint from locally commited git change SHA." +echo +echo "Usage: apilint --unreleased [FILTERS...]" +echo " Shows all lint errors in the current working directory directory added since" +echo " the last released SDK version." +echo +echo "FILTERS" +echo " List of class or package names by which to filter the results." +echo +exit +fi + +if [ \( -z "$ANDROID_BUILD_TOP" \) \ + -a \( ! -f frameworks/base/api/current.txt \) \ + -a \( ! -f frameworks/base/api/system-current.txt \) \ + ]; then + echo "apilint must be run either with ANDROID_BUILD_TOP set or from the" 1>&2 + echo "root of the android source tree" 1>&2 + exit 1 +fi + +if [ ${ANDROID_BUILD_TOP:0:1} != "/" ]; then + echo "ANDROID_BUILD_TOP must be an absolute path, not: $ANDROID_BUILD_TOP" 1>&2 + exit 1 +fi + +if [ -z "$ANDROID_BUILD_TOP" ]; then + ANDROID_BUILD_TOP=$(pwd) +fi + +FW_BASE=$ANDROID_BUILD_TOP/frameworks/base + +MODE=open + +OPTIONS=$(getopt -n apilint -o "" -l "all,sha:,unreleased" -- "$@") + +[ $? -eq 0 ] || { + exit 1 +} + +eval set -- "$OPTIONS" +while true; do + case "$1" in + --all) + MODE=all + ;; + --sha) + shift; # The arg is next in position args + MODE=sha + SHA=$1 + ;; + --unreleased) + MODE=unreleased + ;; + --) + shift + break + ;; + esac + shift +done +FILTERS= +for var in "$@" +do + FILTERS="$FILTERS --filter $var" +done + +if [ $MODE = "all" ]; then + python2.7 -B $ANDROID_BUILD_TOP/frameworks/base/tools/apilint/apilint.py \ + --title "SDK" \ + $FILTERS \ + $ANDROID_BUILD_TOP/frameworks/base/api/current.txt + python2.7 -B $ANDROID_BUILD_TOP/frameworks/base/tools/apilint/apilint.py \ + --title "SystemApi" \ + $FILTERS \ + --base-current $ANDROID_BUILD_TOP/frameworks/base/api/current.txt \ + $ANDROID_BUILD_TOP/frameworks/base/api/system-current.txt +elif [ $MODE = "open" ]; then + python2.7 -B $ANDROID_BUILD_TOP/frameworks/base/tools/apilint/apilint.py \ + --title "SDK" \ + $FILTERS \ + $ANDROID_BUILD_TOP/frameworks/base/api/current.txt \ + <(cd $FW_BASE ; git show HEAD:api/current.txt) + python2.7 -B $ANDROID_BUILD_TOP/frameworks/base/tools/apilint/apilint.py \ + --title "SystemApi" \ + $FILTERS \ + --base-current $ANDROID_BUILD_TOP/frameworks/base/api/current.txt \ + --base-previous <(cd $FW_BASE ; git show HEAD:api/current.txt) \ + $ANDROID_BUILD_TOP/frameworks/base/api/system-current.txt \ + <(cd $FW_BASE ; git show HEAD:api/system-current.txt) +elif [ $MODE = "sha" ]; then + python2.7 -B $ANDROID_BUILD_TOP/frameworks/base/tools/apilint/apilint.py \ + --title "SDK" \ + $FILTERS \ + <(cd $FW_BASE ; git show $SHA:api/current.txt) \ + <(cd $FW_BASE ; git show $SHA^:api/current.txt) + python2.7 -B $ANDROID_BUILD_TOP/frameworks/base/tools/apilint/apilint.py \ + --title "SystemApi" \ + $FILTERS \ + --base-current <(cd $FW_BASE ; git show $SHA:api/current.txt) \ + --base-previous <(cd $FW_BASE ; git show $SHA^:api/current.txt) \ + <(cd $FW_BASE ; git show $SHA:api/system-current.txt) \ + <(cd $FW_BASE ; git show $SHA^:api/system-current.txt) +elif [ $MODE = "unreleased" ]; then + LAST_SDK=$(ls $ANDROID_BUILD_TOP/prebuilts/sdk | grep "^[0-9][0-9]*$" | sort -n | tail -n 1) + python2.7 -B $ANDROID_BUILD_TOP/frameworks/base/tools/apilint/apilint.py \ + --title "SDK" \ + $FILTERS \ + $ANDROID_BUILD_TOP/frameworks/base/api/current.txt \ + $ANDROID_BUILD_TOP/prebuilts/sdk/$LAST_SDK/public/api/android.txt + python2.7 -B $ANDROID_BUILD_TOP/frameworks/base/tools/apilint/apilint.py \ + --title "SystemApi" \ + $FILTERS \ + --base-current $ANDROID_BUILD_TOP/frameworks/base/api/current.txt \ + --base-previous $ANDROID_BUILD_TOP/prebuilts/sdk/$LAST_SDK/public/api/android.txt \ + $ANDROID_BUILD_TOP/frameworks/base/api/system-current.txt \ + $ANDROID_BUILD_TOP/prebuilts/sdk/$LAST_SDK/system/api/android.txt +fi diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py index 97ca6dc7bf34..9e42c044e209 100644 --- a/tools/apilint/apilint.py +++ b/tools/apilint/apilint.py @@ -707,6 +707,7 @@ def _yield_until_matching_class(classes, needle): class Failure(): def __init__(self, sig, clazz, detail, error, rule, msg): + self.clazz = clazz self.sig = sig self.error = error self.rule = rule @@ -2126,12 +2127,25 @@ def verify_compat(cur, prev): return failures +def match_filter(filters, fullname): + for f in filters: + if fullname == f: + return True + if fullname.startswith(f + '.'): + return True + return False + + def show_deprecations_at_birth(cur, prev): """Show API deprecations at birth.""" global failures # Remove all existing things so we're left with new for prev_clazz in prev.values(): + if prev_clazz.fullname not in cur: + # The class was removed this release; we can safely ignore it. + continue + cur_clazz = cur[prev_clazz.fullname] if not is_interesting(cur_clazz): continue @@ -2195,12 +2209,9 @@ def show_stats(cur, prev): print " ", "".join([ str(stats[k]).ljust(20) for k in sorted(stats.keys()) ]) -if __name__ == "__main__": +def main(): parser = argparse.ArgumentParser(description="Enforces common Android public API design \ patterns. It ignores lint messages from a previous API level, if provided.") - parser.add_argument("current.txt", type=argparse.FileType('r'), help="current.txt") - parser.add_argument("previous.txt", nargs='?', type=argparse.FileType('r'), default=None, - help="previous.txt") parser.add_argument("--base-current", nargs='?', type=argparse.FileType('r'), default=None, help="The base current.txt to use when examining system-current.txt or" " test-current.txt") @@ -2209,6 +2220,8 @@ if __name__ == "__main__": " test-previous.txt") parser.add_argument("--no-color", action='store_const', const=True, help="Disable terminal colors") + parser.add_argument("--color", action='store_const', const=True, + help="Use terminal colors") parser.add_argument("--allow-google", action='store_const', const=True, help="Allow references to Google") parser.add_argument("--show-noticed", action='store_const', const=True, @@ -2217,10 +2230,21 @@ if __name__ == "__main__": help="Show API deprecations at birth") parser.add_argument("--show-stats", action='store_const', const=True, help="Show API stats") + parser.add_argument("--title", action='store', default=None, + help="Title to put in for display purposes") + parser.add_argument("--filter", action="append", + help="If provided, only show lint for the given packages or classes.") + parser.add_argument("current.txt", type=argparse.FileType('r'), help="current.txt") + parser.add_argument("previous.txt", nargs='?', type=argparse.FileType('r'), default=None, + help="previous.txt") args = vars(parser.parse_args()) if args['no_color']: USE_COLOR = False + elif args['color']: + USE_COLOR = True + else: + USE_COLOR = sys.stdout.isatty() if args['allow_google']: ALLOW_GOOGLE = True @@ -2229,6 +2253,12 @@ if __name__ == "__main__": base_current_file = args['base_current'] previous_file = args['previous.txt'] base_previous_file = args['base_previous'] + filters = args['filter'] + if not filters: + filters = [] + title = args['title'] + if not title: + title = current_file.name if args['show_deprecations_at_birth']: with current_file as f: @@ -2286,6 +2316,11 @@ if __name__ == "__main__": print """ + # ignore everything but the given filters, if provided + if filters: + cur_fail = dict([(key, failure) for key, failure in cur_fail.iteritems() + if match_filter(filters, failure.clazz.fullname)]) + if args['show_noticed'] and len(cur_noticed) != 0: print "%s API changes noticed %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True))) for f in sorted(cur_noticed.keys()): @@ -2293,8 +2328,20 @@ if __name__ == "__main__": print if len(cur_fail) != 0: - print "%s API style issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True))) + print "%s API style issues: %s %s" % ((format(fg=WHITE, bg=BLUE, bold=True), + title, format(reset=True))) + for f in filters: + print "%s filter: %s %s" % ((format(fg=WHITE, bg=BLUE, bold=True), + f, format(reset=True))) + print for f in sorted(cur_fail): print cur_fail[f] print + print "%d errors" % len(cur_fail) sys.exit(77) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + sys.exit(1) diff --git a/tools/apilint/apilint_test.py b/tools/apilint/apilint_test.py index 5cb43db0b00d..811cb9aa23d5 100644 --- a/tools/apilint/apilint_test.py +++ b/tools/apilint/apilint_test.py @@ -392,5 +392,23 @@ class PackageTests(unittest.TestCase): p = self._package("package @Rt(a.b.L_G_P) @RestrictTo(a.b.C) an.pref.int {") self.assertEquals('an.pref.int', p.name) +class FilterTests(unittest.TestCase): + def test_filter_match_prefix(self): + self.assertTrue(apilint.match_filter(["a"], "a.B")) + self.assertTrue(apilint.match_filter(["a.B"], "a.B.C")) + + def test_filter_dont_match_prefix(self): + self.assertFalse(apilint.match_filter(["c"], "a.B")) + self.assertFalse(apilint.match_filter(["a."], "a.B")) + self.assertFalse(apilint.match_filter(["a.B."], "a.B.C")) + + def test_filter_match_exact(self): + self.assertTrue(apilint.match_filter(["a.B"], "a.B")) + + def test_filter_dont_match_exact(self): + self.assertFalse(apilint.match_filter([""], "a.B")) + self.assertFalse(apilint.match_filter(["a.C"], "a.B")) + self.assertFalse(apilint.match_filter(["a.C"], "a.B")) + if __name__ == "__main__": unittest.main() diff --git a/tools/bit/main.cpp b/tools/bit/main.cpp index 1a91f52bc6cf..d80c2e742fae 100644 --- a/tools/bit/main.cpp +++ b/tools/bit/main.cpp @@ -290,8 +290,14 @@ TestResults::OnTestStatus(TestStatus& status) m_currentAction->target->name.c_str(), className.c_str(), testName.c_str(), g_escapeEndColor); - string stack = get_bundle_string(results, &found, "stack", NULL); - if (found) { + bool stackFound; + string stack = get_bundle_string(results, &stackFound, "stack", NULL); + if (status.has_logcat()) { + const string logcat = status.logcat(); + if (logcat.length() > 0) { + printf("%s\n", logcat.c_str()); + } + } else if (stackFound) { printf("%s\n", stack.c_str()); } } diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp index 3b3fe196736d..c9c0edc59585 100644 --- a/tools/incident_section_gen/main.cpp +++ b/tools/incident_section_gen/main.cpp @@ -469,6 +469,7 @@ static bool generateSectionListCpp(Descriptor const* descriptor) { const FieldDescriptor* field = fieldsInOrder[i]; const string fieldName = getFieldName(field); const Destination fieldDest = getFieldDest(field); + printf("\n// Incident Report Section: %s (%d)\n", field->name().c_str(), field->number()); if (field->type() != FieldDescriptor::TYPE_MESSAGE) { printPrivacy(fieldName, field, "NULL", fieldDest, "NULL"); continue; @@ -477,9 +478,11 @@ static bool generateSectionListCpp(Descriptor const* descriptor) { skip[i] = true; const string fieldMessageName = getMessageName(field->message_type(), fieldDest); // generate privacy flags for each section. - if (generatePrivacyFlags(field->message_type(), fieldDest, variableNames, &parents)) { + if (generatePrivacyFlags(field->message_type(), incidentDest, variableNames, &parents)) { printPrivacy(fieldName, field, fieldMessageName, fieldDest, "NULL"); - } else if (isDefaultField(field, incidentDest)) { + } else if (fieldDest == incidentDest) { + printf("// default %s: fieldDest=%d incidentDest=%d\n", fieldName.c_str(), + getFieldDest(field), incidentDest); continue; // don't create a new privacy if the value is default. } else { printPrivacy(fieldName, field, "NULL", fieldDest, "NULL"); |