1 | //===- CTagsEmitter.cpp - Generate ctags-compatible index -----------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This tablegen backend emits an index of definitions in ctags(1) format. |
10 | // A helper script, utils/TableGen/tdtags, provides an easier-to-use |
11 | // interface; run 'tdtags -H' for documentation. |
12 | // |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #include "llvm/Support/MemoryBuffer.h" |
16 | #include "llvm/Support/SourceMgr.h" |
17 | #include "llvm/TableGen/Error.h" |
18 | #include "llvm/TableGen/Record.h" |
19 | #include "llvm/TableGen/TableGenBackend.h" |
20 | #include <algorithm> |
21 | #include <vector> |
22 | using namespace llvm; |
23 | |
24 | #define DEBUG_TYPE "ctags-emitter" |
25 | |
26 | namespace { |
27 | |
28 | class Tag { |
29 | private: |
30 | StringRef Id; |
31 | StringRef BufferIdentifier; |
32 | unsigned Line; |
33 | |
34 | public: |
35 | Tag(StringRef Name, const SMLoc Location) : Id(Name) { |
36 | const MemoryBuffer *CurMB = |
37 | SrcMgr.getMemoryBuffer(i: SrcMgr.FindBufferContainingLoc(Loc: Location)); |
38 | BufferIdentifier = CurMB->getBufferIdentifier(); |
39 | auto LineAndColumn = SrcMgr.getLineAndColumn(Loc: Location); |
40 | Line = LineAndColumn.first; |
41 | } |
42 | int operator<(const Tag &B) const { |
43 | return std::tuple(Id, BufferIdentifier, Line) < |
44 | std::tuple(B.Id, B.BufferIdentifier, B.Line); |
45 | } |
46 | void emit(raw_ostream &OS) const { |
47 | OS << Id << "\t" << BufferIdentifier << "\t" << Line << "\n" ; |
48 | } |
49 | }; |
50 | |
51 | class CTagsEmitter { |
52 | private: |
53 | RecordKeeper &Records; |
54 | |
55 | public: |
56 | CTagsEmitter(RecordKeeper &R) : Records(R) {} |
57 | |
58 | void run(raw_ostream &OS); |
59 | |
60 | private: |
61 | static SMLoc locate(const Record *R); |
62 | }; |
63 | |
64 | } // End anonymous namespace. |
65 | |
66 | SMLoc CTagsEmitter::locate(const Record *R) { |
67 | ArrayRef<SMLoc> Locs = R->getLoc(); |
68 | return !Locs.empty() ? Locs.front() : SMLoc(); |
69 | } |
70 | |
71 | void CTagsEmitter::run(raw_ostream &OS) { |
72 | const auto &Classes = Records.getClasses(); |
73 | const auto &Defs = Records.getDefs(); |
74 | std::vector<Tag> Tags; |
75 | // Collect tags. |
76 | Tags.reserve(n: Classes.size() + Defs.size()); |
77 | for (const auto &C : Classes) { |
78 | Tags.push_back(x: Tag(C.first, locate(R: C.second.get()))); |
79 | for (SMLoc FwdLoc : C.second->getForwardDeclarationLocs()) |
80 | Tags.push_back(x: Tag(C.first, FwdLoc)); |
81 | } |
82 | for (const auto &D : Defs) |
83 | Tags.push_back(x: Tag(D.first, locate(R: D.second.get()))); |
84 | // Emit tags. |
85 | llvm::sort(C&: Tags); |
86 | OS << "!_TAG_FILE_FORMAT\t1\t/original ctags format/\n" ; |
87 | OS << "!_TAG_FILE_SORTED\t1\t/0=unsorted, 1=sorted, 2=foldcase/\n" ; |
88 | for (const Tag &T : Tags) |
89 | T.emit(OS); |
90 | } |
91 | |
92 | static TableGen::Emitter::OptClass<CTagsEmitter> |
93 | X("gen-ctags" , "Generate ctags-compatible index" ); |
94 | |