• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
shouldMangle(MangleContext * mangler,NamedDecl * decl)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:
Visitor(HeaderDatabase & database,CompilationType type,ASTContext & ctx)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 
getDeclName(NamedDecl * decl)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 
VisitDeclaratorDecl(DeclaratorDecl * decl,SourceRange range)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 if (annotation == "introduced_in_future") {
151         // Tag the compiled-for arch, since this can vary across archs.
152         availability.arch_availability[type.arch].future = true;
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 } },
167           { "introduced_in_mips", { &arch_availability[Arch::mips].introduced } },
168           { "introduced_in_x86", { &arch_availability[Arch::x86].introduced } },
169           { "introduced_in_32",
170             { &arch_availability[Arch::arm].introduced,
171               &arch_availability[Arch::mips].introduced,
172               &arch_availability[Arch::x86].introduced } },
173           { "introduced_in_64",
174             { &arch_availability[Arch::arm64].introduced,
175               &arch_availability[Arch::mips64].introduced,
176               &arch_availability[Arch::x86_64].introduced } },
177         };
178 
179         if (auto it = prefix_map.find(fragments[0]); it != prefix_map.end()) {
180           int value;
181           if (fragments[1].getAsInteger(10, value)) {
182             errx(1, "invalid __ANDROID_AVAILABILITY_DUMP__ annotation: '%s'",
183                  annotation.str().c_str());
184           }
185 
186           for (int* ptr : it->second) {
187             *ptr = value;
188           }
189         }
190       }
191     }
192 
193     auto symbol_it = database.symbols.find(declaration_name);
194     if (symbol_it == database.symbols.end()) {
195       Symbol symbol = {.name = declaration_name };
196       bool dummy;
197       std::tie(symbol_it, dummy) = database.symbols.insert({ declaration_name, symbol });
198     }
199 
200     auto expansion_range = src_manager.getExpansionRange(range);
201     auto filename = src_manager.getFilename(expansion_range.getBegin());
202     if (filename != src_manager.getFilename(expansion_range.getEnd())) {
203       errx(1, "expansion range filenames don't match");
204     }
205 
206     Location location = {
207       .filename = filename,
208       .start = {
209         .line = src_manager.getExpansionLineNumber(expansion_range.getBegin()),
210         .column = src_manager.getExpansionColumnNumber(expansion_range.getBegin()),
211       },
212       .end = {
213         .line = src_manager.getExpansionLineNumber(expansion_range.getEnd()),
214         .column = src_manager.getExpansionColumnNumber(expansion_range.getEnd()),
215       }
216     };
217 
218     // Find or insert an entry for the declaration.
219     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 {
229       Declaration declaration;
230       declaration.name = declaration_name;
231       declaration.location = location;
232       declaration.is_extern = is_extern;
233       declaration.is_definition = is_definition;
234       declaration.no_guard = no_guard;
235       declaration.availability.insert(std::make_pair(type, availability));
236       symbol_it->second.declarations.insert(std::make_pair(location, declaration));
237     }
238 
239     return true;
240   }
241 
VisitDeclaratorDecl(DeclaratorDecl * decl)242   bool VisitDeclaratorDecl(DeclaratorDecl* decl) {
243     return VisitDeclaratorDecl(decl, decl->getSourceRange());
244   }
245 
TraverseLinkageSpecDecl(LinkageSpecDecl * decl)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   }
273 };
274 
merge(const DeclarationAvailability & other)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 
calculateAvailability(DeclarationAvailability * output) const295 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 
calculateAvailability(DeclarationAvailability * output) const306 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 
hasDeclaration(const CompilationType & type) const328 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 
parseAST(CompilationType type,ASTContext & ctx)339 void HeaderDatabase::parseAST(CompilationType type, ASTContext& ctx) {
340   std::unique_lock<std::mutex> lock(this->mutex);
341   Visitor visitor(*this, type, ctx);
342   visitor.TraverseDecl(ctx.getTranslationUnitDecl());
343 }
344 
to_string(const AvailabilityValues & av)345 std::string to_string(const AvailabilityValues& av) {
346   std::stringstream ss;
347 
348   if (av.future) {
349     ss << "future, ";
350   }
351 
352   if (av.introduced != 0) {
353     ss << "introduced = " << av.introduced << ", ";
354   }
355 
356   if (av.deprecated != 0) {
357     ss << "deprecated = " << av.deprecated << ", ";
358   }
359 
360   if (av.obsoleted != 0) {
361     ss << "obsoleted = " << av.obsoleted << ", ";
362   }
363 
364   std::string result = ss.str();
365   if (!result.empty()) {
366     result = result.substr(0, result.length() - 2);
367   }
368   return result;
369 }
370 
to_string(const DeclarationType & type)371 std::string to_string(const DeclarationType& type) {
372   switch (type) {
373     case DeclarationType::function:
374       return "function";
375     case DeclarationType::variable:
376       return "variable";
377     case DeclarationType::inconsistent:
378       return "inconsistent";
379   }
380   abort();
381 }
382 
to_string(const DeclarationAvailability & decl_av)383 std::string to_string(const DeclarationAvailability& decl_av) {
384   std::stringstream ss;
385   if (!decl_av.global_availability.empty()) {
386     ss << to_string(decl_av.global_availability) << ", ";
387   }
388 
389   for (const auto& it : decl_av.arch_availability) {
390     if (!it.second.empty()) {
391       ss << to_string(it.first) << ": " << to_string(it.second) << ", ";
392     }
393   }
394 
395   std::string result = ss.str();
396   if (result.size() == 0) {
397     return "no availability";
398   }
399 
400   return result.substr(0, result.length() - 2);
401 }
402 
to_string(const Location & loc)403 std::string to_string(const Location& loc) {
404   std::stringstream ss;
405   ss << loc.filename << ":" << loc.start.line << ":" << loc.start.column;
406   return ss.str();
407 }
408