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 class Visitor : public RecursiveASTVisitor<Visitor> {
39 HeaderDatabase& database;
40 CompilationType type;
41 SourceManager& src_manager;
42 std::unique_ptr<MangleContext> mangler;
43
44 public:
Visitor(HeaderDatabase & database,CompilationType type,ASTContext & ctx)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
getDeclName(NamedDecl * decl)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
VisitDecl(Decl * decl)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
merge(const DeclarationAvailability & other)220 bool 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
calculateAvailability(DeclarationAvailability * output) const240 bool 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
calculateAvailability(DeclarationAvailability * output) const251 bool 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
hasDeclaration(const CompilationType & type) const273 bool 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
parseAST(CompilationType type,ASTContext & ctx)284 void 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
to_string(const AvailabilityValues & av)290 std::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
to_string(const DeclarationType & type)316 std::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
to_string(const DeclarationAvailability & decl_av)328 std::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
to_string(const Location & loc)348 std::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