1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "java/AnnotationProcessor.h" 18 19 #include <algorithm> 20 #include <array> 21 22 #include "text/Unicode.h" 23 #include "text/Utf8Iterator.h" 24 #include "util/Util.h" 25 26 using ::aapt::text::Printer; 27 using ::aapt::text::Utf8Iterator; 28 using ::android::StringPiece; 29 30 namespace aapt { 31 32 StringPiece AnnotationProcessor::ExtractFirstSentence(const StringPiece& comment) { 33 Utf8Iterator iter(comment); 34 while (iter.HasNext()) { 35 const char32_t codepoint = iter.Next(); 36 if (codepoint == U'.') { 37 const size_t current_position = iter.Position(); 38 if (!iter.HasNext() || text::IsWhitespace(iter.Next())) { 39 return comment.substr(0, current_position); 40 } 41 } 42 } 43 return comment; 44 } 45 46 struct AnnotationRule { 47 enum : uint32_t { 48 kDeprecated = 0x01, 49 kSystemApi = 0x02, 50 kTestApi = 0x04, 51 }; 52 53 StringPiece doc_str; 54 uint32_t bit_mask; 55 StringPiece annotation; 56 }; 57 58 static std::array<AnnotationRule, 2> sAnnotationRules = {{ 59 {"@SystemApi", AnnotationRule::kSystemApi, "@android.annotation.SystemApi"}, 60 {"@TestApi", AnnotationRule::kTestApi, "@android.annotation.TestApi"}, 61 }}; 62 63 void AnnotationProcessor::AppendCommentLine(std::string comment) { 64 static const std::string sDeprecated = "@deprecated"; 65 66 // Treat deprecated specially, since we don't remove it from the source comment. 67 if (comment.find(sDeprecated) != std::string::npos) { 68 annotation_bit_mask_ |= AnnotationRule::kDeprecated; 69 } 70 71 for (const AnnotationRule& rule : sAnnotationRules) { 72 std::string::size_type idx = comment.find(rule.doc_str.data()); 73 if (idx != std::string::npos) { 74 annotation_bit_mask_ |= rule.bit_mask; 75 comment.erase(comment.begin() + idx, comment.begin() + idx + rule.doc_str.size()); 76 } 77 } 78 79 // Check if after removal of annotations the line is empty. 80 const StringPiece trimmed = util::TrimWhitespace(comment); 81 if (trimmed.empty()) { 82 return; 83 } 84 85 // If there was trimming to do, copy the string. 86 if (trimmed.size() != comment.size()) { 87 comment = trimmed.to_string(); 88 } 89 90 if (!has_comments_) { 91 has_comments_ = true; 92 comment_ << "/**"; 93 } 94 comment_ << "\n * " << std::move(comment); 95 } 96 97 void AnnotationProcessor::AppendComment(const StringPiece& comment) { 98 // We need to process line by line to clean-up whitespace and append prefixes. 99 for (StringPiece line : util::Tokenize(comment, '\n')) { 100 line = util::TrimWhitespace(line); 101 if (!line.empty()) { 102 AppendCommentLine(line.to_string()); 103 } 104 } 105 } 106 107 void AnnotationProcessor::AppendNewLine() { 108 if (has_comments_) { 109 comment_ << "\n *"; 110 } 111 } 112 113 void AnnotationProcessor::Print(Printer* printer) const { 114 if (has_comments_) { 115 std::string result = comment_.str(); 116 for (const StringPiece& line : util::Tokenize(result, '\n')) { 117 printer->Println(line); 118 } 119 printer->Println(" */"); 120 } 121 122 if (annotation_bit_mask_ & AnnotationRule::kDeprecated) { 123 printer->Println("@Deprecated"); 124 } 125 126 for (const AnnotationRule& rule : sAnnotationRules) { 127 if (annotation_bit_mask_ & rule.bit_mask) { 128 printer->Println(rule.annotation); 129 } 130 } 131 } 132 133 } // namespace aapt 134