Remove generic comparison IR ops
[hiphop-php.git] / hphp / tools / clang-gc-tool / plugin-util.h
blobfa45c08c4c5e17372a48d7258b0f9038623afe3b
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2015 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_CLANG_GC_TOOL_PLUGIN_UTIL_H_
18 #define incl_HPHP_CLANG_GC_TOOL_PLUGIN_UTIL_H_
20 #undef __GXX_RTTI
22 #include <cstdarg>
23 #include <set>
24 #include <vector>
25 #include <string>
26 #include <fcntl.h>
27 #include <sys/file.h>
28 #include <unistd.h>
29 #include <boost/noncopyable.hpp>
30 #include <boost/format.hpp>
31 #include <clang/AST/AST.h>
32 #include <clang/AST/ASTConsumer.h>
34 namespace HPHP {
36 using DeclSet = std::set<const clang::CXXRecordDecl*>;
37 using DeclMap = std::map<const clang::NamedDecl*, const clang::NamedDecl*>;
39 template <typename C, typename K>
40 bool exists(const C& c, const K& k) {
41 return c.find(k) != c.end();
45 * A helper class that holds an ASTContext and defines some utility
46 * methods for dealing with Clang types and decls.
48 struct PluginUtil {
49 explicit PluginUtil(clang::ASTContext& context);
50 ~PluginUtil();
52 bool isCppFile(const char* file) const;
53 bool isHeaderFile(const char* file) const;
54 bool inSystemHeader(const clang::Decl* decl) const;
56 // Is this decl defined in a cpp file?
57 bool isHiddenDecl(const clang::CXXRecordDecl* decl) const;
59 const char* getFilename(const clang::SourceRange& loc) const;
61 // Get filename for the definition of decl.
62 const char* getDefinitionFilename(const clang::Decl* decl) const;
64 // Get filename for decl.
65 const char* getFilename(const clang::Decl* decl) const;
67 // Print an error message and exit. With optional location information.
68 template <typename ...Args>
69 void error(const clang::SourceRange& loc,
70 const char* fmt,
71 Args&&... args) const {
72 boost::format f(fmt);
73 error(locToString(loc), format(f, std::forward<Args>(args)...));
75 template <typename ...Args>
76 void error(const clang::Decl* decl, const char* fmt, Args&&... args) const {
77 boost::format f(fmt);
78 error(locToString(decl->getSourceRange()),
79 format(f, std::forward<Args>(args)...));
81 template <typename ...Args>
82 void error(const char* fmt, Args&&... args) const {
83 boost::format f(fmt);
84 error(std::string(""), format(f, std::forward<Args>(args)...));
87 // Print a warning message. With optional location information.
88 template <typename ...Args>
89 void warning(const clang::Decl* declLoc,
90 const char* fmt,
91 Args&&... args) const {
92 boost::format f(fmt);
93 warning(locToString(declLoc->getSourceRange()),
94 format(f, std::forward<Args>(args)...));
96 template <typename ...Args>
97 void warning(const clang::SourceRange& loc,
98 const char* fmt,
99 Args&&... args) const {
100 boost::format f(fmt);
101 warning(locToString(loc), format(f, std::forward<Args>(args)...));
103 template <typename ...Args>
104 void warning(const char* fmt, Args&&... args) const {
105 boost::format f(fmt);
106 warning(std::string(""), format(f, std::forward<Args>(args)...));
109 // Print a warning with a chain of reasoning.
110 template <typename ...Args>
111 void warning(const DeclMap& whys,
112 const clang::NamedDecl* decl,
113 const char* fmt,
114 Args&&... args) const {
115 boost::format f(fmt);
116 warning(whys, decl, format(f, std::forward<Args>(args)...));
119 // Test for inheritance.
120 static bool isSubclassOf(const clang::NamedDecl* maybeBase,
121 const clang::CXXRecordDecl* derived);
123 // Is derived a subclass of any class from maybeBases?
124 static bool isSubclassOf(const DeclSet& maybeBases,
125 const clang::CXXRecordDecl* derived);
127 static bool isArrayType(const clang::Type& ty);
128 static bool isPointerType(const clang::Type& ty);
129 static bool isReferenceType(const clang::Type& ty);
130 static bool isPointerOrReferenceType(const clang::Type& ty);
131 static bool isPOD(const clang::Type& ty);
132 bool isOpaque(const clang::Type& ty) const;
134 const clang::Type& getElementType(const clang::Type& ty) const;
135 const clang::Type& getPointeeType(const clang::Type& ty) const;
137 // Strip pointers, references and arrays from a type.
138 const clang::Type& stripType(const clang::Type& ty) const;
140 const clang::CXXRecordDecl*
141 getCanonicalDef(const clang::CXXRecordDecl* decl) const;
143 static bool isTemplate(const clang::CXXRecordDecl* decl);
145 static const clang::ClassTemplateDecl* getTemplateDef(
146 const clang::CXXRecordDecl* decl);
148 std::string getTemplateClassName(const clang::CXXRecordDecl* decl,
149 bool no_namespaces = false) const;
150 static void forEachTemplateParam(const clang::CXXRecordDecl* decl,
151 const std::function<bool(const clang::NamedDecl*)>& fn);
153 std::string getName(const clang::QualType ty,
154 bool no_namespaces = false,
155 bool suppress_tag = true,
156 bool suppress_qualifiers = true) const;
158 std::string getName(const clang::Type& ty,
159 bool no_namespaces = false,
160 bool suppress_tag = true) const;
162 std::string getName(const clang::CXXRecordDecl* decl,
163 bool no_namespaces = false,
164 bool suppress_tag = true) const;
166 std::string getNsName(const clang::CXXRecordDecl* decl) const;
168 std::string getName(const clang::ClassTemplateDecl* decl,
169 bool no_namespaces = false,
170 bool suppress_tag = true) const;
172 std::string getName(const clang::NamedDecl* decl,
173 bool no_namespaces = false,
174 bool suppress_tag = true) const;
176 std::string tagName(const clang::CXXRecordDecl* decl) const;
178 static bool isNestedDecl(const clang::CXXRecordDecl* decl);
179 static bool isNestedInTemplate(const clang::CXXRecordDecl* decl);
181 template <typename F>
182 static bool isNestedInFn(const clang::CXXRecordDecl* decl, F& fn) {
183 auto p = decl->getDeclContext();
184 while (p) {
185 if (p->isRecord() && fn(clang::cast<clang::CXXRecordDecl>(p))) {
186 return true;
188 p = p->getParent();
190 return false;
193 bool isInAnonymousNamespace(const clang::CXXRecordDecl* decl) const;
195 bool isAnonymous(const clang::CXXRecordDecl* decl) const;
196 bool isAnonymous(const clang::FieldDecl* decl) const;
197 bool isAnonymous(const clang::NamespaceDecl* decl) const;
199 static std::vector<const clang::NamespaceDecl*>
200 getParentNamespaces(const clang::CXXRecordDecl* def);
202 std::vector<const clang::CXXRecordDecl*>
203 getOuterClasses(const clang::CXXRecordDecl* def) const;
205 // Find comment (if any) immediately preceding decl.
206 const clang::RawComment* findComment(const clang::Decl* decl) const;
207 void collectComments();
209 clang::ASTContext& m_context;
210 std::set<const clang::RawComment*> m_comments;
211 protected:
212 std::string addNamespaces(const clang::NamedDecl* decl,
213 const std::string& str,
214 bool noClasses = false) const;
215 std::string addNamespaces(const clang::Type& ty,
216 const std::string& str,
217 bool noClasses = false) const;
218 private:
219 std::string format(boost::format& f) const {
220 return boost::str(f);
223 template <typename T, typename... Args>
224 std::string format(boost::format& f, T&& v, Args&&... args) const {
225 return format(f % std::forward<T>(v), std::forward<Args>(args)...);
228 std::string locToString(const clang::SourceRange& loc) const;
229 void error(const std::string& locStr, const std::string& msg) const;
230 void warning(const std::string& locStr, const std::string& msg) const;
231 void warning(const DeclMap& whys,
232 const clang::NamedDecl* decl,
233 const std::string& msg) const;
236 // Simple file locking class.
237 struct Lockfile {
238 explicit operator bool() const { return m_fd != -1 && m_flockres == 0; }
239 void unlock() {
240 if (m_fd >= 0) {
241 flock(m_fd, LOCK_UN);
242 close(m_fd);
243 int res = unlink(m_filename.c_str());
244 (void)res;
245 assert(res == 0 || !m_exclusive);
246 m_fd = -1;
249 // excl requests an exclusive lock.
250 explicit Lockfile(const std::string& basefile, bool exclusive = true)
251 : m_filename(lockfileName(basefile)),
252 m_exclusive(exclusive),
253 m_fd(open(m_filename.c_str(), O_CREAT | O_EXCL)) {
254 if (m_fd < 0 && !m_exclusive) {
255 m_fd = open(m_filename.c_str(), O_RDONLY);
257 m_flockres = m_fd < 0 ? -1 : flock(m_fd, LOCK_EX);
259 ~Lockfile() {
260 unlock();
262 private:
263 Lockfile(const Lockfile&) = delete;
264 Lockfile& operator=(const Lockfile&) = delete;
265 static std::string lockfileName(const std::string& base) {
266 auto ind = base.find_last_of('/');
267 if (ind != std::string::npos) {
268 return base.substr(0,ind+1) + "." + base.substr(ind+1) + ".lock";
270 return std::string(".") + base + ".lock";
272 std::string m_filename;
273 bool m_exclusive;
274 int m_fd;
275 int m_flockres;
280 #endif