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,24 @@ 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+ 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+
2039 public:
2140 // all references and pointers passed as parameters to this constructor are supposed to outlive
2241 // the SwiftDispatcher
@@ -27,7 +46,12 @@ class SwiftDispatcher {
2746 : sourceManager{sourceManager},
2847 trap{trap},
2948 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+ }
3155
3256 template <typename Entry>
3357 void emit (const Entry& entry) {
@@ -61,9 +85,11 @@ class SwiftDispatcher {
6185 // This method gives a TRAP label for already emitted AST node.
6286 // If the AST node was not emitted yet, then the emission is dispatched to a corresponding
6387 // 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+ }
6793 // this is required so we avoid any recursive loop: a `fetchLabel` during the visit of `e` might
6894 // end up calling `fetchLabel` on `e` itself, so we want the visit of `e` to call `fetchLabel`
6995 // only after having called `assignNewLabel` on `e`.
@@ -76,7 +102,7 @@ class SwiftDispatcher {
76102 visit (e);
77103 // TODO when everything is moved to structured C++ classes, this should be moved to createEntry
78104 if (auto l = store.get (e)) {
79- if constexpr (!std::is_base_of_v<swift::TypeBase, E>) {
105+ if constexpr (IsLocatable< E>) {
80106 attachLocation (e, *l);
81107 }
82108 return *l;
@@ -93,36 +119,37 @@ class SwiftDispatcher {
93119 return fetchLabelFromUnion<AstNodeTag>(node);
94120 }
95121
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);
98125 }
99126
100127 // Due to the lazy emission approach, we must assign a label to a corresponding AST node before
101128 // it actually gets emitted to handle recursive cases such as recursive calls, or recursive type
102129 // 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) {
105132 assert (waitingForNewLabel == Store::Handle{e} && " assignNewLabel called on wrong entity" );
106133 auto label = trap.createLabel <TrapTagOf<E>>(std::forward<Args>(args)...);
107134 store.insert (e, label);
108135 waitingForNewLabel = std::monostate{};
109136 return label;
110137 }
111138
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 >
113140 TrapLabelOf<E> assignNewLabel (const E& e, Args&&... args) {
114141 return assignNewLabel (&e, std::forward<Args>(args)...);
115142 }
116143
117144 // 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>
119146 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)...)};
121148 }
122149
123150 // used to create a new entry for entities that should not be cached
124151 // 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>
126153 auto createUncachedEntry (const E& e, Args&&... args) {
127154 auto label = trap.createLabel <TrapTagOf<E>>(std::forward<Args>(args)...);
128155 attachLocation (&e, label);
@@ -206,34 +233,23 @@ class SwiftDispatcher {
206233 }
207234
208235 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-
220236 void attachLocation (swift::SourceLoc start,
221237 swift::SourceLoc end,
222238 TrapLabel<LocatableTag> locatableLabel) {
223239 if (!start.isValid () || !end.isValid ()) {
224240 // invalid locations seem to come from entities synthesized by the compiler
225241 return ;
226242 }
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 });
237253 }
238254
239255 template <typename Tag, typename ... Ts>
@@ -256,21 +272,18 @@ class SwiftDispatcher {
256272 return false ;
257273 }
258274
259- std::string getFilepath (swift::SourceLoc loc ) {
275+ static FilePath getFilePath (llvm::StringRef path ) {
260276 // TODO: this needs more testing
261277 // TODO: check canonicaliztion of names on a case insensitive filesystems
262278 // TODO: make symlink resolution conditional on CODEQL_PRESERVE_SYMLINKS=true
263- auto displayName = sourceManager.getDisplayNameForLoc (loc);
264279 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 " ;
267282 return {};
268283 }
269284 return realPath.str ().str ();
270285 }
271286
272- // TODO: The following methods are supposed to redirect TRAP emission to correpsonding visitors,
273- // which are to be introduced in follow-up PRs
274287 virtual void visit (swift::Decl* decl) = 0;
275288 virtual void visit (swift::Stmt* stmt) = 0;
276289 virtual void visit (const swift::StmtCondition* cond) = 0;
@@ -281,6 +294,12 @@ class SwiftDispatcher {
281294 virtual void visit (swift::TypeRepr* type) = 0;
282295 virtual void visit (swift::TypeBase* type) = 0;
283296
297+ void visit (const FilePath& file) {
298+ auto entry = createEntry (file);
299+ entry.name = file.path ;
300+ emit (entry);
301+ }
302+
284303 const swift::SourceManager& sourceManager;
285304 TrapDomain& trap;
286305 Store store;
0 commit comments