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