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 bool fortify_inline; 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 if (fortify_inline) { 148 fprintf(out, "fortify_inline "); 149 } 150 fprintf(out, "@ %s:%u:%u", StripPrefix(location.filename, base_path).str().c_str(), 151 location.start.line, location.start.column); 152 153 if (!availability.empty()) { 154 DeclarationAvailability avail; 155 156 fprintf(out, "\n%s ", indent_str.c_str()); 157 if (!calculateAvailability(&avail)) { 158 fprintf(out, "invalid availability\n"); 159 } else { 160 fprintf(out, "%s\n", to_string(avail).c_str()); 161 } 162 } 163 } 164 }; 165 166 struct Symbol { 167 std::string name; 168 std::map<Location, Declaration> declarations; 169 170 bool calculateAvailability(DeclarationAvailability* output) const; 171 bool hasDeclaration(const CompilationType& type) const; 172 173 bool operator<(const Symbol& rhs) const { 174 return name < rhs.name; 175 } 176 177 bool operator==(const Symbol& rhs) const { 178 return name == rhs.name; 179 } 180 181 void dump(const std::string& base_path = "", FILE* out = stdout) const { 182 DeclarationAvailability availability; 183 bool valid_availability = calculateAvailability(&availability); 184 fprintf(out, " %s: ", name.c_str()); 185 186 if (valid_availability) { 187 fprintf(out, "%s\n", to_string(availability).c_str()); 188 } else { 189 fprintf(out, "invalid\n"); 190 } 191 192 for (auto& it : declarations) { 193 it.second.dump(base_path, out, 4); 194 } 195 } 196 }; 197 198 class HeaderDatabase { 199 std::mutex mutex; 200 201 public: 202 std::map<std::string, Symbol> symbols; 203 204 void parseAST(CompilationType type, clang::ASTContext& ast); 205 206 void dump(const std::string& base_path = "", FILE* out = stdout) const { 207 fprintf(out, "HeaderDatabase contains %zu symbols:\n", symbols.size()); 208 for (const auto& pair : symbols) { 209 pair.second.dump(base_path, out); 210 } 211 } 212 }; 213