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 36using namespace clang; 37 38class 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 220bool 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 240bool 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 251bool 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 273bool 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 284void 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 290std::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 316std::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 328std::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 348std::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