2 +----------------------------------------------------------------------+
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_
29 #include <boost/noncopyable.hpp>
30 #include <boost/format.hpp>
31 #include <clang/AST/AST.h>
32 #include <clang/AST/ASTConsumer.h>
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.
49 explicit PluginUtil(clang::ASTContext
& context
);
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
,
71 Args
&&... args
) const {
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 {
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 {
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
,
91 Args
&&... args
) const {
93 warning(locToString(declLoc
->getSourceRange()),
94 format(f
, std::forward
<Args
>(args
)...));
96 template <typename
...Args
>
97 void warning(const clang::SourceRange
& loc
,
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
,
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();
185 if (p
->isRecord() && fn(clang::cast
<clang::CXXRecordDecl
>(p
))) {
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
;
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;
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.
238 explicit operator bool() const { return m_fd
!= -1 && m_flockres
== 0; }
241 flock(m_fd
, LOCK_UN
);
243 int res
= unlink(m_filename
.c_str());
245 assert(res
== 0 || !m_exclusive
);
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
);
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
;