summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/aapt2/Android.bp1
-rw-r--r--tools/aapt2/ResourceParser.cpp11
-rw-r--r--tools/aapt2/ResourceParser_test.cpp5
-rw-r--r--tools/aapt2/ResourceTable.cpp14
-rw-r--r--tools/aapt2/ResourceTable.h6
-rw-r--r--tools/aapt2/ResourceValues.cpp4
-rw-r--r--tools/aapt2/ResourceValues_test.cpp52
-rw-r--r--tools/aapt2/link/TableMerger.cpp10
-rw-r--r--tools/aapt2/link/TableMerger_test.cpp56
-rwxr-xr-xtools/apilint/apilint147
-rw-r--r--tools/apilint/apilint.py57
-rw-r--r--tools/apilint/apilint_test.py18
-rw-r--r--tools/bit/main.cpp10
-rw-r--r--tools/incident_section_gen/main.cpp7
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");