| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 1 | /* | 
| Elliott Hughes | dfb74c5 | 2016-10-24 12:53:17 -0700 | [diff] [blame] | 2 | * Copyright (C) 2016 The Android Open Source Project | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 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 | * | 
| Elliott Hughes | dfb74c5 | 2016-10-24 12:53:17 -0700 | [diff] [blame] | 8 | *      http://www.apache.org/licenses/LICENSE-2.0 | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 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 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 19 | #include <err.h> | 
|  | 20 |  | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 21 | #include <iostream> | 
|  | 22 | #include <map> | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 23 | #include <mutex> | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 24 | #include <set> | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 25 | #include <sstream> | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 26 | #include <string> | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 27 | #include <utility> | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 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 |  | 
| Josh Gao | ab25d0b | 2017-08-10 10:50:33 -0700 | [diff] [blame] | 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 |  | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 54 | class Visitor : public RecursiveASTVisitor<Visitor> { | 
|  | 55 | HeaderDatabase& database; | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 56 | CompilationType type; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 57 | SourceManager& src_manager; | 
|  | 58 | std::unique_ptr<MangleContext> mangler; | 
|  | 59 |  | 
|  | 60 | public: | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 61 | Visitor(HeaderDatabase& database, CompilationType type, ASTContext& ctx) | 
|  | 62 | : database(database), type(type), src_manager(ctx.getSourceManager()) { | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 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 |  | 
| Josh Gao | 38685e1 | 2017-10-30 12:45:09 -0700 | [diff] [blame] | 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>()) { | 
| Stephen Hines | 25b8af4 | 2020-05-01 03:44:40 -0700 | [diff] [blame] | 75 | return asm_attr->getLabel().str(); | 
| Josh Gao | 38685e1 | 2017-10-30 12:45:09 -0700 | [diff] [blame] | 76 | } | 
|  | 77 |  | 
| Josh Gao | 0062b3e | 2017-10-24 17:03:58 -0700 | [diff] [blame] | 78 | // The decl might not have a name (e.g. bitfields). | 
| Josh Gao | 0a284f5 | 2016-12-15 13:56:00 -0800 | [diff] [blame] | 79 | if (auto identifier = decl->getIdentifier()) { | 
| Josh Gao | ab25d0b | 2017-08-10 10:50:33 -0700 | [diff] [blame] | 80 | if (shouldMangle(mangler.get(), decl)) { | 
| Josh Gao | 0062b3e | 2017-10-24 17:03:58 -0700 | [diff] [blame] | 81 | std::string mangled; | 
|  | 82 | llvm::raw_string_ostream ss(mangled); | 
|  | 83 | mangler->mangleName(decl, ss); | 
|  | 84 | return mangled; | 
|  | 85 | } | 
|  | 86 |  | 
| Stephen Hines | 25b8af4 | 2020-05-01 03:44:40 -0700 | [diff] [blame] | 87 | return identifier->getName().str(); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 88 | } | 
| Josh Gao | 0062b3e | 2017-10-24 17:03:58 -0700 | [diff] [blame] | 89 |  | 
|  | 90 | return "<unnamed>"; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 91 | } | 
|  | 92 |  | 
| Josh Gao | 8e13b67 | 2017-11-06 17:15:47 -0800 | [diff] [blame] | 93 | bool VisitDeclaratorDecl(DeclaratorDecl* decl, SourceRange range) { | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 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 |  | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 105 | std::string declaration_name = getDeclName(named_decl); | 
| Yi Kong | 29755c2 | 2024-06-13 10:24:19 +0900 | [diff] [blame] | 106 | bool is_extern = named_decl->getFormalLinkage() == Linkage::External; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 107 | bool is_definition = false; | 
| Josh Gao | fff29fe | 2016-09-07 18:29:08 -0700 | [diff] [blame] | 108 | bool no_guard = false; | 
| Logan Chien | c88331b | 2019-12-20 10:27:45 -0800 | [diff] [blame] | 109 | bool fortify_inline = false; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 110 |  | 
|  | 111 | if (auto function_decl = dyn_cast<FunctionDecl>(decl)) { | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 112 | is_definition = function_decl->isThisDeclarationADefinition(); | 
|  | 113 | } else if (auto var_decl = dyn_cast<VarDecl>(decl)) { | 
|  | 114 | if (!var_decl->isFileVarDecl()) { | 
|  | 115 | return true; | 
|  | 116 | } | 
|  | 117 |  | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 118 | switch (var_decl->isThisDeclarationADefinition()) { | 
|  | 119 | case VarDecl::DeclarationOnly: | 
|  | 120 | is_definition = false; | 
|  | 121 | break; | 
|  | 122 |  | 
|  | 123 | case VarDecl::Definition: | 
|  | 124 | is_definition = true; | 
|  | 125 | break; | 
|  | 126 |  | 
|  | 127 | case VarDecl::TentativeDefinition: | 
|  | 128 | // Forbid tentative definitions in headers. | 
|  | 129 | fprintf(stderr, "ERROR: declaration '%s' is a tentative definition\n", | 
|  | 130 | declaration_name.c_str()); | 
|  | 131 | decl->dump(); | 
|  | 132 | abort(); | 
|  | 133 | } | 
|  | 134 | } else { | 
|  | 135 | // We only care about function and variable declarations. | 
|  | 136 | return true; | 
|  | 137 | } | 
|  | 138 |  | 
|  | 139 | if (decl->hasAttr<UnavailableAttr>()) { | 
|  | 140 | // Skip declarations that exist only for compile-time diagnostics. | 
|  | 141 | return true; | 
|  | 142 | } | 
|  | 143 |  | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 144 | DeclarationAvailability availability; | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 145 |  | 
|  | 146 | // Find and parse __ANDROID_AVAILABILITY_DUMP__ annotations. | 
|  | 147 | for (const AnnotateAttr* attr : decl->specific_attrs<AnnotateAttr>()) { | 
|  | 148 | llvm::StringRef annotation = attr->getAnnotation(); | 
| Josh Gao | fff29fe | 2016-09-07 18:29:08 -0700 | [diff] [blame] | 149 | if (annotation == "versioner_no_guard") { | 
|  | 150 | no_guard = true; | 
| Logan Chien | c88331b | 2019-12-20 10:27:45 -0800 | [diff] [blame] | 151 | } else if (annotation == "versioner_fortify_inline") { | 
|  | 152 | fortify_inline = true; | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 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 } }, | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 167 | { "introduced_in_x86", { &arch_availability[Arch::x86].introduced } }, | 
|  | 168 | { "introduced_in_32", | 
|  | 169 | { &arch_availability[Arch::arm].introduced, | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 170 | &arch_availability[Arch::x86].introduced } }, | 
|  | 171 | { "introduced_in_64", | 
|  | 172 | { &arch_availability[Arch::arm64].introduced, | 
| Elliott Hughes | d7f0844 | 2022-10-04 00:36:29 +0000 | [diff] [blame] | 173 | &arch_availability[Arch::riscv64].introduced, | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 174 | &arch_availability[Arch::x86_64].introduced } }, | 
|  | 175 | }; | 
|  | 176 |  | 
| Stephen Hines | 25b8af4 | 2020-05-01 03:44:40 -0700 | [diff] [blame] | 177 | if (auto it = prefix_map.find(fragments[0].str()); it != prefix_map.end()) { | 
| Josh Gao | 0a284f5 | 2016-12-15 13:56:00 -0800 | [diff] [blame] | 178 | int value; | 
|  | 179 | if (fragments[1].getAsInteger(10, value)) { | 
|  | 180 | errx(1, "invalid __ANDROID_AVAILABILITY_DUMP__ annotation: '%s'", | 
|  | 181 | annotation.str().c_str()); | 
|  | 182 | } | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 183 |  | 
| Josh Gao | 0a284f5 | 2016-12-15 13:56:00 -0800 | [diff] [blame] | 184 | for (int* ptr : it->second) { | 
|  | 185 | *ptr = value; | 
|  | 186 | } | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 187 | } | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 188 | } | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 189 | } | 
|  | 190 |  | 
|  | 191 | auto symbol_it = database.symbols.find(declaration_name); | 
|  | 192 | if (symbol_it == database.symbols.end()) { | 
|  | 193 | Symbol symbol = {.name = declaration_name }; | 
| Elliott Hughes | 68ae6ad | 2020-07-21 16:11:30 -0700 | [diff] [blame] | 194 | bool unused; | 
|  | 195 | std::tie(symbol_it, unused) = database.symbols.insert({declaration_name, symbol}); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 196 | } | 
|  | 197 |  | 
| Josh Gao | 8e13b67 | 2017-11-06 17:15:47 -0800 | [diff] [blame] | 198 | auto expansion_range = src_manager.getExpansionRange(range); | 
|  | 199 | auto filename = src_manager.getFilename(expansion_range.getBegin()); | 
|  | 200 | if (filename != src_manager.getFilename(expansion_range.getEnd())) { | 
|  | 201 | errx(1, "expansion range filenames don't match"); | 
|  | 202 | } | 
|  | 203 |  | 
|  | 204 | Location location = { | 
| Stephen Hines | 25b8af4 | 2020-05-01 03:44:40 -0700 | [diff] [blame] | 205 | .filename = filename.str(), | 
| Josh Gao | 8e13b67 | 2017-11-06 17:15:47 -0800 | [diff] [blame] | 206 | .start = { | 
|  | 207 | .line = src_manager.getExpansionLineNumber(expansion_range.getBegin()), | 
|  | 208 | .column = src_manager.getExpansionColumnNumber(expansion_range.getBegin()), | 
|  | 209 | }, | 
|  | 210 | .end = { | 
|  | 211 | .line = src_manager.getExpansionLineNumber(expansion_range.getEnd()), | 
|  | 212 | .column = src_manager.getExpansionColumnNumber(expansion_range.getEnd()), | 
|  | 213 | } | 
|  | 214 | }; | 
|  | 215 |  | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 216 | // Find or insert an entry for the declaration. | 
| Josh Gao | 0a284f5 | 2016-12-15 13:56:00 -0800 | [diff] [blame] | 217 | if (auto declaration_it = symbol_it->second.declarations.find(location); | 
|  | 218 | declaration_it != symbol_it->second.declarations.end()) { | 
|  | 219 | if (declaration_it->second.is_extern != is_extern || | 
|  | 220 | declaration_it->second.is_definition != is_definition || | 
| Logan Chien | c88331b | 2019-12-20 10:27:45 -0800 | [diff] [blame] | 221 | declaration_it->second.no_guard != no_guard || | 
|  | 222 | declaration_it->second.fortify_inline != fortify_inline) { | 
| Josh Gao | 0a284f5 | 2016-12-15 13:56:00 -0800 | [diff] [blame] | 223 | errx(1, "varying declaration of '%s' at %s:%u:%u", declaration_name.c_str(), | 
|  | 224 | location.filename.c_str(), location.start.line, location.start.column); | 
|  | 225 | } | 
|  | 226 | declaration_it->second.availability.insert(std::make_pair(type, availability)); | 
|  | 227 | } else { | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 228 | Declaration declaration; | 
| Josh Gao | 1605788 | 2016-08-02 14:54:09 -0700 | [diff] [blame] | 229 | declaration.name = declaration_name; | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 230 | declaration.location = location; | 
|  | 231 | declaration.is_extern = is_extern; | 
|  | 232 | declaration.is_definition = is_definition; | 
| Josh Gao | fff29fe | 2016-09-07 18:29:08 -0700 | [diff] [blame] | 233 | declaration.no_guard = no_guard; | 
| Logan Chien | c88331b | 2019-12-20 10:27:45 -0800 | [diff] [blame] | 234 | declaration.fortify_inline = fortify_inline; | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 235 | declaration.availability.insert(std::make_pair(type, availability)); | 
|  | 236 | symbol_it->second.declarations.insert(std::make_pair(location, declaration)); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 237 | } | 
|  | 238 |  | 
|  | 239 | return true; | 
|  | 240 | } | 
| Josh Gao | 8e13b67 | 2017-11-06 17:15:47 -0800 | [diff] [blame] | 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 | } | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 273 | }; | 
|  | 274 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 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 |  | 
| Josh Gao | 16016df | 2016-11-07 18:27:16 -0800 | [diff] [blame] | 339 | void HeaderDatabase::parseAST(CompilationType type, ASTContext& ctx) { | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 340 | std::unique_lock<std::mutex> lock(this->mutex); | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 341 | Visitor visitor(*this, type, ctx); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 342 | visitor.TraverseDecl(ctx.getTranslationUnitDecl()); | 
|  | 343 | } | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 344 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 345 | std::string to_string(const AvailabilityValues& av) { | 
|  | 346 | std::stringstream ss; | 
|  | 347 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 348 | if (av.introduced != 0) { | 
|  | 349 | ss << "introduced = " << av.introduced << ", "; | 
|  | 350 | } | 
|  | 351 |  | 
|  | 352 | if (av.deprecated != 0) { | 
|  | 353 | ss << "deprecated = " << av.deprecated << ", "; | 
|  | 354 | } | 
|  | 355 |  | 
|  | 356 | if (av.obsoleted != 0) { | 
|  | 357 | ss << "obsoleted = " << av.obsoleted << ", "; | 
|  | 358 | } | 
|  | 359 |  | 
|  | 360 | std::string result = ss.str(); | 
|  | 361 | if (!result.empty()) { | 
|  | 362 | result = result.substr(0, result.length() - 2); | 
|  | 363 | } | 
|  | 364 | return result; | 
|  | 365 | } | 
|  | 366 |  | 
|  | 367 | std::string to_string(const DeclarationType& type) { | 
|  | 368 | switch (type) { | 
|  | 369 | case DeclarationType::function: | 
|  | 370 | return "function"; | 
|  | 371 | case DeclarationType::variable: | 
|  | 372 | return "variable"; | 
|  | 373 | case DeclarationType::inconsistent: | 
|  | 374 | return "inconsistent"; | 
|  | 375 | } | 
|  | 376 | abort(); | 
|  | 377 | } | 
|  | 378 |  | 
|  | 379 | std::string to_string(const DeclarationAvailability& decl_av) { | 
|  | 380 | std::stringstream ss; | 
|  | 381 | if (!decl_av.global_availability.empty()) { | 
|  | 382 | ss << to_string(decl_av.global_availability) << ", "; | 
|  | 383 | } | 
|  | 384 |  | 
| Josh Gao | 1605788 | 2016-08-02 14:54:09 -0700 | [diff] [blame] | 385 | for (const auto& it : decl_av.arch_availability) { | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 386 | if (!it.second.empty()) { | 
|  | 387 | ss << to_string(it.first) << ": " << to_string(it.second) << ", "; | 
|  | 388 | } | 
|  | 389 | } | 
|  | 390 |  | 
|  | 391 | std::string result = ss.str(); | 
|  | 392 | if (result.size() == 0) { | 
|  | 393 | return "no availability"; | 
|  | 394 | } | 
|  | 395 |  | 
|  | 396 | return result.substr(0, result.length() - 2); | 
|  | 397 | } | 
|  | 398 |  | 
|  | 399 | std::string to_string(const Location& loc) { | 
|  | 400 | std::stringstream ss; | 
|  | 401 | ss << loc.filename << ":" << loc.start.line << ":" << loc.start.column; | 
|  | 402 | return ss.str(); | 
|  | 403 | } |