blob: 44438340ee7dd31dd0cc5807a7612759b03e022d [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
Josh Gaoab25d0b2017-08-10 10:50:33 -070038static 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 Gaobf8a2852016-05-27 11:59:09 -070054class Visitor : public RecursiveASTVisitor<Visitor> {
55 HeaderDatabase& database;
Josh Gaobfb6bae2016-07-15 17:25:21 -070056 CompilationType type;
Josh Gaobf8a2852016-05-27 11:59:09 -070057 SourceManager& src_manager;
58 std::unique_ptr<MangleContext> mangler;
59
60 public:
Josh Gaobfb6bae2016-07-15 17:25:21 -070061 Visitor(HeaderDatabase& database, CompilationType type, ASTContext& ctx)
62 : database(database), type(type), src_manager(ctx.getSourceManager()) {
Josh Gaobf8a2852016-05-27 11:59:09 -070063 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 Gao38685e12017-10-30 12:45:09 -070073 // <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
Josh Gao0062b3e2017-10-24 17:03:58 -070078 // The decl might not have a name (e.g. bitfields).
Josh Gao0a284f52016-12-15 13:56:00 -080079 if (auto identifier = decl->getIdentifier()) {
Josh Gaoab25d0b2017-08-10 10:50:33 -070080 if (shouldMangle(mangler.get(), decl)) {
Josh Gao0062b3e2017-10-24 17:03:58 -070081 std::string mangled;
82 llvm::raw_string_ostream ss(mangled);
83 mangler->mangleName(decl, ss);
84 return mangled;
85 }
86
Josh Gao0a284f52016-12-15 13:56:00 -080087 return identifier->getName();
Josh Gaobf8a2852016-05-27 11:59:09 -070088 }
Josh Gao0062b3e2017-10-24 17:03:58 -070089
90 return "<unnamed>";
Josh Gaobf8a2852016-05-27 11:59:09 -070091 }
92
93 bool VisitDecl(Decl* decl) {
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 DeclarationType declaration_type;
106 std::string declaration_name = getDeclName(named_decl);
107 bool is_extern = named_decl->getFormalLinkage() == ExternalLinkage;
108 bool is_definition = false;
Josh Gaofff29fe2016-09-07 18:29:08 -0700109 bool no_guard = false;
Josh Gaobf8a2852016-05-27 11:59:09 -0700110
111 if (auto function_decl = dyn_cast<FunctionDecl>(decl)) {
112 declaration_type = DeclarationType::function;
113 is_definition = function_decl->isThisDeclarationADefinition();
114 } else if (auto var_decl = dyn_cast<VarDecl>(decl)) {
115 if (!var_decl->isFileVarDecl()) {
116 return true;
117 }
118
119 declaration_type = DeclarationType::variable;
120 switch (var_decl->isThisDeclarationADefinition()) {
121 case VarDecl::DeclarationOnly:
122 is_definition = false;
123 break;
124
125 case VarDecl::Definition:
126 is_definition = true;
127 break;
128
129 case VarDecl::TentativeDefinition:
130 // Forbid tentative definitions in headers.
131 fprintf(stderr, "ERROR: declaration '%s' is a tentative definition\n",
132 declaration_name.c_str());
133 decl->dump();
134 abort();
135 }
136 } else {
137 // We only care about function and variable declarations.
138 return true;
139 }
140
141 if (decl->hasAttr<UnavailableAttr>()) {
142 // Skip declarations that exist only for compile-time diagnostics.
143 return true;
144 }
145
Josh Gaobfb6bae2016-07-15 17:25:21 -0700146 auto start_loc = src_manager.getPresumedLoc(decl->getLocStart());
147 auto end_loc = src_manager.getPresumedLoc(decl->getLocEnd());
148
149 Location location = {
150 .filename = start_loc.getFilename(),
151 .start = {
152 .line = start_loc.getLine(),
153 .column = start_loc.getColumn(),
154 },
155 .end = {
156 .line = end_loc.getLine(),
157 .column = end_loc.getColumn(),
158 }
159 };
160
Josh Gaobf8a2852016-05-27 11:59:09 -0700161 DeclarationAvailability availability;
Josh Gaobfb6bae2016-07-15 17:25:21 -0700162
163 // Find and parse __ANDROID_AVAILABILITY_DUMP__ annotations.
164 for (const AnnotateAttr* attr : decl->specific_attrs<AnnotateAttr>()) {
165 llvm::StringRef annotation = attr->getAnnotation();
Josh Gaofff29fe2016-09-07 18:29:08 -0700166 if (annotation == "versioner_no_guard") {
167 no_guard = true;
168 } else if (annotation == "introduced_in_future") {
Josh Gaobfb6bae2016-07-15 17:25:21 -0700169 // Tag the compiled-for arch, since this can vary across archs.
170 availability.arch_availability[type.arch].future = true;
171 } else {
172 llvm::SmallVector<llvm::StringRef, 2> fragments;
173 annotation.split(fragments, "=");
174 if (fragments.size() != 2) {
175 continue;
176 }
177
178 auto& global_availability = availability.global_availability;
179 auto& arch_availability = availability.arch_availability;
180 std::map<std::string, std::vector<int*>> prefix_map = {
181 { "introduced_in", { &global_availability.introduced } },
182 { "deprecated_in", { &global_availability.deprecated } },
183 { "obsoleted_in", { &global_availability.obsoleted } },
184 { "introduced_in_arm", { &arch_availability[Arch::arm].introduced } },
185 { "introduced_in_mips", { &arch_availability[Arch::mips].introduced } },
186 { "introduced_in_x86", { &arch_availability[Arch::x86].introduced } },
187 { "introduced_in_32",
188 { &arch_availability[Arch::arm].introduced,
189 &arch_availability[Arch::mips].introduced,
190 &arch_availability[Arch::x86].introduced } },
191 { "introduced_in_64",
192 { &arch_availability[Arch::arm64].introduced,
193 &arch_availability[Arch::mips64].introduced,
194 &arch_availability[Arch::x86_64].introduced } },
195 };
196
Josh Gao0a284f52016-12-15 13:56:00 -0800197 if (auto it = prefix_map.find(fragments[0]); it != prefix_map.end()) {
198 int value;
199 if (fragments[1].getAsInteger(10, value)) {
200 errx(1, "invalid __ANDROID_AVAILABILITY_DUMP__ annotation: '%s'",
201 annotation.str().c_str());
202 }
Josh Gaobfb6bae2016-07-15 17:25:21 -0700203
Josh Gao0a284f52016-12-15 13:56:00 -0800204 for (int* ptr : it->second) {
205 *ptr = value;
206 }
Josh Gaobfb6bae2016-07-15 17:25:21 -0700207 }
Josh Gaobf8a2852016-05-27 11:59:09 -0700208 }
Josh Gaobfb6bae2016-07-15 17:25:21 -0700209 }
210
211 auto symbol_it = database.symbols.find(declaration_name);
212 if (symbol_it == database.symbols.end()) {
213 Symbol symbol = {.name = declaration_name };
214 bool dummy;
215 std::tie(symbol_it, dummy) = database.symbols.insert({ declaration_name, symbol });
Josh Gaobf8a2852016-05-27 11:59:09 -0700216 }
217
218 // Find or insert an entry for the declaration.
Josh Gao0a284f52016-12-15 13:56:00 -0800219 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 {
Josh Gaobfb6bae2016-07-15 17:25:21 -0700229 Declaration declaration;
Josh Gao16057882016-08-02 14:54:09 -0700230 declaration.name = declaration_name;
Josh Gaobfb6bae2016-07-15 17:25:21 -0700231 declaration.location = location;
232 declaration.is_extern = is_extern;
233 declaration.is_definition = is_definition;
Josh Gaofff29fe2016-09-07 18:29:08 -0700234 declaration.no_guard = no_guard;
Josh Gaobfb6bae2016-07-15 17:25:21 -0700235 declaration.availability.insert(std::make_pair(type, availability));
236 symbol_it->second.declarations.insert(std::make_pair(location, declaration));
Josh Gaobf8a2852016-05-27 11:59:09 -0700237 }
238
239 return true;
240 }
241};
242
Josh Gaobfb6bae2016-07-15 17:25:21 -0700243bool DeclarationAvailability::merge(const DeclarationAvailability& other) {
244#define check_avail(expr) error |= (!this->expr.empty() && this->expr != other.expr);
245 bool error = false;
246
247 if (!other.global_availability.empty()) {
248 check_avail(global_availability);
249 this->global_availability = other.global_availability;
250 }
251
252 for (Arch arch : supported_archs) {
253 if (!other.arch_availability[arch].empty()) {
254 check_avail(arch_availability[arch]);
255 this->arch_availability[arch] = other.arch_availability[arch];
256 }
257 }
258#undef check_avail
259
260 return !error;
261}
262
263bool Declaration::calculateAvailability(DeclarationAvailability* output) const {
264 DeclarationAvailability avail;
265 for (const auto& it : this->availability) {
266 if (!avail.merge(it.second)) {
267 return false;
268 }
269 }
270 *output = avail;
271 return true;
272}
273
274bool Symbol::calculateAvailability(DeclarationAvailability* output) const {
275 DeclarationAvailability avail;
276 for (const auto& it : this->declarations) {
277 // Don't merge availability for inline functions (because they shouldn't have any).
278 if (it.second.is_definition) {
279 continue;
280 }
281
282 DeclarationAvailability decl_availability;
283 if (!it.second.calculateAvailability(&decl_availability)) {
284 return false;
285 abort();
286 }
287
288 if (!avail.merge(decl_availability)) {
289 return false;
290 }
291 }
292 *output = avail;
293 return true;
294}
295
296bool Symbol::hasDeclaration(const CompilationType& type) const {
297 for (const auto& decl_it : this->declarations) {
298 for (const auto& compilation_it : decl_it.second.availability) {
299 if (compilation_it.first == type) {
300 return true;
301 }
302 }
303 }
304 return false;
305}
306
Josh Gao16016df2016-11-07 18:27:16 -0800307void HeaderDatabase::parseAST(CompilationType type, ASTContext& ctx) {
Josh Gaobfb6bae2016-07-15 17:25:21 -0700308 std::unique_lock<std::mutex> lock(this->mutex);
Josh Gaobfb6bae2016-07-15 17:25:21 -0700309 Visitor visitor(*this, type, ctx);
Josh Gaobf8a2852016-05-27 11:59:09 -0700310 visitor.TraverseDecl(ctx.getTranslationUnitDecl());
311}
Josh Gaobfb6bae2016-07-15 17:25:21 -0700312
Josh Gaobfb6bae2016-07-15 17:25:21 -0700313std::string to_string(const AvailabilityValues& av) {
314 std::stringstream ss;
315
316 if (av.future) {
317 ss << "future, ";
318 }
319
320 if (av.introduced != 0) {
321 ss << "introduced = " << av.introduced << ", ";
322 }
323
324 if (av.deprecated != 0) {
325 ss << "deprecated = " << av.deprecated << ", ";
326 }
327
328 if (av.obsoleted != 0) {
329 ss << "obsoleted = " << av.obsoleted << ", ";
330 }
331
332 std::string result = ss.str();
333 if (!result.empty()) {
334 result = result.substr(0, result.length() - 2);
335 }
336 return result;
337}
338
339std::string to_string(const DeclarationType& type) {
340 switch (type) {
341 case DeclarationType::function:
342 return "function";
343 case DeclarationType::variable:
344 return "variable";
345 case DeclarationType::inconsistent:
346 return "inconsistent";
347 }
348 abort();
349}
350
351std::string to_string(const DeclarationAvailability& decl_av) {
352 std::stringstream ss;
353 if (!decl_av.global_availability.empty()) {
354 ss << to_string(decl_av.global_availability) << ", ";
355 }
356
Josh Gao16057882016-08-02 14:54:09 -0700357 for (const auto& it : decl_av.arch_availability) {
Josh Gaobfb6bae2016-07-15 17:25:21 -0700358 if (!it.second.empty()) {
359 ss << to_string(it.first) << ": " << to_string(it.second) << ", ";
360 }
361 }
362
363 std::string result = ss.str();
364 if (result.size() == 0) {
365 return "no availability";
366 }
367
368 return result.substr(0, result.length() - 2);
369}
370
371std::string to_string(const Location& loc) {
372 std::stringstream ss;
373 ss << loc.filename << ":" << loc.start.line << ":" << loc.start.column;
374 return ss.str();
375}