8
8
#include " swift/extractor/trap/TrapDomain.h"
9
9
#include " swift/extractor/infra/SwiftTagTraits.h"
10
10
#include " swift/extractor/trap/generated/TrapClasses.h"
11
+ #include " swift/extractor/infra/FilePath.h"
11
12
12
13
namespace codeql {
13
14
@@ -17,6 +18,24 @@ namespace codeql {
17
18
// Since SwiftDispatcher sees all the AST nodes, it also attaches a location to every 'locatable'
18
19
// node (AST nodes that are not types: declarations, statements, expressions, etc.).
19
20
class SwiftDispatcher {
21
+ // types to be supported by assignNewLabel/fetchLabel need to be listed here
22
+ using Store = TrapLabelStore<const swift::Decl*,
23
+ const swift::Stmt*,
24
+ const swift::StmtCondition*,
25
+ const swift::StmtConditionElement*,
26
+ const swift::CaseLabelItem*,
27
+ const swift::Expr*,
28
+ const swift::Pattern*,
29
+ const swift::TypeRepr*,
30
+ const swift::TypeBase*,
31
+ FilePath>;
32
+
33
+ template <typename E>
34
+ static constexpr bool IsStorable = std::is_constructible_v<Store::Handle, const E&>;
35
+
36
+ template <typename E>
37
+ static constexpr bool IsLocatable = std::is_base_of_v<LocatableTag, TrapTagOf<E>>;
38
+
20
39
public:
21
40
// all references and pointers passed as parameters to this constructor are supposed to outlive
22
41
// the SwiftDispatcher
@@ -27,7 +46,12 @@ class SwiftDispatcher {
27
46
: sourceManager{sourceManager},
28
47
trap{trap},
29
48
currentModule{currentModule},
30
- currentPrimarySourceFile{currentPrimarySourceFile} {}
49
+ currentPrimarySourceFile{currentPrimarySourceFile} {
50
+ if (currentPrimarySourceFile) {
51
+ // we make sure the file is in the trap output even if the source is empty
52
+ fetchLabel (getFilePath (currentPrimarySourceFile->getFilename ()));
53
+ }
54
+ }
31
55
32
56
template <typename Entry>
33
57
void emit (const Entry& entry) {
@@ -61,9 +85,11 @@ class SwiftDispatcher {
61
85
// This method gives a TRAP label for already emitted AST node.
62
86
// If the AST node was not emitted yet, then the emission is dispatched to a corresponding
63
87
// visitor (see `visit(T *)` methods below).
64
- template <typename E>
65
- TrapLabelOf<E> fetchLabel (E* e) {
66
- assert (e && " trying to fetch a label on nullptr, maybe fetchOptionalLabel is to be used?" );
88
+ template <typename E, std::enable_if_t <IsStorable<E>>* = nullptr >
89
+ TrapLabelOf<E> fetchLabel (const E& e) {
90
+ if constexpr (std::is_constructible_v<bool , const E&>) {
91
+ assert (e && " fetching a label on a null entity, maybe fetchOptionalLabel is to be used?" );
92
+ }
67
93
// this is required so we avoid any recursive loop: a `fetchLabel` during the visit of `e` might
68
94
// end up calling `fetchLabel` on `e` itself, so we want the visit of `e` to call `fetchLabel`
69
95
// only after having called `assignNewLabel` on `e`.
@@ -76,7 +102,7 @@ class SwiftDispatcher {
76
102
visit (e);
77
103
// TODO when everything is moved to structured C++ classes, this should be moved to createEntry
78
104
if (auto l = store.get (e)) {
79
- if constexpr (!std::is_base_of_v<swift::TypeBase, E>) {
105
+ if constexpr (IsLocatable< E>) {
80
106
attachLocation (e, *l);
81
107
}
82
108
return *l;
@@ -93,36 +119,37 @@ class SwiftDispatcher {
93
119
return fetchLabelFromUnion<AstNodeTag>(node);
94
120
}
95
121
96
- TrapLabel<ConditionElementTag> fetchLabel (const swift::StmtConditionElement& element) {
97
- return fetchLabel (&element);
122
+ template <typename E, std::enable_if_t <IsStorable<E*>>* = nullptr >
123
+ TrapLabelOf<E> fetchLabel (const E& e) {
124
+ return fetchLabel (&e);
98
125
}
99
126
100
127
// Due to the lazy emission approach, we must assign a label to a corresponding AST node before
101
128
// it actually gets emitted to handle recursive cases such as recursive calls, or recursive type
102
129
// declarations
103
- template <typename E, typename ... Args>
104
- TrapLabelOf<E> assignNewLabel (E* e, Args&&... args) {
130
+ template <typename E, typename ... Args, std:: enable_if_t <IsStorable<E>>* = nullptr >
131
+ TrapLabelOf<E> assignNewLabel (const E& e, Args&&... args) {
105
132
assert (waitingForNewLabel == Store::Handle{e} && " assignNewLabel called on wrong entity" );
106
133
auto label = trap.createLabel <TrapTagOf<E>>(std::forward<Args>(args)...);
107
134
store.insert (e, label);
108
135
waitingForNewLabel = std::monostate{};
109
136
return label;
110
137
}
111
138
112
- template <typename E, typename ... Args, std::enable_if_t <!std::is_pointer_v<E >>* = nullptr >
139
+ template <typename E, typename ... Args, std::enable_if_t <IsStorable<E* >>* = nullptr >
113
140
TrapLabelOf<E> assignNewLabel (const E& e, Args&&... args) {
114
141
return assignNewLabel (&e, std::forward<Args>(args)...);
115
142
}
116
143
117
144
// convenience methods for structured C++ creation
118
- template <typename E, typename ... Args, std:: enable_if_t <!std::is_pointer_v<E>>* = nullptr >
145
+ template <typename E, typename ... Args>
119
146
auto createEntry (const E& e, Args&&... args) {
120
- return TrapClassOf<E>{assignNewLabel (& e, std::forward<Args>(args)...)};
147
+ return TrapClassOf<E>{assignNewLabel (e, std::forward<Args>(args)...)};
121
148
}
122
149
123
150
// used to create a new entry for entities that should not be cached
124
151
// an example is swift::Argument, that are created on the fly and thus have no stable pointer
125
- template <typename E, typename ... Args, std:: enable_if_t <!std::is_pointer_v<E>>* = nullptr >
152
+ template <typename E, typename ... Args>
126
153
auto createUncachedEntry (const E& e, Args&&... args) {
127
154
auto label = trap.createLabel <TrapTagOf<E>>(std::forward<Args>(args)...);
128
155
attachLocation (&e, label);
@@ -206,34 +233,23 @@ class SwiftDispatcher {
206
233
}
207
234
208
235
private:
209
- // types to be supported by assignNewLabel/fetchLabel need to be listed here
210
- using Store = TrapLabelStore<swift::Decl,
211
- swift::Stmt,
212
- swift::StmtCondition,
213
- swift::StmtConditionElement,
214
- swift::CaseLabelItem,
215
- swift::Expr,
216
- swift::Pattern,
217
- swift::TypeRepr,
218
- swift::TypeBase>;
219
-
220
236
void attachLocation (swift::SourceLoc start,
221
237
swift::SourceLoc end,
222
238
TrapLabel<LocatableTag> locatableLabel) {
223
239
if (!start.isValid () || !end.isValid ()) {
224
240
// invalid locations seem to come from entities synthesized by the compiler
225
241
return ;
226
242
}
227
- std::string filepath = getFilepath ( start);
228
- auto fileLabel = trap. createLabel <FileTag>(filepath) ;
229
- // TODO: do not emit duplicate trap entries for Files
230
- trap. emit (FilesTrap{fileLabel, filepath} );
231
- auto [startLine, startColumn] = sourceManager.getLineAndColumnInBuffer (start );
232
- auto [endLine, endColumn] = sourceManager. getLineAndColumnInBuffer (end);
233
- auto locLabel = trap. createLabel <LocationTag>( ' { ' , fileLabel, " }: " , startLine , ' :' , startColumn ,
234
- ' : ' , endLine, ' : ' , endColumn );
235
- trap. emit (LocationsTrap{locLabel, fileLabel, startLine, startColumn, endLine, endColumn} );
236
- trap. emit (LocatableLocationsTrap{locatableLabel, locLabel });
243
+ auto file = getFilePath (sourceManager. getDisplayNameForLoc ( start) );
244
+ Location entry{{}} ;
245
+ entry. file = fetchLabel (file);
246
+ std::tie (entry. start_line , entry. start_column ) = sourceManager. getLineAndColumnInBuffer (start );
247
+ std::tie (entry. end_line , entry. end_column ) = sourceManager.getLineAndColumnInBuffer (end );
248
+ entry. id = trap. createLabel <LocationTag>( ' { ' , entry. file , " }: " , entry. start_line , ' : ' ,
249
+ entry. start_column , ' : ' , entry. end_line , ' :' ,
250
+ entry. end_column );
251
+ emit (entry );
252
+ emit (LocatableLocationsTrap{locatableLabel, entry. id });
237
253
}
238
254
239
255
template <typename Tag, typename ... Ts>
@@ -256,21 +272,18 @@ class SwiftDispatcher {
256
272
return false ;
257
273
}
258
274
259
- std::string getFilepath (swift::SourceLoc loc ) {
275
+ static FilePath getFilePath (llvm::StringRef path ) {
260
276
// TODO: this needs more testing
261
277
// TODO: check canonicaliztion of names on a case insensitive filesystems
262
278
// TODO: make symlink resolution conditional on CODEQL_PRESERVE_SYMLINKS=true
263
- auto displayName = sourceManager.getDisplayNameForLoc (loc);
264
279
llvm::SmallString<PATH_MAX> realPath;
265
- if (std::error_code ec = llvm::sys::fs::real_path (displayName , realPath)) {
266
- std::cerr << " Cannot get real path: '" << displayName .str () << " ': " << ec.message () << " \n " ;
280
+ if (std::error_code ec = llvm::sys::fs::real_path (path , realPath)) {
281
+ std::cerr << " Cannot get real path: '" << path .str () << " ': " << ec.message () << " \n " ;
267
282
return {};
268
283
}
269
284
return realPath.str ().str ();
270
285
}
271
286
272
- // TODO: The following methods are supposed to redirect TRAP emission to correpsonding visitors,
273
- // which are to be introduced in follow-up PRs
274
287
virtual void visit (swift::Decl* decl) = 0;
275
288
virtual void visit (swift::Stmt* stmt) = 0;
276
289
virtual void visit (const swift::StmtCondition* cond) = 0;
@@ -281,6 +294,12 @@ class SwiftDispatcher {
281
294
virtual void visit (swift::TypeRepr* type) = 0;
282
295
virtual void visit (swift::TypeBase* type) = 0;
283
296
297
+ void visit (const FilePath& file) {
298
+ auto entry = createEntry (file);
299
+ entry.name = file.path ;
300
+ emit (entry);
301
+ }
302
+
284
303
const swift::SourceManager& sourceManager;
285
304
TrapDomain& trap;
286
305
Store store;
0 commit comments