Skip to content

Commit 1c9a684

Browse files
committed
Swift: Introduce SwiftExtractionMode
1 parent 6d67ea2 commit 1c9a684

File tree

5 files changed

+130
-31
lines changed

5 files changed

+130
-31
lines changed

swift/extractor/SwiftDispatcher.h

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
namespace codeql {
1212

13+
enum class SwiftExtractionMode { Module, PrimaryFile };
14+
1315
// The main responsibilities of the SwiftDispatcher are as follows:
1416
// * redirect specific AST node emission to a corresponding visitor (statements, expressions, etc.)
1517
// * storing TRAP labels for emitted AST nodes (in the TrapLabelStore) to avoid re-emission
@@ -18,8 +20,18 @@ namespace codeql {
1820
class SwiftDispatcher {
1921
public:
2022
// sourceManager, arena, and trap are supposed to outlive the SwiftDispatcher
21-
SwiftDispatcher(const swift::SourceManager& sourceManager, TrapArena& arena, TrapOutput& trap)
22-
: sourceManager{sourceManager}, arena{arena}, trap{trap} {}
23+
SwiftDispatcher(const swift::SourceManager& sourceManager,
24+
TrapArena& arena,
25+
TrapOutput& trap,
26+
SwiftExtractionMode extractionMode,
27+
swift::ModuleDecl* currentModule,
28+
llvm::StringRef currentFileName)
29+
: sourceManager{sourceManager},
30+
arena{arena},
31+
trap{trap},
32+
extractionMode(extractionMode),
33+
currentModule{currentModule},
34+
currentFileName(currentFileName) {}
2335

2436
template <typename Entry>
2537
void emit(const Entry& entry) {
@@ -74,10 +86,10 @@ class SwiftDispatcher {
7486
// Due to the lazy emission approach, we must assign a label to a corresponding AST node before
7587
// it actually gets emitted to handle recursive cases such as recursive calls, or recursive type
7688
// declarations
77-
template <typename E>
78-
TrapLabelOf<E> assignNewLabel(E* e) {
89+
template <typename E, typename... Args>
90+
TrapLabelOf<E> assignNewLabel(E* e, Args&&... args) {
7991
assert(waitingForNewLabel == Store::Handle{e} && "assignNewLabel called on wrong entity");
80-
auto label = createLabel<TrapTagOf<E>>();
92+
auto label = createLabel<TrapTagOf<E>>(std::forward<Args>(args)...);
8193
store.insert(e, label);
8294
waitingForNewLabel = std::monostate{};
8395
return label;
@@ -120,6 +132,33 @@ class SwiftDispatcher {
120132
locatableLabel);
121133
}
122134

135+
// In order to not emit duplicated entries for declarations, we restrict emission to only
136+
// Decls declared within the current "scope".
137+
// Depending on the SwiftExtractionMode the scope is defined as follows:
138+
// - SwiftExtractionMode::Module: the current scope means the current module. This is used in
139+
// the case of system or builtin modules.
140+
// - SwiftExtractionMode::PrimaryFile: in this mode, we extract several files belnoging to the
141+
// same module one by one. In this mode, the restrict emission only to the same file ignoring
142+
// all the other files.
143+
bool shouldEmitDeclBody(swift::Decl* decl) {
144+
switch (extractionMode) {
145+
case SwiftExtractionMode::Module: {
146+
return currentModule == decl->getModuleContext();
147+
} break;
148+
case SwiftExtractionMode::PrimaryFile: {
149+
swift::SourceLoc location = decl->getStartLoc();
150+
if (!location.isValid()) {
151+
return false;
152+
}
153+
auto declFileName = sourceManager.getDisplayNameForLoc(location).str();
154+
return currentModule == decl->getModuleContext() && declFileName == currentFileName;
155+
} break;
156+
default:
157+
return false;
158+
}
159+
return false;
160+
}
161+
123162
private:
124163
// types to be supported by assignNewLabel/fetchLabel need to be listed here
125164
using Store = TrapLabelStore<swift::Decl,
@@ -199,6 +238,9 @@ class SwiftDispatcher {
199238
TrapOutput& trap;
200239
Store store;
201240
Store::Handle waitingForNewLabel{std::monostate{}};
241+
SwiftExtractionMode extractionMode;
242+
swift::ModuleDecl* currentModule;
243+
llvm::StringRef currentFileName;
202244
};
203245

204246
} // namespace codeql

swift/extractor/SwiftExtractor.cpp

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,15 @@ static void archiveFile(const SwiftExtractorConfiguration& config, swift::Source
5151

5252
static void extractDeclarations(const SwiftExtractorConfiguration& config,
5353
swift::CompilerInstance& compiler,
54-
llvm::StringRef filename,
54+
SwiftExtractionMode extractionMode,
55+
swift::ModuleDecl* module,
56+
llvm::StringRef fileName,
5557
llvm::ArrayRef<swift::Decl*> topLevelDecls) {
5658
// The extractor can be called several times from different processes with
5759
// the same input file(s)
5860
// We are using PID to avoid concurrent access
5961
// TODO: find a more robust approach to avoid collisions?
60-
std::string tempTrapName = filename.str() + '.' + std::to_string(getpid()) + ".trap";
62+
std::string tempTrapName = fileName.str() + '.' + std::to_string(getpid()) + ".trap";
6163
llvm::SmallString<PATH_MAX> tempTrapPath(config.trapDir);
6264
llvm::sys::path::append(tempTrapPath, tempTrapName);
6365

@@ -94,23 +96,22 @@ static void extractDeclarations(const SwiftExtractorConfiguration& config,
9496
trap.assignKey(unknownLocationLabel, "unknown");
9597
trap.emit(LocationsTrap{unknownLocationLabel, unknownFileLabel});
9698

97-
SwiftVisitor visitor(compiler.getSourceMgr(), arena, trap);
98-
for (swift::Decl* decl : topLevelDecls) {
99+
SwiftVisitor visitor(compiler.getSourceMgr(), arena, trap, extractionMode, module, fileName);
100+
for (auto decl : topLevelDecls) {
99101
visitor.extract(decl);
100102
}
101103
if (topLevelDecls.empty()) {
102-
// In the case of emtpy files, the dispatcher is not called, but we still want to 'record' the
104+
// In the case of empty files, the dispatcher is not called, but we still want to 'record' the
103105
// fact that the file was extracted
104-
// TODO: to be moved elsewhere
105-
llvm::SmallString<PATH_MAX> srcFilePath(filename);
106-
llvm::sys::fs::make_absolute(srcFilePath);
106+
llvm::SmallString<PATH_MAX> name(fileName);
107+
llvm::sys::fs::make_absolute(name);
107108
auto fileLabel = arena.allocateLabel<FileTag>();
108-
trap.assignKey(fileLabel, srcFilePath.str().str());
109-
trap.emit(FilesTrap{fileLabel, srcFilePath.str().str()});
109+
trap.assignKey(fileLabel, name.str().str());
110+
trap.emit(FilesTrap{fileLabel, name.str().str()});
110111
}
111112

112113
// TODO: Pick a better name to avoid collisions
113-
std::string trapName = filename.str() + ".trap";
114+
std::string trapName = fileName.str() + ".trap";
114115
llvm::SmallString<PATH_MAX> trapPath(config.trapDir);
115116
llvm::sys::path::append(trapPath, trapName);
116117

@@ -132,14 +133,15 @@ void codeql::extractSwiftFiles(const SwiftExtractorConfiguration& config,
132133
llvm::SmallVector<swift::Decl*> decls;
133134
module->getTopLevelDecls(decls);
134135
// TODO: pass ModuleDecl directly when we have module extraction in place?
135-
extractDeclarations(config, compiler, module->getModuleFilename(), decls);
136+
extractDeclarations(config, compiler, SwiftExtractionMode::Module, module,
137+
module->getModuleFilename(), decls);
136138
} else {
137139
// The extraction will only work if one (or more) `-primary-file` CLI option is provided,
138140
// which is what always happens in case of `swift build` and `xcodebuild`
139141
for (auto primaryFile : module->getPrimarySourceFiles()) {
140142
archiveFile(config, *primaryFile);
141-
extractDeclarations(config, compiler, primaryFile->getFilename(),
142-
primaryFile->getTopLevelDecls());
143+
extractDeclarations(config, compiler, SwiftExtractionMode::PrimaryFile, module,
144+
primaryFile->getFilename(), primaryFile->getTopLevelDecls());
143145
}
144146
}
145147
}

swift/extractor/trap/TrapOutput.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ class TrapOutput {
3939
print(e);
4040
}
4141

42+
template <typename... Args>
43+
void debug(const Args&... args) {
44+
out_ << "// DEBUG: ";
45+
(out_ << ... << args) << '\n';
46+
}
47+
4248
private:
4349
template <typename... Args>
4450
void print(const Args&... args) {

swift/extractor/visitors/DeclVisitor.h

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <swift/AST/Decl.h>
44
#include <swift/AST/GenericParamList.h>
55
#include <swift/AST/ParameterList.h>
6+
#include <swift/AST/ASTMangler.h>
67

78
#include "swift/extractor/visitors/VisitorBase.h"
89

@@ -20,20 +21,29 @@ class DeclVisitor : public AstVisitorBase<DeclVisitor> {
2021
using AstVisitorBase<DeclVisitor>::AstVisitorBase;
2122

2223
void visitFuncDecl(swift::FuncDecl* decl) {
23-
auto label = dispatcher_.assignNewLabel(decl);
24+
auto label = dispatcher_.assignNewLabel(decl, mangledName(decl));
2425
dispatcher_.emit(ConcreteFuncDeclsTrap{label});
26+
if (!dispatcher_.shouldEmitDeclBody(decl)) {
27+
return;
28+
}
2529
emitAbstractFunctionDecl(decl, label);
2630
}
2731

2832
void visitConstructorDecl(swift::ConstructorDecl* decl) {
29-
auto label = dispatcher_.assignNewLabel(decl);
33+
auto label = dispatcher_.assignNewLabel(decl, mangledName(decl));
3034
dispatcher_.emit(ConstructorDeclsTrap{label});
35+
if (!dispatcher_.shouldEmitDeclBody(decl)) {
36+
return;
37+
}
3138
emitConstructorDecl(decl, label);
3239
}
3340

3441
void visitDestructorDecl(swift::DestructorDecl* decl) {
35-
auto label = dispatcher_.assignNewLabel(decl);
42+
auto label = dispatcher_.assignNewLabel(decl, mangledName(decl));
3643
dispatcher_.emit(DestructorDeclsTrap{label});
44+
if (!dispatcher_.shouldEmitDeclBody(decl)) {
45+
return;
46+
}
3747
emitDestructorDecl(decl, label);
3848
}
3949

@@ -64,6 +74,7 @@ class DeclVisitor : public AstVisitorBase<DeclVisitor> {
6474
}
6575

6676
void visitParamDecl(swift::ParamDecl* decl) {
77+
// TODO: deduplicate
6778
auto label = dispatcher_.assignNewLabel(decl);
6879
dispatcher_.emit(ParamDeclsTrap{label});
6980
if (decl->isInOut()) {
@@ -92,33 +103,46 @@ class DeclVisitor : public AstVisitorBase<DeclVisitor> {
92103
}
93104

94105
void visitVarDecl(swift::VarDecl* decl) {
106+
// TODO: deduplicate all non-local variables
95107
auto label = dispatcher_.assignNewLabel(decl);
96108
auto introducer = static_cast<uint8_t>(decl->getIntroducer());
97109
dispatcher_.emit(ConcreteVarDeclsTrap{label, introducer});
98110
emitVarDecl(decl, label);
99111
}
100112

101113
void visitStructDecl(swift::StructDecl* decl) {
102-
auto label = dispatcher_.assignNewLabel(decl);
114+
auto label = dispatcher_.assignNewLabel(decl, mangledName(decl));
103115
dispatcher_.emit(StructDeclsTrap{label});
116+
if (!dispatcher_.shouldEmitDeclBody(decl)) {
117+
return;
118+
}
104119
emitNominalTypeDecl(decl, label);
105120
}
106121

107122
void visitClassDecl(swift::ClassDecl* decl) {
108-
auto label = dispatcher_.assignNewLabel(decl);
123+
auto label = dispatcher_.assignNewLabel(decl, mangledName(decl));
109124
dispatcher_.emit(ClassDeclsTrap{label});
125+
if (!dispatcher_.shouldEmitDeclBody(decl)) {
126+
return;
127+
}
110128
emitNominalTypeDecl(decl, label);
111129
}
112130

113131
void visitEnumDecl(swift::EnumDecl* decl) {
114-
auto label = dispatcher_.assignNewLabel(decl);
132+
auto label = dispatcher_.assignNewLabel(decl, mangledName(decl));
115133
dispatcher_.emit(EnumDeclsTrap{label});
134+
if (!dispatcher_.shouldEmitDeclBody(decl)) {
135+
return;
136+
}
116137
emitNominalTypeDecl(decl, label);
117138
}
118139

119140
void visitProtocolDecl(swift::ProtocolDecl* decl) {
120-
auto label = dispatcher_.assignNewLabel(decl);
141+
auto label = dispatcher_.assignNewLabel(decl, mangledName(decl));
121142
dispatcher_.emit(ProtocolDeclsTrap{label});
143+
if (!dispatcher_.shouldEmitDeclBody(decl)) {
144+
return;
145+
}
122146
emitNominalTypeDecl(decl, label);
123147
}
124148

@@ -132,8 +156,11 @@ class DeclVisitor : public AstVisitorBase<DeclVisitor> {
132156
}
133157

134158
void visitEnumElementDecl(swift::EnumElementDecl* decl) {
135-
auto label = dispatcher_.assignNewLabel(decl);
159+
auto label = dispatcher_.assignNewLabel(decl, mangledName(decl));
136160
dispatcher_.emit(EnumElementDeclsTrap{label, decl->getNameStr().str()});
161+
if (!dispatcher_.shouldEmitDeclBody(decl)) {
162+
return;
163+
}
137164
if (decl->hasParameterList()) {
138165
auto i = 0u;
139166
for (auto p : *decl->getParameterList()) {
@@ -143,26 +170,36 @@ class DeclVisitor : public AstVisitorBase<DeclVisitor> {
143170
}
144171

145172
void visitGenericTypeParamDecl(swift::GenericTypeParamDecl* decl) {
173+
// TODO: deduplicate
146174
auto label = dispatcher_.assignNewLabel(decl);
147175
dispatcher_.emit(GenericTypeParamDeclsTrap{label});
148176
emitTypeDecl(decl, label);
149177
}
150178

151179
void visitAssociatedTypeDecl(swift::AssociatedTypeDecl* decl) {
152-
auto label = dispatcher_.assignNewLabel(decl);
180+
auto label = dispatcher_.assignNewLabel(decl, mangledName(decl));
153181
dispatcher_.emit(AssociatedTypeDeclsTrap{label});
182+
if (!dispatcher_.shouldEmitDeclBody(decl)) {
183+
return;
184+
}
154185
emitTypeDecl(decl, label);
155186
}
156187

157188
void visitTypeAliasDecl(swift::TypeAliasDecl* decl) {
158-
auto label = dispatcher_.assignNewLabel(decl);
189+
auto label = dispatcher_.assignNewLabel(decl, mangledName(decl));
159190
dispatcher_.emit(TypeAliasDeclsTrap{label});
191+
if (!dispatcher_.shouldEmitDeclBody(decl)) {
192+
return;
193+
}
160194
emitTypeDecl(decl, label);
161195
}
162196

163197
void visitAccessorDecl(swift::AccessorDecl* decl) {
164-
auto label = dispatcher_.assignNewLabel(decl);
198+
auto label = dispatcher_.assignNewLabel(decl, mangledName(decl));
165199
dispatcher_.emit(AccessorDeclsTrap{label});
200+
if (!dispatcher_.shouldEmitDeclBody(decl)) {
201+
return;
202+
}
166203
switch (decl->getAccessorKind()) {
167204
case swift::AccessorKind::Get:
168205
dispatcher_.emit(AccessorDeclIsGetterTrap{label});
@@ -181,7 +218,10 @@ class DeclVisitor : public AstVisitorBase<DeclVisitor> {
181218
}
182219

183220
void visitSubscriptDecl(swift::SubscriptDecl* decl) {
184-
auto label = dispatcher_.assignNewLabel(decl);
221+
auto label = dispatcher_.assignNewLabel(decl, mangledName(decl));
222+
if (!dispatcher_.shouldEmitDeclBody(decl)) {
223+
return;
224+
}
185225
auto elementTypeLabel = dispatcher_.fetchLabel(decl->getElementInterfaceType());
186226
dispatcher_.emit(SubscriptDeclsTrap{label, elementTypeLabel});
187227
if (auto indices = decl->getIndices()) {
@@ -202,6 +242,11 @@ class DeclVisitor : public AstVisitorBase<DeclVisitor> {
202242
}
203243

204244
private:
245+
std::string mangledName(swift::ValueDecl* decl) {
246+
// prefix adds a couple of special symbols, we don't necessary need them
247+
return mangler.mangleAnyDecl(decl, /* prefix = */ false);
248+
}
249+
205250
void emitConstructorDecl(swift::ConstructorDecl* decl, TrapLabel<ConstructorDeclTag> label) {
206251
emitAbstractFunctionDecl(decl, label);
207252
}
@@ -309,6 +354,9 @@ class DeclVisitor : public AstVisitorBase<DeclVisitor> {
309354
}
310355
emitValueDecl(decl, label);
311356
}
357+
358+
private:
359+
swift::Mangle::ASTMangler mangler;
312360
};
313361

314362
} // namespace codeql

swift/integration-tests/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ Packages
55
xcuserdata/
66
DerivedData/
77
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8+
*.actual

0 commit comments

Comments
 (0)