1 module dmdtags.generate; 2 3 import dmdtags.tag: Kind; 4 import dmdtags.appender: Appender; 5 import dmdtags.span; 6 7 import dmd.declaration: AliasDeclaration, VarDeclaration; 8 import dmd.func: FuncDeclaration; 9 import dmd.denum: EnumDeclaration, EnumMember; 10 import dmd.dversion: VersionSymbol; 11 import dmd.dstruct: StructDeclaration, UnionDeclaration; 12 import dmd.dclass: ClassDeclaration, InterfaceDeclaration; 13 import dmd.dtemplate: TemplateDeclaration; 14 import dmd.nspace: Nspace; 15 import dmd.dmodule: Module; 16 import dmd.dsymbol: Dsymbol; 17 import dmd.visitor: Visitor, SemanticTimeTransitiveVisitor; 18 19 import std.meta: AliasSeq; 20 21 void putTag(ref Appender!(Span!(const(char))) sink, Dsymbol sym, bool isPrivate) 22 { 23 import dmd.root..string: toDString; 24 import std.range: put; 25 import std.format: format; 26 27 if (!sym.loc.isValid) return; 28 if (!sym.ident) return; 29 30 const(char)[] filename = sym.loc.filename.toDString; 31 if (!filename) return; 32 33 const(char)[] tag = format( 34 "%s\t%s\t%s;\"\t%s", 35 sym.ident.toString, filename, sym.loc.linnum, cast(char) sym.tagKind 36 ); 37 38 if (isPrivate) { 39 tag ~= "\tfile:"; 40 } 41 42 put(sink, tag.span.headMutable); 43 } 44 45 void putTag(ref Appender!(Span!(const(char))) sink, Module m, bool isPrivate) 46 { 47 import std.range: put; 48 import std.format: format; 49 50 if (!m.srcfile.name) return; 51 52 size_t line = m.md ? m.md.loc.linnum : 1; 53 const(char)[] tag = format( 54 "%s\t%s\t%s;\"\t%s", 55 m.ident.toString, m.srcfile.toString, line, cast(char) m.tagKind 56 ); 57 58 put(sink, tag.span.headMutable); 59 } 60 61 alias TaggableSymbols = AliasSeq!( 62 AliasDeclaration, 63 VarDeclaration, 64 FuncDeclaration, 65 EnumMember, 66 VersionSymbol, 67 StructDeclaration, 68 // UnionDeclaration 69 ClassDeclaration, 70 // InterfaceDeclaration 71 EnumDeclaration, 72 TemplateDeclaration, 73 Nspace, 74 Module 75 ); 76 77 extern(C++) class SymbolTagger : SemanticTimeTransitiveVisitor 78 { 79 import dmd.dsymbol: ScopeDsymbol, foreachDsymbol; 80 import dmd.attrib: VisibilityDeclaration; 81 82 private Appender!(Span!(const(char)))* sink; 83 private VisibilityDeclaration vd; 84 85 this(ref Appender!(Span!(const(char))) sink) 86 { 87 this.sink = &sink; 88 } 89 90 alias visit = typeof(super).visit; 91 92 void visitMembers(ScopeDsymbol s) 93 { 94 s.members.foreachDsymbol((m) { if (m) m.accept(this); }); 95 } 96 97 /* Visibility information is not available via Dsymbol.visible prior to 98 * semantic analysis, so we have to keep track of visibility attributes 99 * while walking the parse tree. 100 */ 101 override void visit(VisibilityDeclaration innerVd) 102 { 103 auto outerVd = vd; 104 vd = innerVd; 105 106 vd.decl.foreachDsymbol((d) { if (d) d.accept(this); }); 107 108 vd = outerVd; 109 } 110 111 static foreach (Symbol; TaggableSymbols) { 112 override void visit(Symbol sym) 113 { 114 import dmd.dsymbol: Visibility; 115 116 bool isPrivate = vd && vd.visibility.kind == Visibility.Kind.private_; 117 putTag(*sink, sym, isPrivate); 118 119 static if (is(Symbol : ScopeDsymbol)) 120 visitMembers(sym); 121 } 122 } 123 } 124 125 Kind tagKind(Dsymbol sym) 126 { 127 static extern(C++) class SymbolKindVisitor : Visitor 128 { 129 Kind result; 130 131 alias visit = typeof(super).visit; 132 133 override void visit(AliasDeclaration) 134 { 135 result = Kind.alias_; 136 } 137 138 override void visit(ClassDeclaration) 139 { 140 result = Kind.class_; 141 } 142 143 override void visit(EnumDeclaration) 144 { 145 result = Kind.enum_; 146 } 147 148 override void visit(EnumMember) 149 { 150 result = Kind.enumMember; 151 } 152 153 override void visit(FuncDeclaration) 154 { 155 result = Kind.function_; 156 } 157 158 override void visit(InterfaceDeclaration) 159 { 160 result = Kind.interface_; 161 } 162 163 override void visit(Module) 164 { 165 result = Kind.module_; 166 } 167 168 override void visit(Nspace) 169 { 170 result = Kind.namespace; 171 } 172 173 override void visit(StructDeclaration) 174 { 175 result = Kind.struct_; 176 } 177 178 override void visit(TemplateDeclaration) 179 { 180 result = Kind.template_; 181 } 182 183 override void visit(UnionDeclaration) 184 { 185 result = Kind.union_; 186 } 187 188 override void visit(VarDeclaration vd) 189 { 190 if (vd.parent && vd.parent.isAggregateDeclaration) 191 result = Kind.member; 192 else 193 result = Kind.variable; 194 } 195 196 override void visit(VersionSymbol) 197 { 198 result = Kind.version_; 199 } 200 } 201 202 scope v = new SymbolKindVisitor(); 203 sym.accept(v); 204 return v.result; 205 }