88#include " swift/extractor/trap/TrapDomain.h"
99#include " swift/extractor/infra/SwiftTagTraits.h"
1010#include " swift/extractor/trap/generated/TrapClasses.h"
11+ #include " swift/extractor/infra/FilePath.h"
1112
1213namespace codeql {
1314
@@ -17,6 +18,25 @@ namespace codeql {
1718// Since SwiftDispatcher sees all the AST nodes, it also attaches a location to every 'locatable'
1819// node (AST nodes that are not types: declarations, statements, expressions, etc.).
1920class 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+
2040 public:
2141 // all references and pointers passed as parameters to this constructor are supposed to outlive
2242 // the SwiftDispatcher
@@ -27,7 +47,12 @@ class SwiftDispatcher {
2747 : sourceManager{sourceManager},
2848 trap{trap},
2949 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+ }
3156
3257 template <typename Entry>
3358 void emit (const Entry& entry) {
@@ -61,9 +86,11 @@ class SwiftDispatcher {
6186 // This method gives a TRAP label for already emitted AST node.
6287 // If the AST node was not emitted yet, then the emission is dispatched to a corresponding
6388 // 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+ }
6794 // this is required so we avoid any recursive loop: a `fetchLabel` during the visit of `e` might
6895 // end up calling `fetchLabel` on `e` itself, so we want the visit of `e` to call `fetchLabel`
6996 // only after having called `assignNewLabel` on `e`.
@@ -76,7 +103,7 @@ class SwiftDispatcher {
76103 visit (e, std::forward<Args>(args)...);
77104 // TODO when everything is moved to structured C++ classes, this should be moved to createEntry
78105 if (auto l = store.get (e)) {
79- if constexpr (!std::is_base_of_v<swift::TypeBase, E>) {
106+ if constexpr (IsLocatable< E>) {
80107 attachLocation (e, *l);
81108 }
82109 return *l;
@@ -93,40 +120,37 @@ class SwiftDispatcher {
93120 return fetchLabelFromUnion<AstNodeTag>(node);
94121 }
95122
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);
102126 }
103127
104128 // Due to the lazy emission approach, we must assign a label to a corresponding AST node before
105129 // it actually gets emitted to handle recursive cases such as recursive calls, or recursive type
106130 // 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) {
109133 assert (waitingForNewLabel == Store::Handle{e} && " assignNewLabel called on wrong entity" );
110134 auto label = trap.createLabel <TrapTagOf<E>>(std::forward<Args>(args)...);
111135 store.insert (e, label);
112136 waitingForNewLabel = std::monostate{};
113137 return label;
114138 }
115139
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 >
117141 TrapLabelOf<E> assignNewLabel (const E& e, Args&&... args) {
118142 return assignNewLabel (&e, std::forward<Args>(args)...);
119143 }
120144
121145 // 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>
123147 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)...)};
125149 }
126150
127151 // used to create a new entry for entities that should not be cached
128152 // 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>
130154 auto createUncachedEntry (const E& e, Args&&... args) {
131155 auto label = trap.createLabel <TrapTagOf<E>>(std::forward<Args>(args)...);
132156 attachLocation (&e, label);
@@ -219,35 +243,23 @@ class SwiftDispatcher {
219243 }
220244
221245 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-
234246 void attachLocation (swift::SourceLoc start,
235247 swift::SourceLoc end,
236248 TrapLabel<LocatableTag> locatableLabel) {
237249 if (!start.isValid () || !end.isValid ()) {
238250 // invalid locations seem to come from entities synthesized by the compiler
239251 return ;
240252 }
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 });
251263 }
252264
253265 template <typename Tag, typename ... Ts>
@@ -276,14 +288,13 @@ class SwiftDispatcher {
276288 return false ;
277289 }
278290
279- std::string getFilepath (swift::SourceLoc loc ) {
291+ static FilePath getFilePath (llvm::StringRef path ) {
280292 // TODO: this needs more testing
281293 // TODO: check canonicaliztion of names on a case insensitive filesystems
282294 // TODO: make symlink resolution conditional on CODEQL_PRESERVE_SYMLINKS=true
283- auto displayName = sourceManager.getDisplayNameForLoc (loc);
284295 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 " ;
287298 return {};
288299 }
289300 return realPath.str ().str ();
@@ -303,6 +314,12 @@ class SwiftDispatcher {
303314 virtual void visit (swift::TypeRepr* typeRepr, swift::Type type) = 0;
304315 virtual void visit (swift::TypeBase* type) = 0;
305316
317+ void visit (const FilePath& file) {
318+ auto entry = createEntry (file);
319+ entry.name = file.path ;
320+ emit (entry);
321+ }
322+
306323 const swift::SourceManager& sourceManager;
307324 TrapDomain& trap;
308325 Store store;
0 commit comments