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