Loading tools/aapt2/java/AnnotationProcessor.cpp +47 −18 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include "java/AnnotationProcessor.h" #include <algorithm> #include <array> #include "text/Unicode.h" #include "text/Utf8Iterator.h" Loading @@ -41,30 +42,54 @@ StringPiece AnnotationProcessor::ExtractFirstSentence(const StringPiece& comment return comment; } void AnnotationProcessor::AppendCommentLine(std::string& comment) { struct AnnotationRule { enum : uint32_t { kDeprecated = 0x01, kSystemApi = 0x02, kTestApi = 0x04, }; StringPiece doc_str; uint32_t bit_mask; StringPiece annotation; }; static std::array<AnnotationRule, 2> sAnnotationRules = {{ {"@SystemApi", AnnotationRule::kSystemApi, "@android.annotation.SystemApi"}, {"@TestApi", AnnotationRule::kTestApi, "@android.annotation.TestApi"}, }}; void AnnotationProcessor::AppendCommentLine(std::string comment) { static const std::string sDeprecated = "@deprecated"; static const std::string sSystemApi = "@SystemApi"; // Treat deprecated specially, since we don't remove it from the source comment. if (comment.find(sDeprecated) != std::string::npos) { annotation_bit_mask_ |= kDeprecated; annotation_bit_mask_ |= AnnotationRule::kDeprecated; } std::string::size_type idx = comment.find(sSystemApi); for (const AnnotationRule& rule : sAnnotationRules) { std::string::size_type idx = comment.find(rule.doc_str.data()); if (idx != std::string::npos) { annotation_bit_mask_ |= kSystemApi; comment.erase(comment.begin() + idx, comment.begin() + idx + sSystemApi.size()); annotation_bit_mask_ |= rule.bit_mask; comment.erase(comment.begin() + idx, comment.begin() + idx + rule.doc_str.size()); } } if (util::TrimWhitespace(comment).empty()) { // Check if after removal of annotations the line is empty. const StringPiece trimmed = util::TrimWhitespace(comment); if (trimmed.empty()) { return; } // If there was trimming to do, copy the string. if (trimmed.size() != comment.size()) { comment = trimmed.to_string(); } if (!has_comments_) { has_comments_ = true; comment_ << "/**"; } comment_ << "\n * " << std::move(comment); } Loading @@ -73,16 +98,18 @@ void AnnotationProcessor::AppendComment(const StringPiece& comment) { for (StringPiece line : util::Tokenize(comment, '\n')) { line = util::TrimWhitespace(line); if (!line.empty()) { std::string lineCopy = line.to_string(); AppendCommentLine(lineCopy); AppendCommentLine(line.to_string()); } } } void AnnotationProcessor::AppendNewLine() { comment_ << "\n *"; } void AnnotationProcessor::AppendNewLine() { if (has_comments_) { comment_ << "\n *"; } } void AnnotationProcessor::WriteToStream(std::ostream* out, const StringPiece& prefix) const { void AnnotationProcessor::WriteToStream(const StringPiece& prefix, std::ostream* out) const { if (has_comments_) { std::string result = comment_.str(); for (StringPiece line : util::Tokenize(result, '\n')) { Loading @@ -92,12 +119,14 @@ void AnnotationProcessor::WriteToStream(std::ostream* out, << "\n"; } if (annotation_bit_mask_ & kDeprecated) { if (annotation_bit_mask_ & AnnotationRule::kDeprecated) { *out << prefix << "@Deprecated\n"; } if (annotation_bit_mask_ & kSystemApi) { *out << prefix << "@android.annotation.SystemApi\n"; for (const AnnotationRule& rule : sAnnotationRules) { if (annotation_bit_mask_ & rule.bit_mask) { *out << prefix << rule.annotation << "\n"; } } } Loading tools/aapt2/java/AnnotationProcessor.h +32 −43 Original line number Diff line number Diff line Loading @@ -24,64 +24,53 @@ namespace aapt { /** * Builds a JavaDoc comment from a set of XML comments. * This will also look for instances of @SystemApi and convert them to * actual Java annotations. * * Example: * * Input XML: * * <!-- This is meant to be hidden because * It is system api. Also it is @deprecated * @SystemApi * --> * * Output JavaDoc: * * /\* * * This is meant to be hidden because * * It is system api. Also it is @deprecated * *\/ * * Output Annotations: * * @Deprecated * @android.annotation.SystemApi * */ // Builds a JavaDoc comment from a set of XML comments. // This will also look for instances of @SystemApi and convert them to // actual Java annotations. // // Example: // // Input XML: // // <!-- This is meant to be hidden because // It is system api. Also it is @deprecated // @SystemApi // --> // // Output JavaDoc: // // /** // * This is meant to be hidden because // * It is system api. Also it is @deprecated // */ // // Output Annotations: // // @Deprecated // @android.annotation.SystemApi class AnnotationProcessor { public: // Extracts the first sentence of a comment. The algorithm selects the substring starting from // the beginning of the string, and ending at the first '.' character that is followed by a // whitespace character. If these requirements are not met, the whole string is returned. static android::StringPiece ExtractFirstSentence(const android::StringPiece& comment); /** * Adds more comments. Since resources can have various values with different * configurations, * we need to collect all the comments. */ // 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(const android::StringPiece& comment); void AppendNewLine(); /** * Writes the comments and annotations to the stream, with the given prefix * before each line. */ void WriteToStream(std::ostream* out, const android::StringPiece& prefix) const; // Writes the comments and annotations to the stream, with the given prefix before each line. void WriteToStream(const android::StringPiece& prefix, std::ostream* out) const; private: enum : uint32_t { kDeprecated = 0x01, kSystemApi = 0x02, }; std::stringstream comment_; std::stringstream mAnnotations; bool has_comments_ = false; uint32_t annotation_bit_mask_ = 0; void AppendCommentLine(std::string& line); void AppendCommentLine(std::string line); }; } // namespace aapt Loading tools/aapt2/java/AnnotationProcessor_test.cpp +15 −2 Original line number Diff line number Diff line Loading @@ -34,7 +34,7 @@ TEST(AnnotationProcessorTest, EmitsDeprecated) { processor.AppendComment(comment); std::stringstream result; processor.WriteToStream(&result, ""); processor.WriteToStream("", &result); std::string annotations = result.str(); EXPECT_THAT(annotations, HasSubstr("@Deprecated")); Loading @@ -45,7 +45,7 @@ TEST(AnnotationProcessorTest, EmitsSystemApiAnnotationAndRemovesFromComment) { processor.AppendComment("@SystemApi This is a system API"); std::stringstream result; processor.WriteToStream(&result, ""); processor.WriteToStream("", &result); std::string annotations = result.str(); EXPECT_THAT(annotations, HasSubstr("@android.annotation.SystemApi")); Loading @@ -53,6 +53,19 @@ TEST(AnnotationProcessorTest, EmitsSystemApiAnnotationAndRemovesFromComment) { EXPECT_THAT(annotations, HasSubstr("This is a system API")); } TEST(AnnotationProcessorTest, EmitsTestApiAnnotationAndRemovesFromComment) { AnnotationProcessor processor; processor.AppendComment("@TestApi This is a test API"); std::stringstream result; processor.WriteToStream("", &result); std::string annotations = result.str(); EXPECT_THAT(annotations, HasSubstr("@android.annotation.TestApi")); EXPECT_THAT(annotations, Not(HasSubstr("@TestApi"))); EXPECT_THAT(annotations, HasSubstr("This is a test API")); } TEST(AnnotationProcessor, ExtractsFirstSentence) { EXPECT_THAT(AnnotationProcessor::ExtractFirstSentence("This is the only sentence"), Eq("This is the only sentence")); Loading tools/aapt2/java/ClassDefinition.cpp +4 −5 Original line number Diff line number Diff line Loading @@ -18,12 +18,12 @@ #include "androidfw/StringPiece.h" using android::StringPiece; using ::android::StringPiece; namespace aapt { void ClassMember::WriteToStream(const StringPiece& prefix, bool final, std::ostream* out) const { processor_.WriteToStream(out, prefix); processor_.WriteToStream(prefix, out); } void MethodDefinition::AppendStatement(const StringPiece& statement) { Loading Loading @@ -81,9 +81,8 @@ constexpr static const char* sWarningHeader = " * should not be modified by hand.\n" " */\n\n"; bool ClassDefinition::WriteJavaFile(const ClassDefinition* def, const StringPiece& package, bool final, std::ostream* out) { bool ClassDefinition::WriteJavaFile(const ClassDefinition* def, const StringPiece& package, bool final, std::ostream* out) { *out << sWarningHeader << "package " << package << ";\n\n"; def->WriteToStream("", final, out); return bool(*out); Loading tools/aapt2/java/JavaClassGenerator_test.cpp +59 −85 Original line number Diff line number Diff line Loading @@ -22,7 +22,9 @@ #include "test/Test.h" #include "util/Util.h" using android::StringPiece; using ::android::StringPiece; using ::testing::HasSubstr; using ::testing::Not; namespace aapt { Loading Loading @@ -52,8 +54,7 @@ TEST(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) { .AddSimple("android:id/hey-man", ResourceId(0x01020000)) .AddValue("android:attr/cool.attr", ResourceId(0x01010000), test::AttributeBuilder(false).Build()) .AddValue( "android:styleable/hey.dude", ResourceId(0x01030000), .AddValue("android:styleable/hey.dude", ResourceId(0x01030000), test::StyleableBuilder() .AddItem("android:attr/cool.attr", ResourceId(0x01010000)) .Build()) Loading @@ -61,8 +62,7 @@ TEST(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) { std::unique_ptr<IAaptContext> context = test::ContextBuilder() .AddSymbolSource( util::make_unique<ResourceTableSymbolSource>(table.get())) .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) .SetNameManglerPolicy(NameManglerPolicy{"android"}) .Build(); JavaClassGenerator generator(context.get(), table.get(), {}); Loading @@ -72,14 +72,9 @@ TEST(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) { std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final int hey_man=0x01020000;")); EXPECT_NE(std::string::npos, output.find("public static final int[] hey_dude={")); EXPECT_NE(std::string::npos, output.find("public static final int hey_dude_cool_attr=0;")); EXPECT_THAT(output, HasSubstr("public static final int hey_man=0x01020000;")); EXPECT_THAT(output, HasSubstr("public static final int[] hey_dude={")); EXPECT_THAT(output, HasSubstr("public static final int hey_dude_cool_attr=0;")); } TEST(JavaClassGeneratorTest, CorrectPackageNameIsUsed) { Loading @@ -92,8 +87,7 @@ TEST(JavaClassGeneratorTest, CorrectPackageNameIsUsed) { std::unique_ptr<IAaptContext> context = test::ContextBuilder() .AddSymbolSource( util::make_unique<ResourceTableSymbolSource>(table.get())) .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) .SetNameManglerPolicy(NameManglerPolicy{"android"}) .Build(); JavaClassGenerator generator(context.get(), table.get(), {}); Loading @@ -101,11 +95,10 @@ TEST(JavaClassGeneratorTest, CorrectPackageNameIsUsed) { ASSERT_TRUE(generator.Generate("android", "com.android.internal", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("package com.android.internal;")); EXPECT_NE(std::string::npos, output.find("public static final int one=0x01020000;")); EXPECT_EQ(std::string::npos, output.find("two")); EXPECT_EQ(std::string::npos, output.find("com_foo$two")); EXPECT_THAT(output, HasSubstr("package com.android.internal;")); EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;")); EXPECT_THAT(output, Not(HasSubstr("two"))); EXPECT_THAT(output, Not(HasSubstr("com_foo$two"))); } TEST(JavaClassGeneratorTest, AttrPrivateIsWrittenAsAttr) { Loading @@ -118,8 +111,7 @@ TEST(JavaClassGeneratorTest, AttrPrivateIsWrittenAsAttr) { std::unique_ptr<IAaptContext> context = test::ContextBuilder() .AddSymbolSource( util::make_unique<ResourceTableSymbolSource>(table.get())) .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) .SetNameManglerPolicy(NameManglerPolicy{"android"}) .Build(); JavaClassGenerator generator(context.get(), table.get(), {}); Loading @@ -127,9 +119,8 @@ TEST(JavaClassGeneratorTest, AttrPrivateIsWrittenAsAttr) { ASSERT_TRUE(generator.Generate("android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final class attr")); EXPECT_EQ(std::string::npos, output.find("public static final class ^attr-private")); EXPECT_THAT(output, HasSubstr("public static final class attr")); EXPECT_THAT(output, Not(HasSubstr("public static final class ^attr-private"))); } TEST(JavaClassGeneratorTest, OnlyWritePublicResources) { Loading @@ -140,16 +131,13 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) { .AddSimple("android:id/one", ResourceId(0x01020000)) .AddSimple("android:id/two", ResourceId(0x01020001)) .AddSimple("android:id/three", ResourceId(0x01020002)) .SetSymbolState("android:id/one", ResourceId(0x01020000), SymbolState::kPublic) .SetSymbolState("android:id/two", ResourceId(0x01020001), SymbolState::kPrivate) .SetSymbolState("android:id/one", ResourceId(0x01020000), SymbolState::kPublic) .SetSymbolState("android:id/two", ResourceId(0x01020001), SymbolState::kPrivate) .Build(); std::unique_ptr<IAaptContext> context = test::ContextBuilder() .AddSymbolSource( util::make_unique<ResourceTableSymbolSource>(table.get())) .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) .SetNameManglerPolicy(NameManglerPolicy{"android"}) .Build(); Loading @@ -160,10 +148,9 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) { std::stringstream out; ASSERT_TRUE(generator.Generate("android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final int one=0x01020000;")); EXPECT_EQ(std::string::npos, output.find("two")); EXPECT_EQ(std::string::npos, output.find("three")); EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;")); EXPECT_THAT(output, Not(HasSubstr("two"))); EXPECT_THAT(output, Not(HasSubstr("three"))); } options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate; Loading @@ -172,11 +159,9 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) { std::stringstream out; ASSERT_TRUE(generator.Generate("android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final int one=0x01020000;")); EXPECT_NE(std::string::npos, output.find("public static final int two=0x01020001;")); EXPECT_EQ(std::string::npos, output.find("three")); EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;")); EXPECT_THAT(output, HasSubstr("public static final int two=0x01020001;")); EXPECT_THAT(output, Not(HasSubstr("three"))); } options.types = JavaClassGeneratorOptions::SymbolTypes::kAll; Loading @@ -185,12 +170,9 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) { std::stringstream out; ASSERT_TRUE(generator.Generate("android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final int one=0x01020000;")); EXPECT_NE(std::string::npos, output.find("public static final int two=0x01020001;")); EXPECT_NE(std::string::npos, output.find("public static final int three=0x01020002;")); EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;")); EXPECT_THAT(output, HasSubstr("public static final int two=0x01020001;")); EXPECT_THAT(output, HasSubstr("public static final int three=0x01020002;")); } } Loading Loading @@ -246,8 +228,7 @@ TEST(JavaClassGeneratorTest, EmitOtherPackagesAttributesInStyleable) { std::unique_ptr<IAaptContext> context = test::ContextBuilder() .AddSymbolSource( util::make_unique<ResourceTableSymbolSource>(table.get())) .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) .SetNameManglerPolicy(NameManglerPolicy{"android"}) .Build(); JavaClassGenerator generator(context.get(), table.get(), {}); Loading @@ -256,8 +237,8 @@ TEST(JavaClassGeneratorTest, EmitOtherPackagesAttributesInStyleable) { EXPECT_TRUE(generator.Generate("android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("int foo_bar=")); EXPECT_NE(std::string::npos, output.find("int foo_com_lib_bar=")); EXPECT_THAT(output, HasSubstr("int foo_bar=")); EXPECT_THAT(output, HasSubstr("int foo_com_lib_bar=")); } TEST(JavaClassGeneratorTest, CommentsForSimpleResourcesArePresent) { Loading @@ -271,24 +252,22 @@ TEST(JavaClassGeneratorTest, CommentsForSimpleResourcesArePresent) { std::unique_ptr<IAaptContext> context = test::ContextBuilder() .AddSymbolSource( util::make_unique<ResourceTableSymbolSource>(table.get())) .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) .SetNameManglerPolicy(NameManglerPolicy{"android"}) .Build(); JavaClassGenerator generator(context.get(), table.get(), {}); std::stringstream out; ASSERT_TRUE(generator.Generate("android", &out)); std::string actual = out.str(); std::string output = out.str(); const char* expectedText = const char* expected_text = R"EOF(/** * This is a comment * @deprecated */ @Deprecated public static final int foo=0x01010000;)EOF"; EXPECT_NE(std::string::npos, actual.find(expectedText)); EXPECT_THAT(output, HasSubstr(expected_text)); } TEST(JavaClassGeneratorTest, CommentsForEnumAndFlagAttributesArePresent) {} Loading @@ -298,8 +277,7 @@ TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent) attr.SetComment(StringPiece("This is an attribute")); Styleable styleable; styleable.entries.push_back( Reference(test::ParseNameOrDie("android:attr/one"))); styleable.entries.push_back(Reference(test::ParseNameOrDie("android:attr/one"))); styleable.SetComment(StringPiece("This is a styleable")); std::unique_ptr<ResourceTable> table = Loading @@ -312,8 +290,7 @@ TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent) std::unique_ptr<IAaptContext> context = test::ContextBuilder() .AddSymbolSource( util::make_unique<ResourceTableSymbolSource>(table.get())) .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) .SetNameManglerPolicy(NameManglerPolicy{"android"}) .Build(); JavaClassGeneratorOptions options; Loading @@ -321,12 +298,12 @@ TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent) JavaClassGenerator generator(context.get(), table.get(), options); std::stringstream out; ASSERT_TRUE(generator.Generate("android", &out)); std::string actual = out.str(); std::string output = out.str(); EXPECT_NE(std::string::npos, actual.find("attr name android:one")); EXPECT_NE(std::string::npos, actual.find("attr description")); EXPECT_NE(std::string::npos, actual.find(attr.GetComment().data())); EXPECT_NE(std::string::npos, actual.find(styleable.GetComment().data())); EXPECT_THAT(output, HasSubstr("attr name android:one")); EXPECT_THAT(output, HasSubstr("attr description")); EXPECT_THAT(output, HasSubstr(attr.GetComment())); EXPECT_THAT(output, HasSubstr(styleable.GetComment())); } TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) { Loading @@ -341,8 +318,7 @@ TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) { std::unique_ptr<IAaptContext> context = test::ContextBuilder() .AddSymbolSource( util::make_unique<ResourceTableSymbolSource>(table.get())) .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) .SetNameManglerPolicy(NameManglerPolicy{"android"}) .Build(); JavaClassGeneratorOptions options; Loading @@ -350,17 +326,17 @@ TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) { JavaClassGenerator generator(context.get(), table.get(), options); std::stringstream out; ASSERT_TRUE(generator.Generate("android", &out)); std::string actual = out.str(); std::string output = out.str(); EXPECT_EQ(std::string::npos, actual.find("@attr name android:one")); EXPECT_EQ(std::string::npos, actual.find("@attr description")); EXPECT_THAT(output, Not(HasSubstr("@attr name android:one"))); EXPECT_THAT(output, Not(HasSubstr("@attr description"))); // We should find @removed only in the attribute javadoc and not anywhere else // (i.e. the class // javadoc). const size_t pos = actual.find("removed"); EXPECT_NE(std::string::npos, pos); EXPECT_EQ(std::string::npos, actual.find("removed", pos + 1)); // (i.e. the class javadoc). const std::string kRemoved("removed"); ASSERT_THAT(output, HasSubstr(kRemoved)); std::string after_first_match = output.substr(output.find(kRemoved) + kRemoved.size()); EXPECT_THAT(after_first_match, Not(HasSubstr(kRemoved))); } TEST(JavaClassGeneratorTest, GenerateOnResourcesLoadedCallbackForSharedLibrary) { Loading @@ -381,19 +357,17 @@ TEST(JavaClassGeneratorTest, GenerateOnResourcesLoadedCallbackForSharedLibrary) JavaClassGeneratorOptions options; options.use_final = false; options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{ {"com.foo", "com.boo"}, }; options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{{"com.foo", "com.boo"}}; JavaClassGenerator generator(context.get(), table.get(), options); std::stringstream out; ASSERT_TRUE(generator.Generate("android", &out)); std::string actual = out.str(); std::string output = out.str(); EXPECT_NE(std::string::npos, actual.find("void onResourcesLoaded")); EXPECT_NE(std::string::npos, actual.find("com.foo.R.onResourcesLoaded")); EXPECT_NE(std::string::npos, actual.find("com.boo.R.onResourcesLoaded")); EXPECT_THAT(output, HasSubstr("void onResourcesLoaded")); EXPECT_THAT(output, HasSubstr("com.foo.R.onResourcesLoaded")); EXPECT_THAT(output, HasSubstr("com.boo.R.onResourcesLoaded")); } } // namespace aapt Loading
tools/aapt2/java/AnnotationProcessor.cpp +47 −18 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include "java/AnnotationProcessor.h" #include <algorithm> #include <array> #include "text/Unicode.h" #include "text/Utf8Iterator.h" Loading @@ -41,30 +42,54 @@ StringPiece AnnotationProcessor::ExtractFirstSentence(const StringPiece& comment return comment; } void AnnotationProcessor::AppendCommentLine(std::string& comment) { struct AnnotationRule { enum : uint32_t { kDeprecated = 0x01, kSystemApi = 0x02, kTestApi = 0x04, }; StringPiece doc_str; uint32_t bit_mask; StringPiece annotation; }; static std::array<AnnotationRule, 2> sAnnotationRules = {{ {"@SystemApi", AnnotationRule::kSystemApi, "@android.annotation.SystemApi"}, {"@TestApi", AnnotationRule::kTestApi, "@android.annotation.TestApi"}, }}; void AnnotationProcessor::AppendCommentLine(std::string comment) { static const std::string sDeprecated = "@deprecated"; static const std::string sSystemApi = "@SystemApi"; // Treat deprecated specially, since we don't remove it from the source comment. if (comment.find(sDeprecated) != std::string::npos) { annotation_bit_mask_ |= kDeprecated; annotation_bit_mask_ |= AnnotationRule::kDeprecated; } std::string::size_type idx = comment.find(sSystemApi); for (const AnnotationRule& rule : sAnnotationRules) { std::string::size_type idx = comment.find(rule.doc_str.data()); if (idx != std::string::npos) { annotation_bit_mask_ |= kSystemApi; comment.erase(comment.begin() + idx, comment.begin() + idx + sSystemApi.size()); annotation_bit_mask_ |= rule.bit_mask; comment.erase(comment.begin() + idx, comment.begin() + idx + rule.doc_str.size()); } } if (util::TrimWhitespace(comment).empty()) { // Check if after removal of annotations the line is empty. const StringPiece trimmed = util::TrimWhitespace(comment); if (trimmed.empty()) { return; } // If there was trimming to do, copy the string. if (trimmed.size() != comment.size()) { comment = trimmed.to_string(); } if (!has_comments_) { has_comments_ = true; comment_ << "/**"; } comment_ << "\n * " << std::move(comment); } Loading @@ -73,16 +98,18 @@ void AnnotationProcessor::AppendComment(const StringPiece& comment) { for (StringPiece line : util::Tokenize(comment, '\n')) { line = util::TrimWhitespace(line); if (!line.empty()) { std::string lineCopy = line.to_string(); AppendCommentLine(lineCopy); AppendCommentLine(line.to_string()); } } } void AnnotationProcessor::AppendNewLine() { comment_ << "\n *"; } void AnnotationProcessor::AppendNewLine() { if (has_comments_) { comment_ << "\n *"; } } void AnnotationProcessor::WriteToStream(std::ostream* out, const StringPiece& prefix) const { void AnnotationProcessor::WriteToStream(const StringPiece& prefix, std::ostream* out) const { if (has_comments_) { std::string result = comment_.str(); for (StringPiece line : util::Tokenize(result, '\n')) { Loading @@ -92,12 +119,14 @@ void AnnotationProcessor::WriteToStream(std::ostream* out, << "\n"; } if (annotation_bit_mask_ & kDeprecated) { if (annotation_bit_mask_ & AnnotationRule::kDeprecated) { *out << prefix << "@Deprecated\n"; } if (annotation_bit_mask_ & kSystemApi) { *out << prefix << "@android.annotation.SystemApi\n"; for (const AnnotationRule& rule : sAnnotationRules) { if (annotation_bit_mask_ & rule.bit_mask) { *out << prefix << rule.annotation << "\n"; } } } Loading
tools/aapt2/java/AnnotationProcessor.h +32 −43 Original line number Diff line number Diff line Loading @@ -24,64 +24,53 @@ namespace aapt { /** * Builds a JavaDoc comment from a set of XML comments. * This will also look for instances of @SystemApi and convert them to * actual Java annotations. * * Example: * * Input XML: * * <!-- This is meant to be hidden because * It is system api. Also it is @deprecated * @SystemApi * --> * * Output JavaDoc: * * /\* * * This is meant to be hidden because * * It is system api. Also it is @deprecated * *\/ * * Output Annotations: * * @Deprecated * @android.annotation.SystemApi * */ // Builds a JavaDoc comment from a set of XML comments. // This will also look for instances of @SystemApi and convert them to // actual Java annotations. // // Example: // // Input XML: // // <!-- This is meant to be hidden because // It is system api. Also it is @deprecated // @SystemApi // --> // // Output JavaDoc: // // /** // * This is meant to be hidden because // * It is system api. Also it is @deprecated // */ // // Output Annotations: // // @Deprecated // @android.annotation.SystemApi class AnnotationProcessor { public: // Extracts the first sentence of a comment. The algorithm selects the substring starting from // the beginning of the string, and ending at the first '.' character that is followed by a // whitespace character. If these requirements are not met, the whole string is returned. static android::StringPiece ExtractFirstSentence(const android::StringPiece& comment); /** * Adds more comments. Since resources can have various values with different * configurations, * we need to collect all the comments. */ // 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(const android::StringPiece& comment); void AppendNewLine(); /** * Writes the comments and annotations to the stream, with the given prefix * before each line. */ void WriteToStream(std::ostream* out, const android::StringPiece& prefix) const; // Writes the comments and annotations to the stream, with the given prefix before each line. void WriteToStream(const android::StringPiece& prefix, std::ostream* out) const; private: enum : uint32_t { kDeprecated = 0x01, kSystemApi = 0x02, }; std::stringstream comment_; std::stringstream mAnnotations; bool has_comments_ = false; uint32_t annotation_bit_mask_ = 0; void AppendCommentLine(std::string& line); void AppendCommentLine(std::string line); }; } // namespace aapt Loading
tools/aapt2/java/AnnotationProcessor_test.cpp +15 −2 Original line number Diff line number Diff line Loading @@ -34,7 +34,7 @@ TEST(AnnotationProcessorTest, EmitsDeprecated) { processor.AppendComment(comment); std::stringstream result; processor.WriteToStream(&result, ""); processor.WriteToStream("", &result); std::string annotations = result.str(); EXPECT_THAT(annotations, HasSubstr("@Deprecated")); Loading @@ -45,7 +45,7 @@ TEST(AnnotationProcessorTest, EmitsSystemApiAnnotationAndRemovesFromComment) { processor.AppendComment("@SystemApi This is a system API"); std::stringstream result; processor.WriteToStream(&result, ""); processor.WriteToStream("", &result); std::string annotations = result.str(); EXPECT_THAT(annotations, HasSubstr("@android.annotation.SystemApi")); Loading @@ -53,6 +53,19 @@ TEST(AnnotationProcessorTest, EmitsSystemApiAnnotationAndRemovesFromComment) { EXPECT_THAT(annotations, HasSubstr("This is a system API")); } TEST(AnnotationProcessorTest, EmitsTestApiAnnotationAndRemovesFromComment) { AnnotationProcessor processor; processor.AppendComment("@TestApi This is a test API"); std::stringstream result; processor.WriteToStream("", &result); std::string annotations = result.str(); EXPECT_THAT(annotations, HasSubstr("@android.annotation.TestApi")); EXPECT_THAT(annotations, Not(HasSubstr("@TestApi"))); EXPECT_THAT(annotations, HasSubstr("This is a test API")); } TEST(AnnotationProcessor, ExtractsFirstSentence) { EXPECT_THAT(AnnotationProcessor::ExtractFirstSentence("This is the only sentence"), Eq("This is the only sentence")); Loading
tools/aapt2/java/ClassDefinition.cpp +4 −5 Original line number Diff line number Diff line Loading @@ -18,12 +18,12 @@ #include "androidfw/StringPiece.h" using android::StringPiece; using ::android::StringPiece; namespace aapt { void ClassMember::WriteToStream(const StringPiece& prefix, bool final, std::ostream* out) const { processor_.WriteToStream(out, prefix); processor_.WriteToStream(prefix, out); } void MethodDefinition::AppendStatement(const StringPiece& statement) { Loading Loading @@ -81,9 +81,8 @@ constexpr static const char* sWarningHeader = " * should not be modified by hand.\n" " */\n\n"; bool ClassDefinition::WriteJavaFile(const ClassDefinition* def, const StringPiece& package, bool final, std::ostream* out) { bool ClassDefinition::WriteJavaFile(const ClassDefinition* def, const StringPiece& package, bool final, std::ostream* out) { *out << sWarningHeader << "package " << package << ";\n\n"; def->WriteToStream("", final, out); return bool(*out); Loading
tools/aapt2/java/JavaClassGenerator_test.cpp +59 −85 Original line number Diff line number Diff line Loading @@ -22,7 +22,9 @@ #include "test/Test.h" #include "util/Util.h" using android::StringPiece; using ::android::StringPiece; using ::testing::HasSubstr; using ::testing::Not; namespace aapt { Loading Loading @@ -52,8 +54,7 @@ TEST(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) { .AddSimple("android:id/hey-man", ResourceId(0x01020000)) .AddValue("android:attr/cool.attr", ResourceId(0x01010000), test::AttributeBuilder(false).Build()) .AddValue( "android:styleable/hey.dude", ResourceId(0x01030000), .AddValue("android:styleable/hey.dude", ResourceId(0x01030000), test::StyleableBuilder() .AddItem("android:attr/cool.attr", ResourceId(0x01010000)) .Build()) Loading @@ -61,8 +62,7 @@ TEST(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) { std::unique_ptr<IAaptContext> context = test::ContextBuilder() .AddSymbolSource( util::make_unique<ResourceTableSymbolSource>(table.get())) .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) .SetNameManglerPolicy(NameManglerPolicy{"android"}) .Build(); JavaClassGenerator generator(context.get(), table.get(), {}); Loading @@ -72,14 +72,9 @@ TEST(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) { std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final int hey_man=0x01020000;")); EXPECT_NE(std::string::npos, output.find("public static final int[] hey_dude={")); EXPECT_NE(std::string::npos, output.find("public static final int hey_dude_cool_attr=0;")); EXPECT_THAT(output, HasSubstr("public static final int hey_man=0x01020000;")); EXPECT_THAT(output, HasSubstr("public static final int[] hey_dude={")); EXPECT_THAT(output, HasSubstr("public static final int hey_dude_cool_attr=0;")); } TEST(JavaClassGeneratorTest, CorrectPackageNameIsUsed) { Loading @@ -92,8 +87,7 @@ TEST(JavaClassGeneratorTest, CorrectPackageNameIsUsed) { std::unique_ptr<IAaptContext> context = test::ContextBuilder() .AddSymbolSource( util::make_unique<ResourceTableSymbolSource>(table.get())) .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) .SetNameManglerPolicy(NameManglerPolicy{"android"}) .Build(); JavaClassGenerator generator(context.get(), table.get(), {}); Loading @@ -101,11 +95,10 @@ TEST(JavaClassGeneratorTest, CorrectPackageNameIsUsed) { ASSERT_TRUE(generator.Generate("android", "com.android.internal", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("package com.android.internal;")); EXPECT_NE(std::string::npos, output.find("public static final int one=0x01020000;")); EXPECT_EQ(std::string::npos, output.find("two")); EXPECT_EQ(std::string::npos, output.find("com_foo$two")); EXPECT_THAT(output, HasSubstr("package com.android.internal;")); EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;")); EXPECT_THAT(output, Not(HasSubstr("two"))); EXPECT_THAT(output, Not(HasSubstr("com_foo$two"))); } TEST(JavaClassGeneratorTest, AttrPrivateIsWrittenAsAttr) { Loading @@ -118,8 +111,7 @@ TEST(JavaClassGeneratorTest, AttrPrivateIsWrittenAsAttr) { std::unique_ptr<IAaptContext> context = test::ContextBuilder() .AddSymbolSource( util::make_unique<ResourceTableSymbolSource>(table.get())) .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) .SetNameManglerPolicy(NameManglerPolicy{"android"}) .Build(); JavaClassGenerator generator(context.get(), table.get(), {}); Loading @@ -127,9 +119,8 @@ TEST(JavaClassGeneratorTest, AttrPrivateIsWrittenAsAttr) { ASSERT_TRUE(generator.Generate("android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final class attr")); EXPECT_EQ(std::string::npos, output.find("public static final class ^attr-private")); EXPECT_THAT(output, HasSubstr("public static final class attr")); EXPECT_THAT(output, Not(HasSubstr("public static final class ^attr-private"))); } TEST(JavaClassGeneratorTest, OnlyWritePublicResources) { Loading @@ -140,16 +131,13 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) { .AddSimple("android:id/one", ResourceId(0x01020000)) .AddSimple("android:id/two", ResourceId(0x01020001)) .AddSimple("android:id/three", ResourceId(0x01020002)) .SetSymbolState("android:id/one", ResourceId(0x01020000), SymbolState::kPublic) .SetSymbolState("android:id/two", ResourceId(0x01020001), SymbolState::kPrivate) .SetSymbolState("android:id/one", ResourceId(0x01020000), SymbolState::kPublic) .SetSymbolState("android:id/two", ResourceId(0x01020001), SymbolState::kPrivate) .Build(); std::unique_ptr<IAaptContext> context = test::ContextBuilder() .AddSymbolSource( util::make_unique<ResourceTableSymbolSource>(table.get())) .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) .SetNameManglerPolicy(NameManglerPolicy{"android"}) .Build(); Loading @@ -160,10 +148,9 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) { std::stringstream out; ASSERT_TRUE(generator.Generate("android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final int one=0x01020000;")); EXPECT_EQ(std::string::npos, output.find("two")); EXPECT_EQ(std::string::npos, output.find("three")); EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;")); EXPECT_THAT(output, Not(HasSubstr("two"))); EXPECT_THAT(output, Not(HasSubstr("three"))); } options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate; Loading @@ -172,11 +159,9 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) { std::stringstream out; ASSERT_TRUE(generator.Generate("android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final int one=0x01020000;")); EXPECT_NE(std::string::npos, output.find("public static final int two=0x01020001;")); EXPECT_EQ(std::string::npos, output.find("three")); EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;")); EXPECT_THAT(output, HasSubstr("public static final int two=0x01020001;")); EXPECT_THAT(output, Not(HasSubstr("three"))); } options.types = JavaClassGeneratorOptions::SymbolTypes::kAll; Loading @@ -185,12 +170,9 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) { std::stringstream out; ASSERT_TRUE(generator.Generate("android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("public static final int one=0x01020000;")); EXPECT_NE(std::string::npos, output.find("public static final int two=0x01020001;")); EXPECT_NE(std::string::npos, output.find("public static final int three=0x01020002;")); EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;")); EXPECT_THAT(output, HasSubstr("public static final int two=0x01020001;")); EXPECT_THAT(output, HasSubstr("public static final int three=0x01020002;")); } } Loading Loading @@ -246,8 +228,7 @@ TEST(JavaClassGeneratorTest, EmitOtherPackagesAttributesInStyleable) { std::unique_ptr<IAaptContext> context = test::ContextBuilder() .AddSymbolSource( util::make_unique<ResourceTableSymbolSource>(table.get())) .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) .SetNameManglerPolicy(NameManglerPolicy{"android"}) .Build(); JavaClassGenerator generator(context.get(), table.get(), {}); Loading @@ -256,8 +237,8 @@ TEST(JavaClassGeneratorTest, EmitOtherPackagesAttributesInStyleable) { EXPECT_TRUE(generator.Generate("android", &out)); std::string output = out.str(); EXPECT_NE(std::string::npos, output.find("int foo_bar=")); EXPECT_NE(std::string::npos, output.find("int foo_com_lib_bar=")); EXPECT_THAT(output, HasSubstr("int foo_bar=")); EXPECT_THAT(output, HasSubstr("int foo_com_lib_bar=")); } TEST(JavaClassGeneratorTest, CommentsForSimpleResourcesArePresent) { Loading @@ -271,24 +252,22 @@ TEST(JavaClassGeneratorTest, CommentsForSimpleResourcesArePresent) { std::unique_ptr<IAaptContext> context = test::ContextBuilder() .AddSymbolSource( util::make_unique<ResourceTableSymbolSource>(table.get())) .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) .SetNameManglerPolicy(NameManglerPolicy{"android"}) .Build(); JavaClassGenerator generator(context.get(), table.get(), {}); std::stringstream out; ASSERT_TRUE(generator.Generate("android", &out)); std::string actual = out.str(); std::string output = out.str(); const char* expectedText = const char* expected_text = R"EOF(/** * This is a comment * @deprecated */ @Deprecated public static final int foo=0x01010000;)EOF"; EXPECT_NE(std::string::npos, actual.find(expectedText)); EXPECT_THAT(output, HasSubstr(expected_text)); } TEST(JavaClassGeneratorTest, CommentsForEnumAndFlagAttributesArePresent) {} Loading @@ -298,8 +277,7 @@ TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent) attr.SetComment(StringPiece("This is an attribute")); Styleable styleable; styleable.entries.push_back( Reference(test::ParseNameOrDie("android:attr/one"))); styleable.entries.push_back(Reference(test::ParseNameOrDie("android:attr/one"))); styleable.SetComment(StringPiece("This is a styleable")); std::unique_ptr<ResourceTable> table = Loading @@ -312,8 +290,7 @@ TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent) std::unique_ptr<IAaptContext> context = test::ContextBuilder() .AddSymbolSource( util::make_unique<ResourceTableSymbolSource>(table.get())) .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) .SetNameManglerPolicy(NameManglerPolicy{"android"}) .Build(); JavaClassGeneratorOptions options; Loading @@ -321,12 +298,12 @@ TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent) JavaClassGenerator generator(context.get(), table.get(), options); std::stringstream out; ASSERT_TRUE(generator.Generate("android", &out)); std::string actual = out.str(); std::string output = out.str(); EXPECT_NE(std::string::npos, actual.find("attr name android:one")); EXPECT_NE(std::string::npos, actual.find("attr description")); EXPECT_NE(std::string::npos, actual.find(attr.GetComment().data())); EXPECT_NE(std::string::npos, actual.find(styleable.GetComment().data())); EXPECT_THAT(output, HasSubstr("attr name android:one")); EXPECT_THAT(output, HasSubstr("attr description")); EXPECT_THAT(output, HasSubstr(attr.GetComment())); EXPECT_THAT(output, HasSubstr(styleable.GetComment())); } TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) { Loading @@ -341,8 +318,7 @@ TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) { std::unique_ptr<IAaptContext> context = test::ContextBuilder() .AddSymbolSource( util::make_unique<ResourceTableSymbolSource>(table.get())) .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) .SetNameManglerPolicy(NameManglerPolicy{"android"}) .Build(); JavaClassGeneratorOptions options; Loading @@ -350,17 +326,17 @@ TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) { JavaClassGenerator generator(context.get(), table.get(), options); std::stringstream out; ASSERT_TRUE(generator.Generate("android", &out)); std::string actual = out.str(); std::string output = out.str(); EXPECT_EQ(std::string::npos, actual.find("@attr name android:one")); EXPECT_EQ(std::string::npos, actual.find("@attr description")); EXPECT_THAT(output, Not(HasSubstr("@attr name android:one"))); EXPECT_THAT(output, Not(HasSubstr("@attr description"))); // We should find @removed only in the attribute javadoc and not anywhere else // (i.e. the class // javadoc). const size_t pos = actual.find("removed"); EXPECT_NE(std::string::npos, pos); EXPECT_EQ(std::string::npos, actual.find("removed", pos + 1)); // (i.e. the class javadoc). const std::string kRemoved("removed"); ASSERT_THAT(output, HasSubstr(kRemoved)); std::string after_first_match = output.substr(output.find(kRemoved) + kRemoved.size()); EXPECT_THAT(after_first_match, Not(HasSubstr(kRemoved))); } TEST(JavaClassGeneratorTest, GenerateOnResourcesLoadedCallbackForSharedLibrary) { Loading @@ -381,19 +357,17 @@ TEST(JavaClassGeneratorTest, GenerateOnResourcesLoadedCallbackForSharedLibrary) JavaClassGeneratorOptions options; options.use_final = false; options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{ {"com.foo", "com.boo"}, }; options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{{"com.foo", "com.boo"}}; JavaClassGenerator generator(context.get(), table.get(), options); std::stringstream out; ASSERT_TRUE(generator.Generate("android", &out)); std::string actual = out.str(); std::string output = out.str(); EXPECT_NE(std::string::npos, actual.find("void onResourcesLoaded")); EXPECT_NE(std::string::npos, actual.find("com.foo.R.onResourcesLoaded")); EXPECT_NE(std::string::npos, actual.find("com.boo.R.onResourcesLoaded")); EXPECT_THAT(output, HasSubstr("void onResourcesLoaded")); EXPECT_THAT(output, HasSubstr("com.foo.R.onResourcesLoaded")); EXPECT_THAT(output, HasSubstr("com.boo.R.onResourcesLoaded")); } } // namespace aapt