Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2016 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 "DeclarationDatabase.h"
     18 
     19 #include <err.h>
     20 
     21 #include <iostream>
     22 #include <map>
     23 #include <mutex>
     24 #include <set>
     25 #include <sstream>
     26 #include <string>
     27 #include <utility>
     28 
     29 #include <clang/AST/AST.h>
     30 #include <clang/AST/Attr.h>
     31 #include <clang/AST/Mangle.h>
     32 #include <clang/AST/RecursiveASTVisitor.h>
     33 #include <clang/Frontend/ASTUnit.h>
     34 #include <llvm/Support/raw_ostream.h>
     35 
     36 using namespace clang;
     37 
     38 class Visitor : public RecursiveASTVisitor<Visitor> {
     39   HeaderDatabase& database;
     40   CompilationType type;
     41   SourceManager& src_manager;
     42   std::unique_ptr<MangleContext> mangler;
     43 
     44  public:
     45   Visitor(HeaderDatabase& database, CompilationType type, ASTContext& ctx)
     46       : database(database), type(type), src_manager(ctx.getSourceManager()) {
     47     mangler.reset(ItaniumMangleContext::create(ctx, ctx.getDiagnostics()));
     48   }
     49 
     50   std::string getDeclName(NamedDecl* decl) {
     51     if (auto var_decl = dyn_cast<VarDecl>(decl)) {
     52       if (!var_decl->isFileVarDecl()) {
     53         return "<local var>";
     54       }
     55     }
     56 
     57     if (mangler->shouldMangleDeclName(decl)) {
     58       std::string mangled;
     59       llvm::raw_string_ostream ss(mangled);
     60       mangler->mangleName(decl, ss);
     61       return mangled;
     62     }
     63 
     64     if (auto identifier = decl->getIdentifier()) {
     65       return identifier->getName();
     66     }
     67     return "<error>";
     68   }
     69 
     70   bool VisitDecl(Decl* decl) {
     71     // Skip declarations inside of functions (function arguments, variable declarations inside of
     72     // inline functions, etc).
     73     if (decl->getParentFunctionOrMethod()) {
     74       return true;
     75     }
     76 
     77     auto named_decl = dyn_cast<NamedDecl>(decl);
     78     if (!named_decl) {
     79       return true;
     80     }
     81 
     82     DeclarationType declaration_type;
     83     std::string declaration_name = getDeclName(named_decl);
     84     bool is_extern = named_decl->getFormalLinkage() == ExternalLinkage;
     85     bool is_definition = false;
     86     bool no_guard = false;
     87 
     88     if (auto function_decl = dyn_cast<FunctionDecl>(decl)) {
     89       declaration_type = DeclarationType::function;
     90       is_definition = function_decl->isThisDeclarationADefinition();
     91     } else if (auto var_decl = dyn_cast<VarDecl>(decl)) {
     92       if (!var_decl->isFileVarDecl()) {
     93         return true;
     94       }
     95 
     96       declaration_type = DeclarationType::variable;
     97       switch (var_decl->isThisDeclarationADefinition()) {
     98         case VarDecl::DeclarationOnly:
     99           is_definition = false;
    100           break;
    101 
    102         case VarDecl::Definition:
    103           is_definition = true;
    104           break;
    105 
    106         case VarDecl::TentativeDefinition:
    107           // Forbid tentative definitions in headers.
    108           fprintf(stderr, "ERROR: declaration '%s' is a tentative definition\n",
    109                   declaration_name.c_str());
    110           decl->dump();
    111           abort();
    112       }
    113     } else {
    114       // We only care about function and variable declarations.
    115       return true;
    116     }
    117 
    118     if (decl->hasAttr<UnavailableAttr>()) {
    119       // Skip declarations that exist only for compile-time diagnostics.
    120       return true;
    121     }
    122 
    123     auto start_loc = src_manager.getPresumedLoc(decl->getLocStart());
    124     auto end_loc = src_manager.getPresumedLoc(decl->getLocEnd());
    125 
    126     Location location = {
    127       .filename = start_loc.getFilename(),
    128       .start = {
    129         .line = start_loc.getLine(),
    130         .column = start_loc.getColumn(),
    131       },
    132       .end = {
    133         .line = end_loc.getLine(),
    134         .column = end_loc.getColumn(),
    135       }
    136     };
    137 
    138     DeclarationAvailability availability;
    139 
    140     // Find and parse __ANDROID_AVAILABILITY_DUMP__ annotations.
    141     for (const AnnotateAttr* attr : decl->specific_attrs<AnnotateAttr>()) {
    142       llvm::StringRef annotation = attr->getAnnotation();
    143       if (annotation == "versioner_no_guard") {
    144         no_guard = true;
    145       } else if (annotation == "introduced_in_future") {
    146         // Tag the compiled-for arch, since this can vary across archs.
    147         availability.arch_availability[type.arch].future = true;
    148       } else {
    149         llvm::SmallVector<llvm::StringRef, 2> fragments;
    150         annotation.split(fragments, "=");
    151         if (fragments.size() != 2) {
    152           continue;
    153         }
    154 
    155         auto& global_availability = availability.global_availability;
    156         auto& arch_availability = availability.arch_availability;
    157         std::map<std::string, std::vector<int*>> prefix_map = {
    158           { "introduced_in", { &global_availability.introduced } },
    159           { "deprecated_in", { &global_availability.deprecated } },
    160           { "obsoleted_in", { &global_availability.obsoleted } },
    161           { "introduced_in_arm", { &arch_availability[Arch::arm].introduced } },
    162           { "introduced_in_mips", { &arch_availability[Arch::mips].introduced } },
    163           { "introduced_in_x86", { &arch_availability[Arch::x86].introduced } },
    164           { "introduced_in_32",
    165             { &arch_availability[Arch::arm].introduced,
    166               &arch_availability[Arch::mips].introduced,
    167               &arch_availability[Arch::x86].introduced } },
    168           { "introduced_in_64",
    169             { &arch_availability[Arch::arm64].introduced,
    170               &arch_availability[Arch::mips64].introduced,
    171               &arch_availability[Arch::x86_64].introduced } },
    172         };
    173 
    174         if (auto it = prefix_map.find(fragments[0]); it != prefix_map.end()) {
    175           int value;
    176           if (fragments[1].getAsInteger(10, value)) {
    177             errx(1, "invalid __ANDROID_AVAILABILITY_DUMP__ annotation: '%s'",
    178                  annotation.str().c_str());
    179           }
    180 
    181           for (int* ptr : it->second) {
    182             *ptr = value;
    183           }
    184         }
    185       }
    186     }
    187 
    188     auto symbol_it = database.symbols.find(declaration_name);
    189     if (symbol_it == database.symbols.end()) {
    190       Symbol symbol = {.name = declaration_name };
    191       bool dummy;
    192       std::tie(symbol_it, dummy) = database.symbols.insert({ declaration_name, symbol });
    193     }
    194 
    195     // Find or insert an entry for the declaration.
    196     if (auto declaration_it = symbol_it->second.declarations.find(location);
    197         declaration_it != symbol_it->second.declarations.end()) {
    198       if (declaration_it->second.is_extern != is_extern ||
    199           declaration_it->second.is_definition != is_definition ||
    200           declaration_it->second.no_guard != no_guard) {
    201         errx(1, "varying declaration of '%s' at %s:%u:%u", declaration_name.c_str(),
    202              location.filename.c_str(), location.start.line, location.start.column);
    203       }
    204       declaration_it->second.availability.insert(std::make_pair(type, availability));
    205     } else {
    206       Declaration declaration;
    207       declaration.name = declaration_name;
    208       declaration.location = location;
    209       declaration.is_extern = is_extern;
    210       declaration.is_definition = is_definition;
    211       declaration.no_guard = no_guard;
    212       declaration.availability.insert(std::make_pair(type, availability));
    213       symbol_it->second.declarations.insert(std::make_pair(location, declaration));
    214     }
    215 
    216     return true;
    217   }
    218 };
    219 
    220 bool DeclarationAvailability::merge(const DeclarationAvailability& other) {
    221 #define check_avail(expr) error |= (!this->expr.empty() && this->expr != other.expr);
    222   bool error = false;
    223 
    224   if (!other.global_availability.empty()) {
    225     check_avail(global_availability);
    226     this->global_availability = other.global_availability;
    227   }
    228 
    229   for (Arch arch : supported_archs) {
    230     if (!other.arch_availability[arch].empty()) {
    231       check_avail(arch_availability[arch]);
    232       this->arch_availability[arch] = other.arch_availability[arch];
    233     }
    234   }
    235 #undef check_avail
    236 
    237   return !error;
    238 }
    239 
    240 bool Declaration::calculateAvailability(DeclarationAvailability* output) const {
    241   DeclarationAvailability avail;
    242   for (const auto& it : this->availability) {
    243     if (!avail.merge(it.second)) {
    244       return false;
    245     }
    246   }
    247   *output = avail;
    248   return true;
    249 }
    250 
    251 bool Symbol::calculateAvailability(DeclarationAvailability* output) const {
    252   DeclarationAvailability avail;
    253   for (const auto& it : this->declarations) {
    254     // Don't merge availability for inline functions (because they shouldn't have any).
    255     if (it.second.is_definition) {
    256       continue;
    257     }
    258 
    259     DeclarationAvailability decl_availability;
    260     if (!it.second.calculateAvailability(&decl_availability)) {
    261       return false;
    262       abort();
    263     }
    264 
    265     if (!avail.merge(decl_availability)) {
    266       return false;
    267     }
    268   }
    269   *output = avail;
    270   return true;
    271 }
    272 
    273 bool Symbol::hasDeclaration(const CompilationType& type) const {
    274   for (const auto& decl_it : this->declarations) {
    275     for (const auto& compilation_it : decl_it.second.availability) {
    276       if (compilation_it.first == type) {
    277         return true;
    278       }
    279     }
    280   }
    281   return false;
    282 }
    283 
    284 void HeaderDatabase::parseAST(CompilationType type, ASTContext& ctx) {
    285   std::unique_lock<std::mutex> lock(this->mutex);
    286   Visitor visitor(*this, type, ctx);
    287   visitor.TraverseDecl(ctx.getTranslationUnitDecl());
    288 }
    289 
    290 std::string to_string(const AvailabilityValues& av) {
    291   std::stringstream ss;
    292 
    293   if (av.future) {
    294     ss << "future, ";
    295   }
    296 
    297   if (av.introduced != 0) {
    298     ss << "introduced = " << av.introduced << ", ";
    299   }
    300 
    301   if (av.deprecated != 0) {
    302     ss << "deprecated = " << av.deprecated << ", ";
    303   }
    304 
    305   if (av.obsoleted != 0) {
    306     ss << "obsoleted = " << av.obsoleted << ", ";
    307   }
    308 
    309   std::string result = ss.str();
    310   if (!result.empty()) {
    311     result = result.substr(0, result.length() - 2);
    312   }
    313   return result;
    314 }
    315 
    316 std::string to_string(const DeclarationType& type) {
    317   switch (type) {
    318     case DeclarationType::function:
    319       return "function";
    320     case DeclarationType::variable:
    321       return "variable";
    322     case DeclarationType::inconsistent:
    323       return "inconsistent";
    324   }
    325   abort();
    326 }
    327 
    328 std::string to_string(const DeclarationAvailability& decl_av) {
    329   std::stringstream ss;
    330   if (!decl_av.global_availability.empty()) {
    331     ss << to_string(decl_av.global_availability) << ", ";
    332   }
    333 
    334   for (const auto& it : decl_av.arch_availability) {
    335     if (!it.second.empty()) {
    336       ss << to_string(it.first) << ": " << to_string(it.second) << ", ";
    337     }
    338   }
    339 
    340   std::string result = ss.str();
    341   if (result.size() == 0) {
    342     return "no availability";
    343   }
    344 
    345   return result.substr(0, result.length() - 2);
    346 }
    347 
    348 std::string to_string(const Location& loc) {
    349   std::stringstream ss;
    350   ss << loc.filename << ":" << loc.start.line << ":" << loc.start.column;
    351   return ss.str();
    352 }
    353