FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
codeql/swift/extractor/SwiftExtractor.cpp at codeql-cli-2.11.3 · github/codeql · GitHub
github
/
codeql
Public
Notifications
You must be signed in to change notification settings
Fork
2.1k
Star
10.1k
Code
Issues
1k
Pull requests
468
Discussions
Actions
Projects
Security and quality
0
Insights
Additional navigation options
Code
Issues
Pull requests
Discussions
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
codeql
/
swift
/
extractor
/
SwiftExtractor.cpp
Copy path
More file actions
More file actions
Latest commit
History
History
History
215 lines (193 loc) · 7.88 KB
Breadcrumbs
codeql
/
swift
/
extractor
/
SwiftExtractor.cpp
Copy path
File metadata and controls
215 lines (193 loc) · 7.88 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#
include
"
SwiftExtractor.h
"
#
include
<
iostream
>
#
include
<
memory
>
#
include
<
unordered_set
>
#
include
<
queue
>
#
include
<
swift/AST/SourceFile.h
>
#
include
<
swift/AST/Builtins.h
>
#
include
"
swift/extractor/trap/TrapDomain.h
"
#
include
"
swift/extractor/visitors/SwiftVisitor.h
"
#
include
"
swift/extractor/TargetTrapFile.h
"
#
include
"
swift/extractor/SwiftBuiltinSymbols.h
"
using
namespace
codeql
;
using
namespace
std
::string_literals
;
namespace
fs
=
std::filesystem;
static
fs::path
toPath
(llvm::StringRef s) {
return
{
static_cast
<std::string_view>(s)};
}
static
void
ensureDirectory
(
const
char
* label,
const
fs::path& dir) {
std::error_code ec;
fs::create_directories
(dir, ec);
if
(ec) {
std::cerr <<
"
Cannot create
"
<< label <<
"
directory:
"
<< ec.
message
() <<
"
\n
"
;
std::abort
();
}
}
static
void
archiveFile
(
const
SwiftExtractorConfiguration& config, swift::SourceFile& file) {
ensureDirectory
(
"
TRAP
"
, config.
trapDir
);
ensureDirectory
(
"
source archive
"
, config.
sourceArchiveDir
);
fs::path srcFilePath =
fs::absolute
(
toPath
(file.
getFilename
()));
auto
dstFilePath = config.
sourceArchiveDir
;
dstFilePath += srcFilePath;
ensureDirectory
(
"
source archive destination
"
, dstFilePath.
parent_path
());
std::error_code ec;
fs::copy
(srcFilePath, dstFilePath, fs::copy_options::overwrite_existing, ec);
if
(ec) {
std::cerr <<
"
Cannot archive source file
"
<< srcFilePath <<
"
->
"
<< dstFilePath <<
"
:
"
<< ec.
message
() <<
"
\n
"
;
std::abort
();
}
}
static
fs::path
getFilename
(swift::ModuleDecl&
module
, swift::SourceFile* primaryFile) {
if
(primaryFile) {
return
primaryFile->
getFilename
().
str
();
}
//
PCM clang module
if
(
module
.
isNonSwiftModule
()) {
//
Several modules with different names might come from .pcm (clang module) files
//
In this case we want to differentiate them
//
Moreover, pcm files may come from caches located in different directories, but are
//
unambiguously identified by the base file name, so we can discard the absolute directory
fs::path filename =
"
/pcms
"
;
filename /=
toPath
(
module
.
getModuleFilename
()).
filename
();
filename +=
"
-
"
;
filename +=
module
.
getName
().
str
();
return
filename;
}
if
(
module
.
isBuiltinModule
()) {
//
The Builtin module has an empty filename, let's fix that
return
"
/__Builtin__
"
;
}
auto
filename =
toPath
(
module
.
getModuleFilename
());
//
there is a special case of a module without an actual filename reporting `<imports>`: in this
//
case we want to avoid the `<>` characters, in case a dirty DB is imported on Windows
if
(filename ==
"
<imports>
"
) {
return
"
/__imports__
"
;
}
return
filename;
}
/*
The builtin module is special, as it does not publish any top-level declaration
* It creates (and caches) declarations on demand when a lookup is carried out
* (see BuiltinUnit in swift/AST/FileUnit.h for the cache details, and getBuiltinValueDecl in
* swift/AST/Builtins.h for the creation details)
* As we want to create the Builtin trap file once and for all so that it works for other
* extraction runs, rather than collecting what we need we pre-populate the builtin trap with
* what we expect. This list might need thus to be expanded.
* Notice, that while swift/AST/Builtins.def has a list of builtin symbols, it does not contain
* all information required to instantiate builtin variants.
* Other possible approaches:
* * create one trap per builtin declaration when encountered
* * expand the list to all possible builtins (of which there are a lot)
*/
static
void
getBuiltinDecls
(swift::ModuleDecl& builtinModule,
llvm::SmallVector<swift::Decl*>& decls) {
llvm::SmallVector<swift::ValueDecl*> values;
for
(
auto
symbol : swiftBuiltins) {
builtinModule.
lookupValue
(builtinModule.
getASTContext
().
getIdentifier
(symbol),
swift::NLKind::QualifiedLookup, values);
}
decls.
insert
(decls.
end
(), values.
begin
(), values.
end
());
}
static
llvm::SmallVector<swift::Decl*>
getTopLevelDecls
(swift::ModuleDecl&
module
,
swift::SourceFile* primaryFile =
nullptr
) {
llvm::SmallVector<swift::Decl*> ret;
ret.
push_back
(&
module
);
if
(primaryFile) {
primaryFile->
getTopLevelDecls
(ret);
}
else
if
(
module
.
isBuiltinModule
()) {
getBuiltinDecls
(
module
, ret);
}
else
{
module
.
getTopLevelDecls
(ret);
}
return
ret;
}
static
std::unordered_set<swift::ModuleDecl*>
extractDeclarations
(
const
SwiftExtractorConfiguration& config,
swift::CompilerInstance& compiler,
swift::ModuleDecl&
module
,
swift::SourceFile* primaryFile =
nullptr
) {
auto
filename =
getFilename
(
module
, primaryFile);
//
The extractor can be called several times from different processes with
//
the same input file(s). Using `TargetFile` the first process will win, and the following
//
will just skip the work
auto
trapTarget =
createTargetTrapFile
(config, filename);
if
(!trapTarget) {
//
another process arrived first, nothing to do for us
return
{};
}
TrapDomain trap{*trapTarget};
std::vector<swift::Token> comments;
if
(primaryFile && primaryFile->
getBufferID
().
hasValue
()) {
auto
& sourceManager = compiler.
getSourceMgr
();
auto
tokens =
swift::tokenize
(compiler.
getInvocation
().
getLangOptions
(), sourceManager,
primaryFile->
getBufferID
().
getValue
());
for
(
auto
& token : tokens) {
if
(token.
getKind
() == swift::tok::comment) {
comments.
push_back
(token);
}
}
}
SwiftVisitor
visitor
(compiler.
getSourceMgr
(), trap,
module
, primaryFile);
auto
topLevelDecls =
getTopLevelDecls
(
module
, primaryFile);
for
(
auto
decl : topLevelDecls) {
visitor.
extract
(decl);
}
for
(
auto
& comment : comments) {
visitor.
extract
(comment);
}
return
std::move
(visitor).
getEncounteredModules
();
}
static
std::unordered_set<std::string>
collectInputFilenames
(swift::CompilerInstance& compiler) {
//
The frontend can be called in many different ways.
//
At each invocation we only extract system and builtin modules and any input source files that
//
have an output associated with them.
std::unordered_set<std::string> sourceFiles;
auto
inputFiles = compiler.
getInvocation
().
getFrontendOptions
().
InputsAndOutputs
.
getAllInputs
();
for
(
auto
& input : inputFiles) {
if
(input.
getType
() == swift::file_types::TY_Swift && !input.
outputFilename
().
empty
()) {
sourceFiles.
insert
(input.
getFileName
());
}
}
return
sourceFiles;
}
static
std::vector<swift::ModuleDecl*>
collectLoadedModules
(swift::CompilerInstance& compiler) {
std::vector<swift::ModuleDecl*> ret;
for
(
const
auto
& [id,
module
] : compiler.
getASTContext
().
getLoadedModules
()) {
std::ignore = id;
ret.
push_back
(
module
);
}
return
ret;
}
void
codeql::extractSwiftFiles
(
const
SwiftExtractorConfiguration& config,
swift::CompilerInstance& compiler) {
auto
inputFiles =
collectInputFilenames
(compiler);
std::vector<swift::ModuleDecl*> todo =
collectLoadedModules
(compiler);
std::unordered_set<swift::ModuleDecl*> seen{todo.
begin
(), todo.
end
()};
while
(!todo.
empty
()) {
auto
module
= todo.
back
();
todo.
pop_back
();
bool
isFromSourceFile =
false
;
std::unordered_set<swift::ModuleDecl*> encounteredModules;
for
(
auto
file :
module
->
getFiles
()) {
auto
sourceFile = llvm::dyn_cast<swift::SourceFile>(file);
if
(!sourceFile) {
continue
;
}
isFromSourceFile =
true
;
if
(inputFiles.
count
(sourceFile->
getFilename
().
str
()) ==
0
) {
continue
;
}
archiveFile
(config, *sourceFile);
encounteredModules =
extractDeclarations
(config, compiler, *
module
, sourceFile);
}
if
(!isFromSourceFile) {
encounteredModules =
extractDeclarations
(config, compiler, *
module
);
}
for
(
auto
encountered : encounteredModules) {
if
(seen.
count
(encountered) ==
0
) {
todo.
push_back
(encountered);
seen.
insert
(encountered);
}
}
}
}
Back
|
FazBrowse Home
|
New Git URL