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 #pragma once 18 19 #include <stdio.h> 20 21 #include <map> 22 #include <mutex> 23 #include <set> 24 #include <string> 25 #include <vector> 26 27 #include <llvm/ADT/StringRef.h> 28 29 #include "Arch.h" 30 #include "CompilationType.h" 31 #include "Utils.h" 32 33 namespace clang { 34 class ASTContext; 35 class Decl; 36 } 37 38 enum class DeclarationType { 39 function, 40 variable, 41 inconsistent, 42 }; 43 44 struct AvailabilityValues { 45 bool future = false; 46 int introduced = 0; 47 int deprecated = 0; 48 int obsoleted = 0; 49 emptyAvailabilityValues50 bool empty() const { 51 return !(future || introduced || deprecated || obsoleted); 52 } 53 54 bool operator==(const AvailabilityValues& rhs) const { 55 return std::tie(introduced, deprecated, obsoleted) == 56 std::tie(rhs.introduced, rhs.deprecated, rhs.obsoleted); 57 } 58 59 bool operator!=(const AvailabilityValues& rhs) const { 60 return !(*this == rhs); 61 } 62 }; 63 64 std::string to_string(const AvailabilityValues& av); 65 66 struct DeclarationAvailability { 67 AvailabilityValues global_availability; 68 ArchMap<AvailabilityValues> arch_availability; 69 emptyDeclarationAvailability70 bool empty() const { 71 if (!global_availability.empty()) { 72 return false; 73 } 74 75 for (const auto& it : arch_availability) { 76 if (!it.second.empty()) { 77 return false; 78 } 79 } 80 81 return true; 82 } 83 84 bool operator==(const DeclarationAvailability& rhs) const { 85 return std::tie(global_availability, arch_availability) == 86 std::tie(rhs.global_availability, rhs.arch_availability); 87 } 88 89 bool operator!=(const DeclarationAvailability& rhs) const { 90 return !(*this == rhs); 91 } 92 93 // Returns false if the availability declarations conflict. 94 bool merge(const DeclarationAvailability& other); 95 }; 96 97 std::string to_string(const DeclarationAvailability& decl_av); 98 99 struct FileLocation { 100 unsigned line; 101 unsigned column; 102 103 bool operator<(const FileLocation& rhs) const { 104 return std::tie(line, column) < std::tie(rhs.line, rhs.column); 105 } 106 107 bool operator==(const FileLocation& rhs) const { 108 return std::tie(line, column) == std::tie(rhs.line, rhs.column); 109 } 110 }; 111 112 struct Location { 113 std::string filename; 114 FileLocation start; 115 FileLocation end; 116 117 bool operator<(const Location& rhs) const { 118 return std::tie(filename, start, end) < std::tie(rhs.filename, rhs.start, rhs.end); 119 } 120 }; 121 122 std::string to_string(const Location& loc); 123 124 struct Declaration { 125 std::string name; 126 Location location; 127 128 bool is_extern; 129 bool is_definition; 130 bool no_guard; 131 std::map<CompilationType, DeclarationAvailability> availability; 132 133 bool calculateAvailability(DeclarationAvailability* output) const; 134 bool operator<(const Declaration& rhs) const { 135 return location < rhs.location; 136 } 137 138 void dump(const std::string& base_path = "", FILE* out = stdout, unsigned indent = 0) const { 139 std::string indent_str(indent, ' '); 140 fprintf(out, "%s", indent_str.c_str()); 141 142 fprintf(out, "%s ", is_extern ? "extern" : "static"); 143 fprintf(out, "%s ", is_definition ? "definition" : "declaration"); 144 if (no_guard) { 145 fprintf(out, "no_guard "); 146 } 147 fprintf(out, "@ %s:%u:%u", StripPrefix(location.filename, base_path).str().c_str(), 148 location.start.line, location.start.column); 149 150 if (!availability.empty()) { 151 DeclarationAvailability avail; 152 153 fprintf(out, "\n%s ", indent_str.c_str()); 154 if (!calculateAvailability(&avail)) { 155 fprintf(out, "invalid availability\n"); 156 } else { 157 fprintf(out, "%s\n", to_string(avail).c_str()); 158 } 159 } 160 } 161 }; 162 163 struct Symbol { 164 std::string name; 165 std::map<Location, Declaration> declarations; 166 167 bool calculateAvailability(DeclarationAvailability* output) const; 168 bool hasDeclaration(const CompilationType& type) const; 169 170 bool operator<(const Symbol& rhs) const { 171 return name < rhs.name; 172 } 173 174 bool operator==(const Symbol& rhs) const { 175 return name == rhs.name; 176 } 177 178 void dump(const std::string& base_path = "", FILE* out = stdout) const { 179 DeclarationAvailability availability; 180 bool valid_availability = calculateAvailability(&availability); 181 fprintf(out, " %s: ", name.c_str()); 182 183 if (valid_availability) { 184 fprintf(out, "%s\n", to_string(availability).c_str()); 185 } else { 186 fprintf(out, "invalid\n"); 187 } 188 189 for (auto& it : declarations) { 190 it.second.dump(base_path, out, 4); 191 } 192 } 193 }; 194 195 class HeaderDatabase { 196 std::mutex mutex; 197 198 public: 199 std::map<std::string, Symbol> symbols; 200 201 void parseAST(CompilationType type, clang::ASTContext& ast); 202 203 void dump(const std::string& base_path = "", FILE* out = stdout) const { 204 fprintf(out, "HeaderDatabase contains %zu symbols:\n", symbols.size()); 205 for (const auto& pair : symbols) { 206 pair.second.dump(base_path, out); 207 } 208 } 209 }; 210