blob: 33bccf372db81657d58f037644612750df4fd909 [file] [log] [blame]
Josh Gaobf8a2852016-05-27 11:59:09 -07001/*
Elliott Hughesdfb74c52016-10-24 12:53:17 -07002 * Copyright (C) 2016 The Android Open Source Project
Josh Gaobf8a2852016-05-27 11:59:09 -07003 *
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 Hughesdfb74c52016-10-24 12:53:17 -07008 * http://www.apache.org/licenses/LICENSE-2.0
Josh Gaobf8a2852016-05-27 11:59:09 -07009 *
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 Gaobfb6bae2016-07-15 17:25:21 -070019#include <err.h>
20
Josh Gaobf8a2852016-05-27 11:59:09 -070021#include <iostream>
22#include <map>
Josh Gaobfb6bae2016-07-15 17:25:21 -070023#include <mutex>
Josh Gaobf8a2852016-05-27 11:59:09 -070024#include <set>
Josh Gaobfb6bae2016-07-15 17:25:21 -070025#include <sstream>
Josh Gaobf8a2852016-05-27 11:59:09 -070026#include <string>
Josh Gaobfb6bae2016-07-15 17:25:21 -070027#include <utility>
Josh Gaobf8a2852016-05-27 11:59:09 -070028
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;
Josh Gaobfb6bae2016-07-15 17:25:21 -070040 CompilationType type;
Josh Gaobf8a2852016-05-27 11:59:09 -070041 SourceManager& src_manager;
42 std::unique_ptr<MangleContext> mangler;
43
44 public:
Josh Gaobfb6bae2016-07-15 17:25:21 -070045 Visitor(HeaderDatabase& database, CompilationType type, ASTContext& ctx)
46 : database(database), type(type), src_manager(ctx.getSourceManager()) {
Josh Gaobf8a2852016-05-27 11:59:09 -070047 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
Josh Gao38685e12017-10-30 12:45:09 -070057 // <math.h> maps fool onto foo on 32-bit, since long double is the same as double.
58 if (auto asm_attr = decl->getAttr<AsmLabelAttr>()) {
59 return asm_attr->getLabel();
60 }
61
Josh Gao0062b3e2017-10-24 17:03:58 -070062 // The decl might not have a name (e.g. bitfields).
Josh Gao0a284f52016-12-15 13:56:00 -080063 if (auto identifier = decl->getIdentifier()) {
Josh Gao0062b3e2017-10-24 17:03:58 -070064 if (mangler->shouldMangleDeclName(decl)) {
65 std::string mangled;
66 llvm::raw_string_ostream ss(mangled);
67 mangler->mangleName(decl, ss);
68 return mangled;
69 }
70
Josh Gao0a284f52016-12-15 13:56:00 -080071 return identifier->getName();
Josh Gaobf8a2852016-05-27 11:59:09 -070072 }
Josh Gao0062b3e2017-10-24 17:03:58 -070073
74 return "<unnamed>";
Josh Gaobf8a2852016-05-27 11:59:09 -070075 }
76
77 bool VisitDecl(Decl* decl) {
78 // Skip declarations inside of functions (function arguments, variable declarations inside of
79 // inline functions, etc).
80 if (decl->getParentFunctionOrMethod()) {
81 return true;
82 }
83
84 auto named_decl = dyn_cast<NamedDecl>(decl);
85 if (!named_decl) {
86 return true;
87 }
88
89 DeclarationType declaration_type;
90 std::string declaration_name = getDeclName(named_decl);
91 bool is_extern = named_decl->getFormalLinkage() == ExternalLinkage;
92 bool is_definition = false;
Josh Gaofff29fe2016-09-07 18:29:08 -070093 bool no_guard = false;
Josh Gaobf8a2852016-05-27 11:59:09 -070094
95 if (auto function_decl = dyn_cast<FunctionDecl>(decl)) {
96 declaration_type = DeclarationType::function;
97 is_definition = function_decl->isThisDeclarationADefinition();
98 } else if (auto var_decl = dyn_cast<VarDecl>(decl)) {
99 if (!var_decl->isFileVarDecl()) {
100 return true;
101 }
102
103 declaration_type = DeclarationType::variable;
104 switch (var_decl->isThisDeclarationADefinition()) {
105 case VarDecl::DeclarationOnly:
106 is_definition = false;
107 break;
108
109 case VarDecl::Definition:
110 is_definition = true;
111 break;
112
113 case VarDecl::TentativeDefinition:
114 // Forbid tentative definitions in headers.
115 fprintf(stderr, "ERROR: declaration '%s' is a tentative definition\n",
116 declaration_name.c_str());
117 decl->dump();
118 abort();
119 }
120 } else {
121 // We only care about function and variable declarations.
122 return true;
123 }
124
125 if (decl->hasAttr<UnavailableAttr>()) {
126 // Skip declarations that exist only for compile-time diagnostics.
127 return true;
128 }
129
Josh Gaobfb6bae2016-07-15 17:25:21 -0700130 auto start_loc = src_manager.getPresumedLoc(decl->getLocStart());
131 auto end_loc = src_manager.getPresumedLoc(decl->getLocEnd());
132
133 Location location = {
134 .filename = start_loc.getFilename(),
135 .start = {
136 .line = start_loc.getLine(),
137 .column = start_loc.getColumn(),
138 },
139 .end = {
140 .line = end_loc.getLine(),
141 .column = end_loc.getColumn(),
142 }
143 };
144
Josh Gaobf8a2852016-05-27 11:59:09 -0700145 DeclarationAvailability availability;
Josh Gaobfb6bae2016-07-15 17:25:21 -0700146
147 // Find and parse __ANDROID_AVAILABILITY_DUMP__ annotations.
148 for (const AnnotateAttr* attr : decl->specific_attrs<AnnotateAttr>()) {
149 llvm::StringRef annotation = attr->getAnnotation();
Josh Gaofff29fe2016-09-07 18:29:08 -0700150 if (annotation == "versioner_no_guard") {
151 no_guard = true;
152 } else if (annotation == "introduced_in_future") {
Josh Gaobfb6bae2016-07-15 17:25:21 -0700153 // Tag the compiled-for arch, since this can vary across archs.
154 availability.arch_availability[type.arch].future = true;
155 } else {
156 llvm::SmallVector<llvm::StringRef, 2> fragments;
157 annotation.split(fragments, "=");
158 if (fragments.size() != 2) {
159 continue;
160 }
161
162 auto& global_availability = availability.global_availability;
163 auto& arch_availability = availability.arch_availability;
164 std::map<std::string, std::vector<int*>> prefix_map = {
165 { "introduced_in", { &global_availability.introduced } },
166 { "deprecated_in", { &global_availability.deprecated } },
167 { "obsoleted_in", { &global_availability.obsoleted } },
168 { "introduced_in_arm", { &arch_availability[Arch::arm].introduced } },
169 { "introduced_in_mips", { &arch_availability[Arch::mips].introduced } },
170 { "introduced_in_x86", { &arch_availability[Arch::x86].introduced } },
171 { "introduced_in_32",
172 { &arch_availability[Arch::arm].introduced,
173 &arch_availability[Arch::mips].introduced,
174 &arch_availability[Arch::x86].introduced } },
175 { "introduced_in_64",
176 { &arch_availability[Arch::arm64].introduced,
177 &arch_availability[Arch::mips64].introduced,
178 &arch_availability[Arch::x86_64].introduced } },
179 };
180
Josh Gao0a284f52016-12-15 13:56:00 -0800181 if (auto it = prefix_map.find(fragments[0]); it != prefix_map.end()) {
182 int value;
183 if (fragments[1].getAsInteger(10, value)) {
184 errx(1, "invalid __ANDROID_AVAILABILITY_DUMP__ annotation: '%s'",
185 annotation.str().c_str());
186 }
Josh Gaobfb6bae2016-07-15 17:25:21 -0700187
Josh Gao0a284f52016-12-15 13:56:00 -0800188 for (int* ptr : it->second) {
189 *ptr = value;
190 }
Josh Gaobfb6bae2016-07-15 17:25:21 -0700191 }
Josh Gaobf8a2852016-05-27 11:59:09 -0700192 }
Josh Gaobfb6bae2016-07-15 17:25:21 -0700193 }
194
195 auto symbol_it = database.symbols.find(declaration_name);
196 if (symbol_it == database.symbols.end()) {
197 Symbol symbol = {.name = declaration_name };
198 bool dummy;
199 std::tie(symbol_it, dummy) = database.symbols.insert({ declaration_name, symbol });
Josh Gaobf8a2852016-05-27 11:59:09 -0700200 }
201
202 // Find or insert an entry for the declaration.
Josh Gao0a284f52016-12-15 13:56:00 -0800203 if (auto declaration_it = symbol_it->second.declarations.find(location);
204 declaration_it != symbol_it->second.declarations.end()) {
205 if (declaration_it->second.is_extern != is_extern ||
206 declaration_it->second.is_definition != is_definition ||
207 declaration_it->second.no_guard != no_guard) {
208 errx(1, "varying declaration of '%s' at %s:%u:%u", declaration_name.c_str(),
209 location.filename.c_str(), location.start.line, location.start.column);
210 }
211 declaration_it->second.availability.insert(std::make_pair(type, availability));
212 } else {
Josh Gaobfb6bae2016-07-15 17:25:21 -0700213 Declaration declaration;
Josh Gao16057882016-08-02 14:54:09 -0700214 declaration.name = declaration_name;
Josh Gaobfb6bae2016-07-15 17:25:21 -0700215 declaration.location = location;
216 declaration.is_extern = is_extern;
217 declaration.is_definition = is_definition;
Josh Gaofff29fe2016-09-07 18:29:08 -0700218 declaration.no_guard = no_guard;
Josh Gaobfb6bae2016-07-15 17:25:21 -0700219 declaration.availability.insert(std::make_pair(type, availability));
220 symbol_it->second.declarations.insert(std::make_pair(location, declaration));
Josh Gaobf8a2852016-05-27 11:59:09 -0700221 }
222
223 return true;
224 }
225};
226
Josh Gaobfb6bae2016-07-15 17:25:21 -0700227bool DeclarationAvailability::merge(const DeclarationAvailability& other) {
228#define check_avail(expr) error |= (!this->expr.empty() && this->expr != other.expr);
229 bool error = false;
230
231 if (!other.global_availability.empty()) {
232 check_avail(global_availability);
233 this->global_availability = other.global_availability;
234 }
235
236 for (Arch arch : supported_archs) {
237 if (!other.arch_availability[arch].empty()) {
238 check_avail(arch_availability[arch]);
239 this->arch_availability[arch] = other.arch_availability[arch];
240 }
241 }
242#undef check_avail
243
244 return !error;
245}
246
247bool Declaration::calculateAvailability(DeclarationAvailability* output) const {
248 DeclarationAvailability avail;
249 for (const auto& it : this->availability) {
250 if (!avail.merge(it.second)) {
251 return false;
252 }
253 }
254 *output = avail;
255 return true;
256}
257
258bool Symbol::calculateAvailability(DeclarationAvailability* output) const {
259 DeclarationAvailability avail;
260 for (const auto& it : this->declarations) {
261 // Don't merge availability for inline functions (because they shouldn't have any).
262 if (it.second.is_definition) {
263 continue;
264 }
265
266 DeclarationAvailability decl_availability;
267 if (!it.second.calculateAvailability(&decl_availability)) {
268 return false;
269 abort();
270 }
271
272 if (!avail.merge(decl_availability)) {
273 return false;
274 }
275 }
276 *output = avail;
277 return true;
278}
279
280bool Symbol::hasDeclaration(const CompilationType& type) const {
281 for (const auto& decl_it : this->declarations) {
282 for (const auto& compilation_it : decl_it.second.availability) {
283 if (compilation_it.first == type) {
284 return true;
285 }
286 }
287 }
288 return false;
289}
290
Josh Gao16016df2016-11-07 18:27:16 -0800291void HeaderDatabase::parseAST(CompilationType type, ASTContext& ctx) {
Josh Gaobfb6bae2016-07-15 17:25:21 -0700292 std::unique_lock<std::mutex> lock(this->mutex);
Josh Gaobfb6bae2016-07-15 17:25:21 -0700293 Visitor visitor(*this, type, ctx);
Josh Gaobf8a2852016-05-27 11:59:09 -0700294 visitor.TraverseDecl(ctx.getTranslationUnitDecl());
295}
Josh Gaobfb6bae2016-07-15 17:25:21 -0700296
Josh Gaobfb6bae2016-07-15 17:25:21 -0700297std::string to_string(const AvailabilityValues& av) {
298 std::stringstream ss;
299
300 if (av.future) {
301 ss << "future, ";
302 }
303
304 if (av.introduced != 0) {
305 ss << "introduced = " << av.introduced << ", ";
306 }
307
308 if (av.deprecated != 0) {
309 ss << "deprecated = " << av.deprecated << ", ";
310 }
311
312 if (av.obsoleted != 0) {
313 ss << "obsoleted = " << av.obsoleted << ", ";
314 }
315
316 std::string result = ss.str();
317 if (!result.empty()) {
318 result = result.substr(0, result.length() - 2);
319 }
320 return result;
321}
322
323std::string to_string(const DeclarationType& type) {
324 switch (type) {
325 case DeclarationType::function:
326 return "function";
327 case DeclarationType::variable:
328 return "variable";
329 case DeclarationType::inconsistent:
330 return "inconsistent";
331 }
332 abort();
333}
334
335std::string to_string(const DeclarationAvailability& decl_av) {
336 std::stringstream ss;
337 if (!decl_av.global_availability.empty()) {
338 ss << to_string(decl_av.global_availability) << ", ";
339 }
340
Josh Gao16057882016-08-02 14:54:09 -0700341 for (const auto& it : decl_av.arch_availability) {
Josh Gaobfb6bae2016-07-15 17:25:21 -0700342 if (!it.second.empty()) {
343 ss << to_string(it.first) << ": " << to_string(it.second) << ", ";
344 }
345 }
346
347 std::string result = ss.str();
348 if (result.size() == 0) {
349 return "no availability";
350 }
351
352 return result.substr(0, result.length() - 2);
353}
354
355std::string to_string(const Location& loc) {
356 std::stringstream ss;
357 ss << loc.filename << ":" << loc.start.line << ":" << loc.start.column;
358 return ss.str();
359}