[PATCH] D62954: [Syntax] Add a helper to find expansion by its first spelled token

Ilya Biryukov via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 6 07:24:52 PDT 2019


ilya-biryukov created this revision.
ilya-biryukov added a reviewer: sammccall.
Herald added a subscriber: kadircet.
Herald added a project: clang.

Used in clangd for a code tweak that expands a macro.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D62954

Files:
  clang/include/clang/Tooling/Syntax/Tokens.h
  clang/lib/Tooling/Syntax/Tokens.cpp


Index: clang/lib/Tooling/Syntax/Tokens.cpp
===================================================================
--- clang/lib/Tooling/Syntax/Tokens.cpp
+++ clang/lib/Tooling/Syntax/Tokens.cpp
@@ -200,6 +200,32 @@
                   : LastSpelled + 1);
 }
 
+llvm::Optional<TokenBuffer::Expansion>
+TokenBuffer::findExpansion(const syntax::Token *Spelled) const {
+  assert(Spelled);
+  assert(Spelled->location().isFileID() && "not a spelled token");
+  auto FileIt = Files.find(SourceMgr->getFileID(Spelled->location()));
+  assert(FileIt != Files.end());
+
+  auto &File = FileIt->second;
+  assert(File.SpelledTokens.data() <= Spelled &&
+         Spelled < (File.SpelledTokens.data() + File.SpelledTokens.size()));
+
+  unsigned SpelledIndex = Spelled - File.SpelledTokens.data();
+  auto M = llvm::bsearch(File.Mappings, [&](const Mapping &M) {
+    return SpelledIndex <= M.BeginSpelled;
+  });
+  if (M == File.Mappings.end() || M->BeginSpelled != SpelledIndex)
+    return llvm::None;
+
+  Expansion E;
+  E.Spelled = llvm::makeArrayRef(File.SpelledTokens.data() + M->BeginSpelled,
+                                 File.SpelledTokens.data() + M->EndSpelled);
+  E.Expanded = llvm::makeArrayRef(ExpandedTokens.data() + M->BeginExpanded,
+                                  ExpandedTokens.data() + M->EndExpanded);
+  return E;
+}
+
 std::vector<syntax::Token> syntax::tokenize(FileID FID, const SourceManager &SM,
                                             const LangOptions &LO) {
   std::vector<syntax::Token> Tokens;
Index: clang/include/clang/Tooling/Syntax/Tokens.h
===================================================================
--- clang/include/clang/Tooling/Syntax/Tokens.h
+++ clang/include/clang/Tooling/Syntax/Tokens.h
@@ -200,6 +200,21 @@
   llvm::Optional<llvm::ArrayRef<syntax::Token>>
   spelledForExpanded(llvm::ArrayRef<syntax::Token> Expanded) const;
 
+  /// An expansion produced by the preprocessor, includes macro expansions and
+  /// macro directives. Preprocessor always maps a non-empty range of spelled
+  /// tokens to a (possibly empty) range of expanded tokens.
+  /// Here is a few examples of expansions:
+  ///    #pragme once      // Expansion from "#pragma once" to an empty range.
+  ///    #define FOO 1 2 3 // Expansion from "#define FOO 1" to an empty range.
+  ///    FOO               // Expansion from "FOO" to "1 2 3".
+  struct Expansion {
+    llvm::ArrayRef<syntax::Token> Spelled;
+    llvm::ArrayRef<syntax::Token> Expanded;
+  };
+  /// If \p Spelled starts a mapping (e.g. if it's a macro name) return the
+  /// subrange of expanded tokens that the macro expands to.
+  llvm::Optional<Expansion> findExpansion(const syntax::Token *Spelled) const;
+
   /// Lexed tokens of a file before preprocessing. E.g. for the following input
   ///     #define DECL(name) int name = 10
   ///     DECL(a);
@@ -292,6 +307,7 @@
   /// finished, i.e. after running Execute().
   LLVM_NODISCARD TokenBuffer consume() &&;
 
+
 private:
   /// Maps from a start location to an end location of each mapping.
   ///   1. range from '#' to the last token in the line for PP directives,


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D62954.203356.patch
Type: text/x-patch
Size: 3129 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20190606/5d6281b7/attachment.bin>


More information about the cfe-commits mailing list