Home | History | Annotate | Download | only in java
      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