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 static bool shouldMangle(MangleContext* mangler, NamedDecl* decl) {
     39   // Passing a decl with static linkage to the mangler gives incorrect results.
     40   // Check some things ourselves before handing it off to the mangler.
     41   if (auto FD = dyn_cast<FunctionDecl>(decl)) {
     42     if (FD->isExternC()) {
     43       return false;
     44     }
     45 
     46     if (FD->isInExternCContext()) {
     47       return false;
     48     }
     49   }
     50 
     51   return mangler->shouldMangleDeclName(decl);
     52 }
     53 
     54 class Visitor : public RecursiveASTVisitor<Visitor> {
     55   HeaderDatabase& database;
     56   CompilationType type;
     57   SourceManager& src_manager;
     58   std::unique_ptr<MangleContext> mangler;
     59 
     60  public:
     61   Visitor(HeaderDatabase& database, CompilationType type, ASTContext& ctx)
     62       : database(database), type(type), src_manager(ctx.getSourceManager()) {
     63     mangler.reset(ItaniumMangleContext::create(ctx, ctx.getDiagnostics()));
     64   }
     65 
     66   std::string getDeclName(NamedDecl* decl) {
     67     if (auto var_decl = dyn_cast<VarDecl>(decl)) {
     68       if (!var_decl->isFileVarDecl()) {
     69         return "<local var>";
     70       }
     71     }
     72 
     73     // <math.h> maps fool onto foo on 32-bit, since long double is the same as double.
     74     if (auto asm_attr = decl->getAttr<AsmLabelAttr>()) {
     75       return asm_attr->getLabel();
     76     }
     77 
     78     // The decl might not have a name (e.g. bitfields).
     79     if (auto identifier = decl->getIdentifier()) {
     80       if (shouldMangle(mangler.get(), decl)) {
     81         std::string mangled;
     82         llvm::raw_string_ostream ss(mangled);
     83         mangler->mangleName(decl, ss);
     84         return mangled;
     85       }
     86 
     87       return identifier->getName();
     88     }
     89 
     90     return "<unnamed>";
     91   }
     92 
     93   bool VisitDeclaratorDecl(DeclaratorDecl* decl, SourceRange range) {
     94     // Skip declarations inside of functions (function arguments, variable declarations inside of
     95     // inline functions, etc).
     96     if (decl->getParentFunctionOrMethod()) {
     97       return true;
     98     }
     99 
    100     auto named_decl = dyn_cast<NamedDecl>(decl);
    101     if (!named_decl) {
    102       return true;
    103     }
    104 
    105     std::string declaration_name = getDeclName(named_decl);
    106     bool is_extern = named_decl->getFormalLinkage() == ExternalLinkage;
    107     bool is_definition = false;
    108     bool no_guard = false;
    109 
    110     if (auto function_decl = dyn_cast<FunctionDecl>(decl)) {
    111       is_definition = function_decl->isThisDeclarationADefinition();
    112     } else if (auto var_decl = dyn_cast<VarDecl>(decl)) {
    113       if (!var_decl->isFileVarDecl()) {
    114         return true;
    115       }
    116 
    117       switch (var_decl->isThisDeclarationADefinition()) {
    118         case VarDecl::DeclarationOnly:
    119           is_definition = false;
    120           break;
    121 
    122         case VarDecl::Definition:
    123           is_definition = true;
    124           break;
    125 
    126         case VarDecl::TentativeDefinition:
    127           // Forbid tentative definitions in headers.
    128           fprintf(stderr, "ERROR: declaration '%s' is a tentative definition\n",
    129                   declaration_name.c_str());
    130           decl->dump();
    131           abort();
    132       }
    133     } else {
    134       // We only care about function and variable declarations.
    135       return true;
    136     }
    137 
    138     if (decl->hasAttr<UnavailableAttr>()) {
    139       // Skip declarations that exist only for compile-time diagnostics.
    140       return true;
    141     }
    142 
    143     DeclarationAvailability availability;
    144 
    145     // Find and parse __ANDROID_AVAILABILITY_DUMP__ annotations.
    146     for (const AnnotateAttr* attr : decl->specific_attrs<AnnotateAttr>()) {
    147       llvm::StringRef annotation = attr->getAnnotation();
    148       if (annotation == "versioner_no_guard") {
    149         no_guard = true;
    150       } else if (annotation == "introduced_in_future") {
    151         // Tag the compiled-for arch, since this can vary across archs.
    152         availability.arch_availability[type.arch].future = true;
    153       } else {
    154         llvm::SmallVector<llvm::StringRef, 2> fragments;
    155         annotation.split(fragments, "=");
    156         if (fragments.size() != 2) {
    157           continue;
    158         }
    159 
    160         auto& global_availability = availability.global_availability;
    161         auto& arch_availability = availability.arch_availability;
    162         std::map<std::string, std::vector<int*>> prefix_map = {
    163           { "introduced_in", { &global_availability.introduced } },
    164           { "deprecated_in", { &global_availability.deprecated } },
    165           { "obsoleted_in", { &global_availability.obsoleted } },
    166           { "introduced_in_arm", { &arch_availability[Arch::arm].introduced } },
    167           { "introduced_in_mips", { &arch_availability[Arch::mips].introduced } },
    168           { "introduced_in_x86", { &arch_availability[Arch::x86].introduced } },
    169           { "introduced_in_32",
    170             { &arch_availability[Arch::arm].introduced,
    171               &arch_availability[Arch::mips].introduced,
    172               &arch_availability[Arch::x86].introduced } },
    173           { "introduced_in_64",
    174             { &arch_availability[Arch::arm64].introduced,
    175               &arch_availability[Arch::mips64].introduced,
    176               &arch_availability[Arch::x86_64].introduced } },
    177         };
    178 
    179         if (auto it = prefix_map.find(fragments[0]); it != prefix_map.end()) {
    180           int value;
    181           if (fragments[1].getAsInteger(10, value)) {
    182             errx(1, "invalid __ANDROID_AVAILABILITY_DUMP__ annotation: '%s'",
    183                  annotation.str().c_str());
    184           }
    185 
    186           for (int* ptr : it->second) {
    187             *ptr = value;
    188           }
    189         }
    190       }
    191     }
    192 
    193     auto symbol_it = database.symbols.find(declaration_name);
    194     if (symbol_it == database.symbols.end()) {
    195       Symbol symbol = {.name = declaration_name };
    196       bool dummy;
    197       std::tie(symbol_it, dummy) = database.symbols.insert({ declaration_name, symbol });
    198     }
    199 
    200     auto expansion_range = src_manager.getExpansionRange(range);
    201     auto filename = src_manager.getFilename(expansion_range.getBegin());
    202     if (filename != src_manager.getFilename(expansion_range.getEnd())) {
    203       errx(1, "expansion range filenames don't match");
    204     }
    205 
    206     Location location = {
    207       .filename = filename,
    208       .start = {
    209         .line = src_manager.getExpansionLineNumber(expansion_range.getBegin()),
    210         .column = src_manager.getExpansionColumnNumber(expansion_range.getBegin()),
    211       },
    212       .end = {
    213         .line = src_manager.getExpansionLineNumber(expansion_range.getEnd()),
    214         .column = src_manager.getExpansionColumnNumber(expansion_range.getEnd()),
    215       }
    216     };
    217 
    218     // Find or insert an entry for the declaration.
    219     if (auto declaration_it = symbol_it->second.declarations.find(location);
    220         declaration_it != symbol_it->second.declarations.end()) {
    221       if (declaration_it->second.is_extern != is_extern ||
    222           declaration_it->second.is_definition != is_definition ||
    223           declaration_it->second.no_guard != no_guard) {
    224         errx(1, "varying declaration of '%s' at %s:%u:%u", declaration_name.c_str(),
    225              location.filename.c_str(), location.start.line, location.start.column);
    226       }
    227       declaration_it->second.availability.insert(std::make_pair(type, availability));
    228     } else {
    229       Declaration declaration;
    230       declaration.name = declaration_name;
    231       declaration.location = location;
    232       declaration.is_extern = is_extern;
    233       declaration.is_definition = is_definition;
    234       declaration.no_guard = no_guard;
    235       declaration.availability.insert(std::make_pair(type, availability));
    236       symbol_it->second.declarations.insert(std::make_pair(location, declaration));
    237     }
    238 
    239     return true;
    240   }
    241 
    242   bool VisitDeclaratorDecl(DeclaratorDecl* decl) {
    243     return VisitDeclaratorDecl(decl, decl->getSourceRange());
    244   }
    245 
    246   bool TraverseLinkageSpecDecl(LinkageSpecDecl* decl) {
    247     // Make sure that we correctly calculate the SourceRange of a declaration that has a non-braced
    248     // extern "C"/"C++".
    249     if (!decl->hasBraces()) {
    250       DeclaratorDecl* child = nullptr;
    251       for (auto child_decl : decl->decls()) {
    252         if (child != nullptr) {
    253           errx(1, "LinkageSpecDecl has multiple children");
    254         }
    255 
    256         if (DeclaratorDecl* declarator_decl = dyn_cast<DeclaratorDecl>(child_decl)) {
    257           child = declarator_decl;
    258         } else {
    259           errx(1, "child of LinkageSpecDecl is not a DeclaratorDecl");
    260         }
    261       }
    262 
    263       return VisitDeclaratorDecl(child, decl->getSourceRange());
    264     }
    265 
    266     for (auto child : decl->decls()) {
    267       if (!TraverseDecl(child)) {
    268         return false;
    269       }
    270     }
    271     return true;
    272   }
    273 };
    274 
    275 bool DeclarationAvailability::merge(const DeclarationAvailability& other) {
    276 #define check_avail(expr) error |= (!this->expr.empty() && this->expr != other.expr);
    277   bool error = false;
    278 
    279   if (!other.global_availability.empty()) {
    280     check_avail(global_availability);
    281     this->global_availability = other.global_availability;
    282   }
    283 
    284   for (Arch arch : supported_archs) {
    285     if (!other.arch_availability[arch].empty()) {
    286       check_avail(arch_availability[arch]);
    287       this->arch_availability[arch] = other.arch_availability[arch];
    288     }
    289   }
    290 #undef check_avail
    291 
    292   return !error;
    293 }
    294 
    295 bool Declaration::calculateAvailability(DeclarationAvailability* output) const {
    296   DeclarationAvailability avail;
    297   for (const auto& it : this->availability) {
    298     if (!avail.merge(it.second)) {
    299       return false;
    300     }
    301   }
    302   *output = avail;
    303   return true;
    304 }
    305 
    306 bool Symbol::calculateAvailability(DeclarationAvailability* output) const {
    307   DeclarationAvailability avail;
    308   for (const auto& it : this->declarations) {
    309     // Don't merge availability for inline functions (because they shouldn't have any).
    310     if (it.second.is_definition) {
    311       continue;
    312     }
    313 
    314     DeclarationAvailability decl_availability;
    315     if (!it.second.calculateAvailability(&decl_availability)) {
    316       return false;
    317       abort();
    318     }
    319 
    320     if (!avail.merge(decl_availability)) {
    321       return false;
    322     }
    323   }
    324   *output = avail;
    325   return true;
    326 }
    327 
    328 bool Symbol::hasDeclaration(const CompilationType& type) const {
    329   for (const auto& decl_it : this->declarations) {
    330     for (const auto& compilation_it : decl_it.second.availability) {
    331       if (compilation_it.first == type) {
    332         return true;
    333       }
    334     }
    335   }
    336   return false;
    337 }
    338 
    339 void HeaderDatabase::parseAST(CompilationType type, ASTContext& ctx) {
    340   std::unique_lock<std::mutex> lock(this->mutex);
    341   Visitor visitor(*this, type, ctx);
    342   visitor.TraverseDecl(ctx.getTranslationUnitDecl());
    343 }
    344 
    345 std::string to_string(const AvailabilityValues& av) {
    346   std::stringstream ss;
    347 
    348   if (av.future) {
    349     ss << "future, ";
    350   }
    351 
    352   if (av.introduced != 0) {
    353     ss << "introduced = " << av.introduced << ", ";
    354   }
    355 
    356   if (av.deprecated != 0) {
    357     ss << "deprecated = " << av.deprecated << ", ";
    358   }
    359 
    360   if (av.obsoleted != 0) {
    361     ss << "obsoleted = " << av.obsoleted << ", ";
    362   }
    363 
    364   std::string result = ss.str();
    365   if (!result.empty()) {
    366     result = result.substr(0, result.length() - 2);
    367   }
    368   return result;
    369 }
    370 
    371 std::string to_string(const DeclarationType& type) {
    372   switch (type) {
    373     case DeclarationType::function:
    374       return "function";
    375     case DeclarationType::variable:
    376       return "variable";
    377     case DeclarationType::inconsistent:
    378       return "inconsistent";
    379   }
    380   abort();
    381 }
    382 
    383 std::string to_string(const DeclarationAvailability& decl_av) {
    384   std::stringstream ss;
    385   if (!decl_av.global_availability.empty()) {
    386     ss << to_string(decl_av.global_availability) << ", ";
    387   }
    388 
    389   for (const auto& it : decl_av.arch_availability) {
    390     if (!it.second.empty()) {
    391       ss << to_string(it.first) << ": " << to_string(it.second) << ", ";
    392     }
    393   }
    394 
    395   std::string result = ss.str();
    396   if (result.size() == 0) {
    397     return "no availability";
    398   }
    399 
    400   return result.substr(0, result.length() - 2);
    401 }
    402 
    403 std::string to_string(const Location& loc) {
    404   std::stringstream ss;
    405   ss << loc.filename << ":" << loc.start.line << ":" << loc.start.column;
    406   return ss.str();
    407 }
    408