@@ -44,20 +44,20 @@ inplace("inplace", llvm::cl::init(false),
4444 llvm::cl::cat(idt::category));
4545
4646llvm::cl::list<std::string>
47- ignored_functions (" ignore" ,
48- llvm::cl::desc (" Ignore one or more functions" ),
49- llvm::cl::value_desc(" function-name[,function-name...]" ),
50- llvm::cl::CommaSeparated,
51- llvm::cl::cat(idt::category));
47+ ignored_symbols (" ignore" ,
48+ llvm::cl::desc (" Ignore one or more functions" ),
49+ llvm::cl::value_desc(" function-name[,function-name...]" ),
50+ llvm::cl::CommaSeparated,
51+ llvm::cl::cat(idt::category));
5252
5353template <typename Key, typename Compare, typename Allocator>
5454bool contains (const std::set<Key, Compare, Allocator>& set, const Key& key) {
5555 return set.find (key) != set.end ();
5656}
5757
58- const std::set<std::string> &get_ignored_functions () {
58+ const std::set<std::string> &get_ignored_symbols () {
5959 static auto kIgnoredFunctions = [&]() -> std::set<std::string> {
60- return { ignored_functions .begin (), ignored_functions .end () };
60+ return { ignored_symbols .begin (), ignored_symbols .end () };
6161 }();
6262
6363 return kIgnoredFunctions ;
@@ -97,6 +97,19 @@ class visitor : public clang::RecursiveASTVisitor<visitor> {
9797 return context_.getFullLoc (TD->getBeginLoc ()).getExpansionLoc ();
9898 }
9999
100+ template <typename Decl_>
101+ bool is_in_header (const Decl_ *D) const {
102+ const clang::FullSourceLoc location = get_location (D);
103+ const clang::FileID id = source_manager_.getFileID (location);
104+ if (const auto entry = source_manager_.getFileEntryRefForID (id)) {
105+ const llvm::StringRef name = entry->getName ();
106+ for (const auto &extension : { " .h" , " .hh" , " .hpp" , " .hxx" })
107+ if (name.ends_with (extension))
108+ return true ;
109+ }
110+ return false ;
111+ }
112+
100113public:
101114 explicit visitor (clang::ASTContext &context)
102115 : context_(context), source_manager_(context.getSourceManager()) {}
@@ -150,7 +163,7 @@ class visitor : public clang::RecursiveASTVisitor<visitor> {
150163 return true ;
151164
152165 // TODO(compnerd) replace with std::set::contains in C++20
153- if (contains (get_ignored_functions (), FD->getNameAsString ()))
166+ if (contains (get_ignored_symbols (), FD->getNameAsString ()))
154167 return true ;
155168
156169 clang::SourceLocation insertion_point =
@@ -163,6 +176,46 @@ class visitor : public clang::RecursiveASTVisitor<visitor> {
163176 export_macro + " " );
164177 return true ;
165178 }
179+
180+ // VisitVarDecl will visit all variable declarations as well as static fields
181+ // in classes and structs. Non-static fields are not visited by this method.
182+ bool VisitVarDecl (clang::VarDecl *VD) {
183+ if (VD->hasAttr <clang::DLLExportAttr>() ||
184+ VD->hasAttr <clang::DLLImportAttr>())
185+ return true ;
186+
187+ if (VD->hasInit ())
188+ return true ;
189+
190+ // Skip local variables.
191+ if (VD->getParentFunctionOrMethod ())
192+ return true ;
193+
194+ // Skip all variable declarations not in header files.
195+ if (!is_in_header (VD))
196+ return true ;
197+
198+ // Skip private static members.
199+ if (VD->getAccess () == clang::AccessSpecifier::AS_private)
200+ return true ;
201+
202+ // Skip all other local and global variables unless they are extern.
203+ if (!VD->isStaticDataMember () &&
204+ VD->getStorageClass () != clang::StorageClass::SC_Extern)
205+ return true ;
206+
207+ // TODO(compnerd) replace with std::set::contains in C++20
208+ if (contains (get_ignored_symbols (), VD->getNameAsString ()))
209+ return true ;
210+
211+ clang::FullSourceLoc location = get_location (VD);
212+ clang::SourceLocation insertion_point = VD->getBeginLoc ();
213+ unexported_public_interface (location)
214+ << VD
215+ << clang::FixItHint::CreateInsertion (insertion_point,
216+ export_macro + " " );
217+ return true ;
218+ }
166219};
167220
168221class consumer : public clang ::ASTConsumer {
0 commit comments