Skip to content

Commit 67cd251

Browse files
authored
Merge pull request github#12433 from github/alexdenisov+redsun82/tuple-mangling
Swift: properly identify types and declarations in trap files via mangling
2 parents 48048d6 + 0dafe2d commit 67cd251

File tree

23 files changed

+751
-170
lines changed

23 files changed

+751
-170
lines changed

swift/extractor/SwiftExtractor.cpp

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include "swift/extractor/infra/file/Path.h"
1515
#include "swift/extractor/infra/SwiftLocationExtractor.h"
1616
#include "swift/extractor/infra/SwiftBodyEmissionStrategy.h"
17-
#include "swift/extractor/mangler/SwiftMangler.h"
1817
#include "swift/logging/SwiftAssert.h"
1918

2019
using namespace codeql;
@@ -49,24 +48,20 @@ static void archiveFile(const SwiftExtractorConfiguration& config, swift::Source
4948
}
5049
}
5150

52-
// TODO: This should be factored out/replaced with simplified version of custom mangling
53-
static std::string mangledDeclName(const swift::ValueDecl& decl) {
54-
std::string_view moduleName = decl.getModuleContext()->getRealName().str();
55-
// ASTMangler::mangleAnyDecl crashes when called on `ModuleDecl`
56-
if (decl.getKind() == swift::DeclKind::Module) {
57-
return std::string{moduleName};
58-
}
59-
swift::Mangle::ASTMangler mangler;
60-
if (decl.getKind() == swift::DeclKind::TypeAlias) {
61-
// In cases like this (when coming from PCM)
62-
// typealias CFXMLTree = CFTree
63-
// typealias CFXMLTreeRef = CFXMLTree
64-
// mangleAnyDecl mangles both CFXMLTree and CFXMLTreeRef into 'So12CFXMLTreeRefa'
65-
// which is not correct and causes inconsistencies. mangleEntity makes these two distinct
66-
// prefix adds a couple of special symbols, we don't necessary need them
67-
return mangler.mangleEntity(&decl);
51+
static std::string mangledDeclName(const swift::Decl& decl) {
52+
// SwiftRecursiveMangler mangled name cannot be used directly as it can be too long for file names
53+
// so we build some minimal human readable info for debuggability and append a hash
54+
auto ret = decl.getModuleContext()->getRealName().str().str();
55+
ret += '/';
56+
ret += swift::Decl::getKindName(decl.getKind());
57+
ret += '_';
58+
if (auto valueDecl = llvm::dyn_cast<swift::ValueDecl>(&decl); valueDecl && valueDecl->hasName()) {
59+
ret += valueDecl->getBaseName().userFacingName();
60+
ret += '_';
6861
}
69-
return mangler.mangleAnyDecl(&decl, /* prefix = */ false);
62+
SwiftRecursiveMangler mangler;
63+
ret += mangler.mangleDecl(decl).hash();
64+
return ret;
7065
}
7166

7267
static fs::path getFilename(swift::ModuleDecl& module,
@@ -76,20 +71,7 @@ static fs::path getFilename(swift::ModuleDecl& module,
7671
return resolvePath(primaryFile->getFilename());
7772
}
7873
if (lazyDeclaration) {
79-
// this code will be thrown away in the near future
80-
auto decl = llvm::dyn_cast<swift::ValueDecl>(lazyDeclaration);
81-
CODEQL_ASSERT(decl, "not a ValueDecl");
82-
auto mangled = mangledDeclName(*decl);
83-
// mangled name can be too long to use as a file name, so we can't use it directly
84-
mangled = picosha2::hash256_hex_string(mangled);
85-
std::string ret;
86-
ret += module.getRealName().str();
87-
ret += '_';
88-
ret += decl->getBaseName().userFacingName();
89-
ret += '_';
90-
// half a SHA2 is enough
91-
ret += std::string_view(mangled).substr(0, mangled.size() / 2);
92-
return ret;
74+
return mangledDeclName(*lazyDeclaration);
9375
}
9476
// PCM clang module
9577
if (module.isNonSwiftModule()) {

swift/extractor/infra/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ swift_cc_library(
1111
"//swift/extractor/trap",
1212
"//swift/logging",
1313
"//swift/third_party/swift-llvm-support",
14+
"@picosha2",
1415
],
1516
)

swift/extractor/infra/SwiftLocationExtractor.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sour
2525
entry.file = fetchFileLabel(file);
2626
std::tie(entry.start_line, entry.start_column) = sourceManager.getLineAndColumnInBuffer(start);
2727
std::tie(entry.end_line, entry.end_column) = sourceManager.getLineAndColumnInBuffer(end);
28-
SwiftMangledName locName{{"loc", entry.file, ":", entry.start_line, ":", entry.start_column, ":",
29-
entry.end_line, ":", entry.end_column}};
28+
SwiftMangledName locName{"loc", entry.file, ':', entry.start_line, ':', entry.start_column,
29+
':', entry.end_line, ':', entry.end_column};
3030
entry.id = trap.createTypedLabel<DbLocationTag>(locName);
3131
trap.emit(entry);
3232
trap.emit(LocatableLocationsTrap{locatableLabel, entry.id});
@@ -99,7 +99,7 @@ TrapLabel<FileTag> SwiftLocationExtractor::fetchFileLabel(const std::filesystem:
9999
}
100100

101101
DbFile entry({});
102-
entry.id = trap.createTypedLabel<DbFileTag>({{"file_", file.string()}});
102+
entry.id = trap.createTypedLabel<DbFileTag>({"file_", file.string()});
103103
entry.name = file.string();
104104
trap.emit(entry);
105105
store[file] = entry.id;
Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,25 @@
11
#include "swift/extractor/infra/SwiftMangledName.h"
22
#include "absl/strings/str_cat.h"
33

4-
namespace codeql {
4+
#include <picosha2.h>
55

6-
namespace {
7-
void appendPart(std::string& out, const std::string& prefix) {
8-
out += prefix;
9-
}
6+
namespace codeql {
107

11-
void appendPart(std::string& out, UntypedTrapLabel label) {
12-
absl::StrAppend(&out, "{", label.str(), "}");
8+
std::string SwiftMangledName::hash() const {
9+
auto ret = picosha2::hash256_hex_string(value);
10+
// half a hash is already enough for disambuiguation
11+
ret.resize(ret.size() / 2);
12+
return ret;
1313
}
1414

15-
void appendPart(std::string& out, unsigned index) {
16-
absl::StrAppend(&out, index);
15+
SwiftMangledName& SwiftMangledName::operator<<(UntypedTrapLabel label) & {
16+
absl::StrAppend(&value, "{", label.str(), "}");
17+
return *this;
1718
}
1819

19-
} // namespace
20-
21-
std::string SwiftMangledName::str() const {
22-
std::string out;
23-
for (const auto& part : parts) {
24-
std::visit([&](const auto& contents) { appendPart(out, contents); }, part);
25-
}
26-
return out;
20+
SwiftMangledName& SwiftMangledName::operator<<(unsigned int i) & {
21+
absl::StrAppend(&value, i);
22+
return *this;
2723
}
2824

2925
} // namespace codeql

swift/extractor/infra/SwiftMangledName.h

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,52 @@
99

1010
namespace codeql {
1111

12-
struct SwiftMangledName {
12+
class SwiftMangledName {
13+
public:
1314
using Part = std::variant<UntypedTrapLabel, std::string, unsigned>;
1415

15-
std::vector<Part> parts;
16+
explicit operator bool() const { return !value.empty(); }
1617

17-
explicit operator bool() const { return !parts.empty(); }
18+
const std::string& str() const { return value; }
19+
operator std::string_view() const { return value; }
1820

19-
std::string str() const;
21+
std::string hash() const;
2022

21-
// streaming labels or ints into a SwiftMangledName just appends them
22-
template <typename Tag>
23-
SwiftMangledName& operator<<(TrapLabel<Tag> label) {
24-
parts.emplace_back(label);
25-
return *this;
23+
// let's avoid copying as long as we don't need it
24+
SwiftMangledName() = default;
25+
SwiftMangledName(const SwiftMangledName&) = delete;
26+
SwiftMangledName& operator=(const SwiftMangledName&) = delete;
27+
SwiftMangledName(SwiftMangledName&&) = default;
28+
SwiftMangledName& operator=(SwiftMangledName&&) = default;
29+
30+
template <typename... Args>
31+
SwiftMangledName(Args&&... args) {
32+
(operator<<(std::forward<Args>(args)), ...);
2633
}
2734

28-
SwiftMangledName& operator<<(unsigned i) {
29-
parts.emplace_back(i);
30-
return *this;
35+
SwiftMangledName& operator<<(UntypedTrapLabel label) &;
36+
SwiftMangledName& operator<<(unsigned i) &;
37+
38+
template <typename Tag>
39+
SwiftMangledName& operator<<(TrapLabel<Tag> label) & {
40+
return operator<<(static_cast<UntypedTrapLabel>(label));
3141
}
3242

3343
// streaming string-like stuff will add a new part it only if strictly required, otherwise it will
3444
// append to the last part if it is a string
3545
template <typename T>
36-
SwiftMangledName& operator<<(T&& arg) {
37-
if (parts.empty() || !std::holds_alternative<std::string>(parts.back())) {
38-
parts.emplace_back("");
39-
}
40-
std::get<std::string>(parts.back()) += std::forward<T>(arg);
46+
SwiftMangledName& operator<<(T&& arg) & {
47+
value += arg;
4148
return *this;
4249
}
50+
51+
template <typename T>
52+
SwiftMangledName&& operator<<(T&& arg) && {
53+
return std::move(operator<<(std::forward<T>(arg)));
54+
}
55+
56+
private:
57+
std::string value;
4358
};
4459

4560
} // namespace codeql

0 commit comments

Comments
 (0)