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