88#include < clang/Basic/LangOptions.h>
99#include < clang/Lex/Lexer.h>
1010#include < clang/Lex/Preprocessor.h>
11+ #include < clang/Sema/Lookup.h>
1112#include < clang/Sema/Sema.h>
1213#include < llvm/ADT/DenseSet.h>
1314#include < llvm/ADT/STLExtras.h>
@@ -203,6 +204,7 @@ class RuleUsageCollector
203204 AddTemplateArgs (spec->getTemplateArgs ().asArray ());
204205 }
205206 AddSpecialMembers (record);
207+ AddIterator (type, record);
206208 }
207209 return ;
208210 }
@@ -226,6 +228,46 @@ class RuleUsageCollector
226228 }
227229 }
228230
231+ void AddIterator (clang::QualType type, const clang::CXXRecordDecl *record) {
232+ auto *std_namespace = sema_.getStdNamespace ();
233+ if (!std_namespace ||
234+ !ctx_.getSourceManager ().isInSystemHeader (record->getLocation ())) {
235+ return ;
236+ }
237+ clang::ClassTemplateDecl *traits = nullptr ;
238+ for (auto *decl :
239+ std_namespace->lookup (&ctx_.Idents .get (" iterator_traits" ))) {
240+ if ((traits = llvm::dyn_cast<clang::ClassTemplateDecl>(decl))) {
241+ break ;
242+ }
243+ }
244+ if (!traits) {
245+ return ;
246+ }
247+ auto loc = record->getLocation ();
248+ RuleDecls::Trial trial (sema_);
249+ clang::TemplateArgumentListInfo args (loc, loc);
250+ args.addArgument (
251+ clang::TemplateArgumentLoc (clang::TemplateArgument (type),
252+ ctx_.getTrivialTypeSourceInfo (type, loc)));
253+ auto instance = sema_.CheckTemplateIdType (
254+ clang::ElaboratedTypeKeyword::None, clang::TemplateName (traits), loc,
255+ args, /* Scope=*/ nullptr , /* ForNestedNameSpecifier=*/ false );
256+ if (instance.isNull () || !sema_.isCompleteType (loc, instance) ||
257+ trial.failed ()) {
258+ return ;
259+ }
260+ auto *instance_record = instance->getAsCXXRecordDecl ();
261+ if (!instance_record) {
262+ return ;
263+ }
264+ clang::LookupResult category (sema_, &ctx_.Idents .get (" iterator_category" ),
265+ loc, clang::Sema::LookupMemberName);
266+ if (sema_.LookupQualifiedName (category, instance_record)) {
267+ AddKey (kAnyIteratorKey );
268+ }
269+ }
270+
229271 void AddTemplateArgs (llvm::ArrayRef<clang::TemplateArgument> args) {
230272 for (const auto &arg : args) {
231273 switch (arg.getKind ()) {
@@ -299,31 +341,8 @@ unsigned CxxStandard(const clang::LangOptions &opts) {
299341 return 11 ;
300342}
301343
302- bool IsDeclared (clang::ASTContext &ctx, llvm::StringRef key) {
303- const clang::DeclContext *scope = ctx.getTranslationUnitDecl ();
304- while (true ) {
305- auto [name, rest] = key.split (' /' );
306- auto found = scope->lookup (&ctx.Idents .get (name));
307- if (rest.empty ()) {
308- return !found.empty ();
309- }
310- scope = nullptr ;
311- for (auto decl : found) {
312- if (llvm::isa<clang::NamespaceDecl, clang::TagDecl>(decl)) {
313- scope = llvm::cast<clang::DeclContext>(decl);
314- break ;
315- }
316- }
317- if (!scope) {
318- return false ;
319- }
320- key = rest;
321- }
322- }
323-
324344std::string BuildRulesEpilogue (const std::unordered_set<std::string> &keys,
325- clang::ASTContext &ctx) {
326- const auto &opts = ctx.getLangOpts ();
345+ const clang::LangOptions &opts) {
327346 bool is_cxx = opts.CPlusPlus ;
328347 const auto &index = is_cxx ? CxxIndex () : CIndex ();
329348 unsigned standard = is_cxx ? CxxStandard (opts) : 0 ;
@@ -352,13 +371,6 @@ std::string BuildRulesEpilogue(const std::unordered_set<std::string> &keys,
352371 })) {
353372 continue ;
354373 }
355- if (auto declared = rule->getArray (" declares" );
356- declared &&
357- !llvm::all_of (*declared, [&](const llvm::json::Value &name) {
358- return IsDeclared (ctx, *name.getAsString ());
359- })) {
360- continue ;
361- }
362374 out += WrapRule (*rule, is_cxx);
363375 }
364376 }
@@ -553,7 +565,7 @@ void PragmaHandler::HandlePragma(clang::Preprocessor &PP,
553565 RuleUsageCollector collector (CI_ .getSema (), keys);
554566 collector.TraverseDecl (ctx.getTranslationUnitDecl ());
555567
556- auto text = BuildRulesEpilogue (keys, ctx);
568+ auto text = BuildRulesEpilogue (keys, ctx. getLangOpts () );
557569 log () << " rules loaded for this translation unit:\n " << text;
558570 auto rules_file = src_mgr.createFileID (
559571 llvm::MemoryBuffer::getMemBufferCopy (text, " <cpp2rust-rules>" ),
0 commit comments