[aapt2] Ignore annotations in flag/enum attribute values
Bug: 258855262
Test: atest aapt2_tests
Change-Id: If67a73b02da719b049c19cee561a2f9b8945956b
diff --git a/tools/aapt2/java/AnnotationProcessor.cpp b/tools/aapt2/java/AnnotationProcessor.cpp
index 8c644cf..a7f6f55 100644
--- a/tools/aapt2/java/AnnotationProcessor.cpp
+++ b/tools/aapt2/java/AnnotationProcessor.cpp
@@ -64,29 +64,31 @@
{"@FlaggedApi", AnnotationRule::kFlaggedApi, "@android.annotation.FlaggedApi", true},
}};
-void AnnotationProcessor::AppendCommentLine(std::string comment) {
+void AnnotationProcessor::AppendCommentLine(std::string comment, bool add_api_annotations) {
static constexpr std::string_view sDeprecated = "@deprecated";
- // Treat deprecated specially, since we don't remove it from the source comment.
- if (comment.find(sDeprecated) != std::string::npos) {
- annotation_parameter_map_[AnnotationRule::kDeprecated] = "";
- }
+ if (add_api_annotations) {
+ // Treat deprecated specially, since we don't remove it from the source comment.
+ if (comment.find(sDeprecated) != std::string::npos) {
+ annotation_parameter_map_[AnnotationRule::kDeprecated] = "";
+ }
- for (const AnnotationRule& rule : sAnnotationRules) {
- std::string::size_type idx = comment.find(rule.doc_str.data());
- if (idx != std::string::npos) {
- // Captures all parameters associated with the specified annotation rule
- // by matching the first pair of parentheses after the rule.
- std::regex re(std::string(rule.doc_str).append(R"(\s*\((.+)\))"));
- std::smatch match_result;
- const bool is_match = std::regex_search(comment, match_result, re);
- if (is_match && rule.preserve_params) {
- annotation_parameter_map_[rule.bit_mask] = match_result[1].str();
- comment.erase(comment.begin() + match_result.position(),
- comment.begin() + match_result.position() + match_result.length());
- } else {
- annotation_parameter_map_[rule.bit_mask] = "";
- comment.erase(comment.begin() + idx, comment.begin() + idx + rule.doc_str.size());
+ for (const AnnotationRule& rule : sAnnotationRules) {
+ std::string::size_type idx = comment.find(rule.doc_str.data());
+ if (idx != std::string::npos) {
+ // Captures all parameters associated with the specified annotation rule
+ // by matching the first pair of parentheses after the rule.
+ std::regex re(std::string(rule.doc_str).append(R"(\s*\((.+)\))"));
+ std::smatch match_result;
+ const bool is_match = std::regex_search(comment, match_result, re);
+ if (is_match && rule.preserve_params) {
+ annotation_parameter_map_[rule.bit_mask] = match_result[1].str();
+ comment.erase(comment.begin() + match_result.position(),
+ comment.begin() + match_result.position() + match_result.length());
+ } else {
+ annotation_parameter_map_[rule.bit_mask] = "";
+ comment.erase(comment.begin() + idx, comment.begin() + idx + rule.doc_str.size());
+ }
}
}
}
@@ -109,12 +111,12 @@
comment_ << "\n * " << std::move(comment);
}
-void AnnotationProcessor::AppendComment(StringPiece comment) {
+void AnnotationProcessor::AppendComment(StringPiece comment, bool add_api_annotations) {
// We need to process line by line to clean-up whitespace and append prefixes.
for (StringPiece line : util::Tokenize(comment, '\n')) {
line = util::TrimWhitespace(line);
if (!line.empty()) {
- AppendCommentLine(std::string(line));
+ AppendCommentLine(std::string(line), add_api_annotations);
}
}
}
diff --git a/tools/aapt2/java/AnnotationProcessor.h b/tools/aapt2/java/AnnotationProcessor.h
index db3437e..2217ab3 100644
--- a/tools/aapt2/java/AnnotationProcessor.h
+++ b/tools/aapt2/java/AnnotationProcessor.h
@@ -60,7 +60,10 @@
// Adds more comments. Resources can have value definitions for various configurations, and
// each of the definitions may have comments that need to be processed.
- void AppendComment(android::StringPiece comment);
+ //
+ // If add_api_annotations is false, annotations found in the comment (e.g., "@SystemApi")
+ // will NOT be converted to Java annotations.
+ void AppendComment(android::StringPiece comment, bool add_api_annotations = true);
void AppendNewLine();
@@ -73,7 +76,7 @@
bool has_comments_ = false;
std::unordered_map<uint32_t, std::string> annotation_parameter_map_;
- void AppendCommentLine(std::string line);
+ void AppendCommentLine(std::string line, bool add_api_annotations);
};
} // namespace aapt
diff --git a/tools/aapt2/java/AnnotationProcessor_test.cpp b/tools/aapt2/java/AnnotationProcessor_test.cpp
index e98e96b..e5eee34 100644
--- a/tools/aapt2/java/AnnotationProcessor_test.cpp
+++ b/tools/aapt2/java/AnnotationProcessor_test.cpp
@@ -136,7 +136,28 @@
EXPECT_THAT(annotations, HasSubstr("This is a system API"));
}
-TEST(AnnotationProcessor, ExtractsFirstSentence) {
+TEST(AnnotationProcessorTest, DoNotAddApiAnnotations) {
+ AnnotationProcessor processor;
+ processor.AppendComment(
+ "@SystemApi This is a system API\n"
+ "@FlaggedApi This is a flagged API\n"
+ "@TestApi This is a test API\n"
+ "@deprecated Deprecate me\n", /*add_api_annotations=*/
+ false);
+
+ std::string annotations;
+ StringOutputStream out(&annotations);
+ Printer printer(&out);
+ processor.Print(&printer);
+ out.Flush();
+
+ EXPECT_THAT(annotations, Not(HasSubstr("@android.annotation.SystemApi")));
+ EXPECT_THAT(annotations, Not(HasSubstr("@android.annotation.FlaggedApi")));
+ EXPECT_THAT(annotations, Not(HasSubstr("@android.annotation.TestApi")));
+ EXPECT_THAT(annotations, Not(HasSubstr("@Deprecated")));
+}
+
+TEST(AnnotationProcessorTest, ExtractsFirstSentence) {
EXPECT_THAT(AnnotationProcessor::ExtractFirstSentence("This is the only sentence"),
Eq("This is the only sentence"));
EXPECT_THAT(AnnotationProcessor::ExtractFirstSentence(
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 58f6564..6e73b01 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -180,7 +180,10 @@
<< "<td>" << std::hex << symbol.value << std::dec << "</td>"
<< "<td>" << util::TrimWhitespace(symbol.symbol.GetComment())
<< "</td></tr>";
- processor->AppendComment(line.str());
+ // add_api_annotations is false since we don't want any annotations
+ // (e.g., "@deprecated")/ found in the enum/flag values to be propagated
+ // up to the attribute.
+ processor->AppendComment(line.str(), /*add_api_annotations=*/false);
}
processor->AppendComment("</table>");
}
diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp
index 40395ed..bca9f4b 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -324,7 +324,58 @@
EXPECT_THAT(output, HasSubstr(expected_text));
}
-TEST(JavaClassGeneratorTest, CommentsForEnumAndFlagAttributesArePresent) {}
+TEST(JavaClassGeneratorTest, CommentsForEnumAndFlagAttributesArePresent) {
+ std::unique_ptr<Attribute> flagAttr =
+ test::AttributeBuilder()
+ .SetTypeMask(android::ResTable_map::TYPE_FLAGS)
+ .SetComment("Flag attribute")
+ .AddItemWithComment("flagOne", 0x01, "Flag comment 1")
+ .AddItemWithComment("flagTwo", 0x02, "@deprecated Flag comment 2")
+ .Build();
+ std::unique_ptr<Attribute> enumAttr =
+ test::AttributeBuilder()
+ .SetTypeMask(android::ResTable_map::TYPE_ENUM)
+ .SetComment("Enum attribute")
+ .AddItemWithComment("enumOne", 0x01, "@TestApi Enum comment 1")
+ .AddItemWithComment("enumTwo", 0x02, "Enum comment 2")
+ .Build();
+
+ std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
+ .AddValue("android:attr/one", std::move(flagAttr))
+ .AddValue("android:attr/two", std::move(enumAttr))
+ .Build();
+
+ std::unique_ptr<IAaptContext> context =
+ test::ContextBuilder()
+ .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+ .SetNameManglerPolicy(NameManglerPolicy{"android"})
+ .Build();
+ JavaClassGeneratorOptions options;
+ options.use_final = false;
+ JavaClassGenerator generator(context.get(), table.get(), options);
+
+ std::string output;
+ StringOutputStream out(&output);
+ ASSERT_TRUE(generator.Generate("android", &out));
+ out.Flush();
+
+ // Special annotations from the enum/flag values should NOT generate
+ // annotations for the attribute value.
+ EXPECT_THAT(output, Not(HasSubstr("@Deprecated")));
+ EXPECT_THAT(output, Not(HasSubstr("@android.annotation.TestApi")));
+
+ EXPECT_THAT(output, HasSubstr("Flag attribute"));
+ EXPECT_THAT(output, HasSubstr("flagOne"));
+ EXPECT_THAT(output, HasSubstr("Flag comment 1"));
+ EXPECT_THAT(output, HasSubstr("flagTwo"));
+ EXPECT_THAT(output, HasSubstr("@deprecated Flag comment 2"));
+
+ EXPECT_THAT(output, HasSubstr("Enum attribute"));
+ EXPECT_THAT(output, HasSubstr("enumOne"));
+ EXPECT_THAT(output, HasSubstr("@TestApi Enum comment 1"));
+ EXPECT_THAT(output, HasSubstr("enumTwo"));
+ EXPECT_THAT(output, HasSubstr("Enum comment 2"));
+}
TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent) {
Attribute attr;