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
36using namespace clang;
37
38class Visitor : public RecursiveASTVisitor<Visitor> {
39  HeaderDatabase& database;
40  CompilationType type;
41  SourceManager& src_manager;
42  std::unique_ptr<MangleContext> mangler;
43
44 public:
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
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
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
220bool 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
240bool 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
251bool 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
273bool 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
284void 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
290std::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
316std::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
328std::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
348std::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