blob: 9f02588ec9ce76a05813a67f264dfadcf35ad7f0 [file] [log] [blame]
Josh Gaobf8a2852016-05-27 11:59:09 -07001/*
2 * Copyright 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 <iostream>
20#include <map>
21#include <set>
22#include <string>
23
24#include <clang/AST/AST.h>
25#include <clang/AST/Attr.h>
26#include <clang/AST/Mangle.h>
27#include <clang/AST/RecursiveASTVisitor.h>
28#include <clang/Frontend/ASTUnit.h>
29#include <llvm/Support/raw_ostream.h>
30
31using namespace clang;
32
33class Visitor : public RecursiveASTVisitor<Visitor> {
34 HeaderDatabase& database;
35 SourceManager& src_manager;
36 std::unique_ptr<MangleContext> mangler;
37
38 public:
39 Visitor(HeaderDatabase& database, ASTContext& ctx)
40 : database(database), src_manager(ctx.getSourceManager()) {
41 mangler.reset(ItaniumMangleContext::create(ctx, ctx.getDiagnostics()));
42 }
43
44 std::string getDeclName(NamedDecl* decl) {
45 if (auto var_decl = dyn_cast<VarDecl>(decl)) {
46 if (!var_decl->isFileVarDecl()) {
47 return "<local var>";
48 }
49 }
50
51 if (mangler->shouldMangleDeclName(decl)) {
52 std::string mangled;
53 llvm::raw_string_ostream ss(mangled);
54 mangler->mangleName(decl, ss);
55 return mangled;
56 }
57
58 auto identifier = decl->getIdentifier();
59 if (!identifier) {
60 return "<error>";
61 }
62 return identifier->getName();
63 }
64
65 bool VisitDecl(Decl* decl) {
66 // Skip declarations inside of functions (function arguments, variable declarations inside of
67 // inline functions, etc).
68 if (decl->getParentFunctionOrMethod()) {
69 return true;
70 }
71
72 auto named_decl = dyn_cast<NamedDecl>(decl);
73 if (!named_decl) {
74 return true;
75 }
76
77 DeclarationType declaration_type;
78 std::string declaration_name = getDeclName(named_decl);
79 bool is_extern = named_decl->getFormalLinkage() == ExternalLinkage;
80 bool is_definition = false;
81
82 if (auto function_decl = dyn_cast<FunctionDecl>(decl)) {
83 declaration_type = DeclarationType::function;
84 is_definition = function_decl->isThisDeclarationADefinition();
85 } else if (auto var_decl = dyn_cast<VarDecl>(decl)) {
86 if (!var_decl->isFileVarDecl()) {
87 return true;
88 }
89
90 declaration_type = DeclarationType::variable;
91 switch (var_decl->isThisDeclarationADefinition()) {
92 case VarDecl::DeclarationOnly:
93 is_definition = false;
94 break;
95
96 case VarDecl::Definition:
97 is_definition = true;
98 break;
99
100 case VarDecl::TentativeDefinition:
101 // Forbid tentative definitions in headers.
102 fprintf(stderr, "ERROR: declaration '%s' is a tentative definition\n",
103 declaration_name.c_str());
104 decl->dump();
105 abort();
106 }
107 } else {
108 // We only care about function and variable declarations.
109 return true;
110 }
111
112 if (decl->hasAttr<UnavailableAttr>()) {
113 // Skip declarations that exist only for compile-time diagnostics.
114 return true;
115 }
116
117 // Look for availability annotations.
118 DeclarationAvailability availability;
119 for (const AvailabilityAttr* attr : decl->specific_attrs<AvailabilityAttr>()) {
120 if (attr->getPlatform()->getName() != "android") {
121 fprintf(stderr, "skipping non-android platform %s\n",
122 attr->getPlatform()->getName().str().c_str());
123 continue;
124 }
125 if (attr->getIntroduced().getMajor() != 0) {
126 availability.introduced = attr->getIntroduced().getMajor();
127 }
128 if (attr->getDeprecated().getMajor() != 0) {
129 availability.deprecated = attr->getDeprecated().getMajor();
130 }
131 if (attr->getObsoleted().getMajor() != 0) {
132 availability.obsoleted = attr->getObsoleted().getMajor();
133 }
134 }
135
136 // Find or insert an entry for the declaration.
137 auto declaration_it = database.declarations.find(declaration_name);
138 if (declaration_it == database.declarations.end()) {
139 Declaration declaration = {.name = declaration_name };
140 bool inserted;
141 std::tie(declaration_it, inserted) =
142 database.declarations.insert({ declaration_name, declaration });
143 }
144
145 auto& declaration_locations = declaration_it->second.locations;
146 auto presumed_loc = src_manager.getPresumedLoc(decl->getLocation());
147 DeclarationLocation location = {
148 .filename = presumed_loc.getFilename(),
149 .line_number = presumed_loc.getLine(),
150 .column = presumed_loc.getColumn(),
151 .type = declaration_type,
152 .is_extern = is_extern,
153 .is_definition = is_definition,
154 .availability = availability,
155 };
156
157 // It's fine if the location is already there, we'll get an iterator to the existing element.
158 auto location_it = declaration_locations.begin();
159 bool inserted = false;
160 std::tie(location_it, inserted) = declaration_locations.insert(location);
161
162 // If we didn't insert, check to see if the availability attributes are identical.
163 if (!inserted) {
164 if (location_it->availability != availability) {
165 fprintf(stderr, "ERROR: availability attribute mismatch\n");
166 decl->dump();
167 abort();
168 }
169 }
170
171 return true;
172 }
173};
174
175void HeaderDatabase::parseAST(ASTUnit* ast) {
176 ASTContext& ctx = ast->getASTContext();
177 Visitor visitor(*this, ctx);
178 visitor.TraverseDecl(ctx.getTranslationUnitDecl());
179}