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 { 151 llvm::SmallVector<llvm::StringRef, 2> fragments; 152 annotation.split(fragments, "="); 153 if (fragments.size() != 2) { 154 continue; 155 } 156 157 auto& global_availability = availability.global_availability; 158 auto& arch_availability = availability.arch_availability; 159 std::map<std::string, std::vector<int*>> prefix_map = { 160 { "introduced_in", { &global_availability.introduced } }, 161 { "deprecated_in", { &global_availability.deprecated } }, 162 { "obsoleted_in", { &global_availability.obsoleted } }, 163 { "introduced_in_arm", { &arch_availability[Arch::arm].introduced } }, 164 { "introduced_in_mips", { &arch_availability[Arch::mips].introduced } }, 165 { "introduced_in_x86", { &arch_availability[Arch::x86].introduced } }, 166 { "introduced_in_32", 167 { &arch_availability[Arch::arm].introduced, 168 &arch_availability[Arch::mips].introduced, 169 &arch_availability[Arch::x86].introduced } }, 170 { "introduced_in_64", 171 { &arch_availability[Arch::arm64].introduced, 172 &arch_availability[Arch::mips64].introduced, 173 &arch_availability[Arch::x86_64].introduced } }, 174 }; 175 176 if (auto it = prefix_map.find(fragments[0]); it != prefix_map.end()) { 177 int value; 178 if (fragments[1].getAsInteger(10, value)) { 179 errx(1, "invalid __ANDROID_AVAILABILITY_DUMP__ annotation: '%s'", 180 annotation.str().c_str()); 181 } 182 183 for (int* ptr : it->second) { 184 *ptr = value; 185 } 186 } 187 } 188 } 189 190 auto symbol_it = database.symbols.find(declaration_name); 191 if (symbol_it == database.symbols.end()) { 192 Symbol symbol = {.name = declaration_name }; 193 bool dummy; 194 std::tie(symbol_it, dummy) = database.symbols.insert({ declaration_name, symbol }); 195 } 196 197 auto expansion_range = src_manager.getExpansionRange(range); 198 auto filename = src_manager.getFilename(expansion_range.getBegin()); 199 if (filename != src_manager.getFilename(expansion_range.getEnd())) { 200 errx(1, "expansion range filenames don't match"); 201 } 202 203 Location location = { 204 .filename = filename, 205 .start = { 206 .line = src_manager.getExpansionLineNumber(expansion_range.getBegin()), 207 .column = src_manager.getExpansionColumnNumber(expansion_range.getBegin()), 208 }, 209 .end = { 210 .line = src_manager.getExpansionLineNumber(expansion_range.getEnd()), 211 .column = src_manager.getExpansionColumnNumber(expansion_range.getEnd()), 212 } 213 }; 214 215 // Find or insert an entry for the declaration. 216 if (auto declaration_it = symbol_it->second.declarations.find(location); 217 declaration_it != symbol_it->second.declarations.end()) { 218 if (declaration_it->second.is_extern != is_extern || 219 declaration_it->second.is_definition != is_definition || 220 declaration_it->second.no_guard != no_guard) { 221 errx(1, "varying declaration of '%s' at %s:%u:%u", declaration_name.c_str(), 222 location.filename.c_str(), location.start.line, location.start.column); 223 } 224 declaration_it->second.availability.insert(std::make_pair(type, availability)); 225 } else { 226 Declaration declaration; 227 declaration.name = declaration_name; 228 declaration.location = location; 229 declaration.is_extern = is_extern; 230 declaration.is_definition = is_definition; 231 declaration.no_guard = no_guard; 232 declaration.availability.insert(std::make_pair(type, availability)); 233 symbol_it->second.declarations.insert(std::make_pair(location, declaration)); 234 } 235 236 return true; 237 } 238 239 bool VisitDeclaratorDecl(DeclaratorDecl* decl) { 240 return VisitDeclaratorDecl(decl, decl->getSourceRange()); 241 } 242 243 bool TraverseLinkageSpecDecl(LinkageSpecDecl* decl) { 244 // Make sure that we correctly calculate the SourceRange of a declaration that has a non-braced 245 // extern "C"/"C++". 246 if (!decl->hasBraces()) { 247 DeclaratorDecl* child = nullptr; 248 for (auto child_decl : decl->decls()) { 249 if (child != nullptr) { 250 errx(1, "LinkageSpecDecl has multiple children"); 251 } 252 253 if (DeclaratorDecl* declarator_decl = dyn_cast<DeclaratorDecl>(child_decl)) { 254 child = declarator_decl; 255 } else { 256 errx(1, "child of LinkageSpecDecl is not a DeclaratorDecl"); 257 } 258 } 259 260 return VisitDeclaratorDecl(child, decl->getSourceRange()); 261 } 262 263 for (auto child : decl->decls()) { 264 if (!TraverseDecl(child)) { 265 return false; 266 } 267 } 268 return true; 269 } 270 }; 271 272 bool DeclarationAvailability::merge(const DeclarationAvailability& other) { 273 #define check_avail(expr) error |= (!this->expr.empty() && this->expr != other.expr); 274 bool error = false; 275 276 if (!other.global_availability.empty()) { 277 check_avail(global_availability); 278 this->global_availability = other.global_availability; 279 } 280 281 for (Arch arch : supported_archs) { 282 if (!other.arch_availability[arch].empty()) { 283 check_avail(arch_availability[arch]); 284 this->arch_availability[arch] = other.arch_availability[arch]; 285 } 286 } 287 #undef check_avail 288 289 return !error; 290 } 291 292 bool Declaration::calculateAvailability(DeclarationAvailability* output) const { 293 DeclarationAvailability avail; 294 for (const auto& it : this->availability) { 295 if (!avail.merge(it.second)) { 296 return false; 297 } 298 } 299 *output = avail; 300 return true; 301 } 302 303 bool Symbol::calculateAvailability(DeclarationAvailability* output) const { 304 DeclarationAvailability avail; 305 for (const auto& it : this->declarations) { 306 // Don't merge availability for inline functions (because they shouldn't have any). 307 if (it.second.is_definition) { 308 continue; 309 } 310 311 DeclarationAvailability decl_availability; 312 if (!it.second.calculateAvailability(&decl_availability)) { 313 return false; 314 abort(); 315 } 316 317 if (!avail.merge(decl_availability)) { 318 return false; 319 } 320 } 321 *output = avail; 322 return true; 323 } 324 325 bool Symbol::hasDeclaration(const CompilationType& type) const { 326 for (const auto& decl_it : this->declarations) { 327 for (const auto& compilation_it : decl_it.second.availability) { 328 if (compilation_it.first == type) { 329 return true; 330 } 331 } 332 } 333 return false; 334 } 335 336 void HeaderDatabase::parseAST(CompilationType type, ASTContext& ctx) { 337 std::unique_lock<std::mutex> lock(this->mutex); 338 Visitor visitor(*this, type, ctx); 339 visitor.TraverseDecl(ctx.getTranslationUnitDecl()); 340 } 341 342 std::string to_string(const AvailabilityValues& av) { 343 std::stringstream ss; 344 345 if (av.introduced != 0) { 346 ss << "introduced = " << av.introduced << ", "; 347 } 348 349 if (av.deprecated != 0) { 350 ss << "deprecated = " << av.deprecated << ", "; 351 } 352 353 if (av.obsoleted != 0) { 354 ss << "obsoleted = " << av.obsoleted << ", "; 355 } 356 357 std::string result = ss.str(); 358 if (!result.empty()) { 359 result = result.substr(0, result.length() - 2); 360 } 361 return result; 362 } 363 364 std::string to_string(const DeclarationType& type) { 365 switch (type) { 366 case DeclarationType::function: 367 return "function"; 368 case DeclarationType::variable: 369 return "variable"; 370 case DeclarationType::inconsistent: 371 return "inconsistent"; 372 } 373 abort(); 374 } 375 376 std::string to_string(const DeclarationAvailability& decl_av) { 377 std::stringstream ss; 378 if (!decl_av.global_availability.empty()) { 379 ss << to_string(decl_av.global_availability) << ", "; 380 } 381 382 for (const auto& it : decl_av.arch_availability) { 383 if (!it.second.empty()) { 384 ss << to_string(it.first) << ": " << to_string(it.second) << ", "; 385 } 386 } 387 388 std::string result = ss.str(); 389 if (result.size() == 0) { 390 return "no availability"; 391 } 392 393 return result.substr(0, result.length() - 2); 394 } 395 396 std::string to_string(const Location& loc) { 397 std::stringstream ss; 398 ss << loc.filename << ":" << loc.start.line << ":" << loc.start.column; 399 return ss.str(); 400 } 401