Skip to content

Commit 5beeb63

Browse files
authored
Junk detection: read compilation database flags from bitcode (#663)
* Junk detection: read compilation database flags from bitcode * tests-lit: enable conditional flag that toggles LLVM >= 8 * Junk detection: read compilation database flags from bitcode (code review)
1 parent ada21bd commit 5beeb63

File tree

17 files changed

+241
-35
lines changed

17 files changed

+241
-35
lines changed

include/mull/BitcodeMetadataReader.h

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#pragma once
2+
3+
#include <map>
4+
#include <memory>
5+
#include <vector>
6+
7+
namespace mull {
8+
class Bitcode;
9+
10+
class BitcodeMetadataReader {
11+
public:
12+
std::map<std::string, std::string>
13+
getCompilationDatabase(std::vector<std::unique_ptr<mull::Bitcode>> &bitcode);
14+
};
15+
16+
} // namespace mull

include/mull/JunkDetection/CXX/ASTStorage.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@ class ThreadSafeASTUnit {
4040
class ASTStorage {
4141
public:
4242
ASTStorage(Diagnostics &diagnostics, const std::string &cxxCompilationDatabasePath,
43-
const std::string &cxxCompilationFlags);
43+
const std::string &cxxCompilationFlags,
44+
const std::map<std::string, std::string> &bitcodeCompilationFlags);
4445

4546
ThreadSafeASTUnit *findAST(const MutationPoint *point);
4647

4748
clang::Expr *getMutantASTNode(MutationPoint *mutationPoint);
48-
void setMutantASTNode(MutationPoint *mutationPoint,
49-
clang::Expr *mutantExpression);
49+
void setMutantASTNode(MutationPoint *mutationPoint, clang::Expr *mutantExpression);
5050

5151
private:
5252
Diagnostics &diagnostics;

include/mull/JunkDetection/CXX/CompilationDatabase.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,26 @@ class CompilationDatabase {
3131
private:
3232
std::string flags;
3333
};
34+
class BitcodeFlags {
35+
public:
36+
explicit BitcodeFlags(std::map<std::string, std::string> bitcodeFlags)
37+
: bitcodeFlags(std::move(bitcodeFlags)) {}
38+
const std::map<std::string, std::string> &getFlags() const {
39+
return bitcodeFlags;
40+
}
41+
private:
42+
std::map<std::string, std::string> bitcodeFlags;
43+
};
3444

3545
public:
36-
CompilationDatabase(Diagnostics &diagnostics, Path path, Flags flags);
46+
CompilationDatabase(Diagnostics &diagnostics, Path path, Flags flags, BitcodeFlags bitcodeFlags);
3747

3848
const std::vector<std::string> &compilationFlagsForFile(const std::string &filepath) const;
3949

4050
private:
4151
const std::vector<std::string> extraFlags;
4252
const std::map<std::string, std::vector<std::string>> database;
53+
const std::map<std::string, std::vector<std::string>> bitcodeFlags;
4354
};
4455

4556
} // namespace mull

include/mull/Path.h

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#pragma once
2+
3+
#include <string>
4+
5+
namespace mull {
6+
std::string absoluteFilePath(const std::string &directory, const std::string &filePath);
7+
}

lib/BitcodeMetadataReader.cpp

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include "mull/BitcodeMetadataReader.h"
2+
3+
#include "mull/Bitcode.h"
4+
#include "mull/Path.h"
5+
6+
#include <llvm/IR/DebugInfoMetadata.h>
7+
#include <llvm/IR/Module.h>
8+
9+
std::map<std::string, std::string> mull::BitcodeMetadataReader::getCompilationDatabase(
10+
std::vector<std::unique_ptr<mull::Bitcode>> &bitcode) {
11+
std::map<std::string, std::string> bitcodeCompilationFlags;
12+
if (bitcode.empty()) {
13+
return bitcodeCompilationFlags;
14+
}
15+
for (auto &bitcodeModule: bitcode) {
16+
llvm::Module *module = bitcodeModule->getModule();
17+
18+
for (llvm::DICompileUnit *unit : module->debug_compile_units()) {
19+
llvm::StringRef directory = unit->getDirectory();
20+
llvm::StringRef fileName = unit->getFilename();
21+
std::string unitFullPath = absoluteFilePath(directory, fileName);
22+
23+
llvm::StringRef unitFlags = unit->getFlags();
24+
25+
if (!unitFlags.empty()) {
26+
bitcodeCompilationFlags[unitFullPath] = unitFlags.str();
27+
}
28+
}
29+
}
30+
return bitcodeCompilationFlags;
31+
}

lib/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ set(mull_sources
55
Driver.cpp
66
Sandbox/ProcessSandbox.cpp
77
BitcodeLoader.cpp
8+
BitcodeMetadataReader.cpp
89
MutationsFinder.cpp
910

1011
Instrumentation/DynamicCallTree.cpp
@@ -72,6 +73,8 @@ set(mull_sources
7273
Parallelization/Tasks/FunctionFilterTask.cpp
7374
Parallelization/Tasks/InstructionSelectionTask.cpp
7475

76+
Path.cpp
77+
7578
Config/ConfigurationOptions.cpp
7679
Config/Configuration.cpp
7780
TestFrameworks/TestFramework.cpp

lib/JunkDetection/CXX/ASTStorage.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,12 @@ clang::Decl *ThreadSafeASTUnit::getDecl(clang::SourceLocation &location) {
168168
}
169169

170170
ASTStorage::ASTStorage(Diagnostics &diagnostics, const std::string &cxxCompilationDatabasePath,
171-
const std::string &cxxCompilationFlags)
171+
const std::string &cxxCompilationFlags,
172+
const std::map<std::string, std::string> &bitcodeCompilationFlags)
172173
: diagnostics(diagnostics),
173174
compilationDatabase(diagnostics, CompilationDatabase::Path(cxxCompilationDatabasePath),
174-
CompilationDatabase::Flags(cxxCompilationFlags)) {}
175+
CompilationDatabase::Flags(cxxCompilationFlags),
176+
CompilationDatabase::BitcodeFlags(bitcodeCompilationFlags)) {}
175177

176178
ThreadSafeASTUnit *ASTStorage::findAST(const MutationPoint *point) {
177179
assert(point);

lib/JunkDetection/CXX/CompilationDatabase.cpp

+53-6
Original file line numberDiff line numberDiff line change
@@ -107,28 +107,75 @@ loadDatabaseFromFile(Diagnostics &diagnostics, const std::string &path,
107107
return database;
108108
}
109109

110+
static std::map<std::string, std::vector<std::string>>
111+
createBitcodeFlags(Diagnostics &diagnostics, CompilationDatabase::BitcodeFlags &bitcodeFlags,
112+
const std::vector<std::string> &extraFlags) {
113+
const std::map<std::string, std::string> &bitcodeFlagsMap = bitcodeFlags.getFlags();
114+
115+
std::map<std::string, std::vector<std::string>> mergedBitcodeFlags;
116+
117+
for (auto const &bitcodeFileEntry : bitcodeFlagsMap) {
118+
std::vector<std::string> fileFlagsArray = flagsFromString(bitcodeFileEntry.second);
119+
120+
fileFlagsArray = filterFlags(fileFlagsArray, true);
121+
122+
/// Remove file name from the list of flags
123+
fileFlagsArray.erase(
124+
std::remove(fileFlagsArray.begin(), fileFlagsArray.end(), bitcodeFileEntry.first),
125+
fileFlagsArray.end());
126+
127+
for (const auto &extraFlag : extraFlags) {
128+
fileFlagsArray.push_back(extraFlag);
129+
}
130+
131+
mergedBitcodeFlags[bitcodeFileEntry.first] = fileFlagsArray;
132+
}
133+
134+
return mergedBitcodeFlags;
135+
}
136+
110137
CompilationDatabase::CompilationDatabase(Diagnostics &diagnostics, CompilationDatabase::Path path,
111-
CompilationDatabase::Flags flags)
138+
CompilationDatabase::Flags flags,
139+
CompilationDatabase::BitcodeFlags bitcodeFlags)
112140
: extraFlags(filterFlags(flagsFromString(flags.getFlags()), false)),
113-
database(loadDatabaseFromFile(diagnostics, path.getPath(), extraFlags)) {}
141+
database(loadDatabaseFromFile(diagnostics, path.getPath(), extraFlags)),
142+
bitcodeFlags(createBitcodeFlags(diagnostics, bitcodeFlags, extraFlags)) {}
114143

115144
const std::vector<std::string> &
116145
CompilationDatabase::compilationFlagsForFile(const std::string &filepath) const {
117-
if (database.empty()) {
146+
if (database.empty() && bitcodeFlags.empty()) {
118147
return extraFlags;
119148
}
120149

121-
auto it = database.find(filepath);
122-
if (it != database.end()) {
150+
/// Look in bitcode flags
151+
auto it = bitcodeFlags.find(filepath);
152+
if (it != bitcodeFlags.end()) {
123153
return it->second;
124154
}
125155
auto filename = llvm::sys::path::filename(filepath);
156+
it = bitcodeFlags.find(filename);
157+
if (it != bitcodeFlags.end()) {
158+
return it->second;
159+
}
160+
161+
llvm::SmallString<128> dotlessPath(filepath);
162+
llvm::sys::path::remove_dots(dotlessPath, true);
163+
it = bitcodeFlags.find(dotlessPath.str());
164+
if (it != bitcodeFlags.end()) {
165+
return it->second;
166+
}
167+
168+
/// Look in compilation database
169+
it = database.find(filepath);
170+
if (it != database.end()) {
171+
return it->second;
172+
}
173+
filename = llvm::sys::path::filename(filepath);
126174
it = database.find(filename);
127175
if (it != database.end()) {
128176
return it->second;
129177
}
130178

131-
llvm::SmallString<128> dotlessPath(filepath);
132179
llvm::sys::path::remove_dots(dotlessPath, true);
133180
it = database.find(dotlessPath.str());
134181
if (it != database.end()) {

lib/Path.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include "mull/Path.h"
2+
3+
#include <llvm/Support/Path.h>
4+
5+
std::string mull::absoluteFilePath(const std::string &directory, const std::string &filePath) {
6+
if (!filePath.empty() && !llvm::sys::path::is_absolute(filePath)) {
7+
return directory + llvm::sys::path::get_separator().str() + filePath;
8+
}
9+
return filePath;
10+
}

lib/SourceLocation.cpp

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "mull/SourceLocation.h"
22

3+
#import "mull/Path.h"
4+
35
#include <string>
46
#include <utility>
57

@@ -8,17 +10,9 @@
810
#include <llvm/IR/DebugLoc.h>
911
#include <llvm/IR/Function.h>
1012
#include <llvm/IR/Instruction.h>
11-
#include <llvm/Support/Path.h>
1213

1314
namespace mull {
1415

15-
std::string absoluteFilePath(const std::string &directory, const std::string &filePath) {
16-
if (!filePath.empty() && !llvm::sys::path::is_absolute(filePath)) {
17-
return directory + llvm::sys::path::get_separator().str() + filePath;
18-
}
19-
return filePath;
20-
}
21-
2216
SourceLocation::SourceLocation(std::string unitDirectory, std::string unitFilePath,
2317
std::string directory, std::string filePath, int line, int column)
2418
: unitDirectory(std::move(unitDirectory)), unitFilePath(std::move(unitFilePath)),

tests-lit/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ set(LIT_EXEC lit)
33
set(FILECHECK_EXEC filecheck)
44

55
set(LIT_COMMAND
6+
LLVM_VERSION_MAJOR=${LLVM_VERSION_MAJOR}
67
CURRENT_DIR=${CMAKE_CURRENT_SOURCE_DIR}
78
MULL_EXEC=$<TARGET_FILE:mull-cxx>
89
CLANG_EXEC=${CLANG_EXEC}

tests-lit/lit.cfg

+9
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,19 @@ current_dir = os.environ.get('CURRENT_DIR', '')
99
clang_exec = os.environ.get('CLANG_EXEC', '')
1010
mull_exec = os.environ.get('MULL_EXEC', '')
1111
filecheck_exec = os.environ.get('FILECHECK_EXEC', '')
12+
llvm_major_version = os.environ.get('LLVM_VERSION_MAJOR', '')
13+
assert llvm_major_version
1214

1315
config.substitutions.append(('%CURRENT_DIR', current_dir))
1416
config.substitutions.append(('%CLANG_EXEC', clang_exec))
1517
config.substitutions.append(('%MULL_EXEC', mull_exec))
1618
config.substitutions.append(('%FILECHECK_EXEC', filecheck_exec))
1719

1820
config.suffixes = ['.cpp']
21+
22+
class MullConfig():
23+
llvm_8_or_higher = False
24+
def __init__(self, llvm_8_or_higher):
25+
self.llvm_8_or_higher = llvm_8_or_higher
26+
27+
config.mull = MullConfig(int(llvm_major_version) >= 8)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
if not config.mull.llvm_8_or_higher:
2+
config.unsupported = True
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#ifndef FLAG
2+
#error "FLAG is not defined"
3+
#endif
4+
5+
int sum(int a, int b) {
6+
return a + b;
7+
}
8+
9+
int main() {
10+
return sum(-2, 2);
11+
}
12+
13+
/**
14+
; RUN: cd / && %CLANG_EXEC -fembed-bitcode -g -DFLAG=1 %s -o %s.exe
15+
; RUN: cd %CURRENT_DIR
16+
; RUN: (unset TERM; %MULL_EXEC -test-framework CustomTest -mutators=all -reporters=IDE -ide-reporter-show-killed %s.exe 2>&1; test $? = 0) | %FILECHECK_EXEC %s --strict-whitespace --match-full-lines --check-prefix=WITHOUT-RECORD-COMMAND-LINE
17+
; WITHOUT-RECORD-COMMAND-LINE-NOT:Found compilation flags in the input bitcode
18+
; WITHOUT-RECORD-COMMAND-LINE:{{^.*}}sample.cpp:5:13: warning: Survived: Remove Void Call: removed llvm.dbg.declare [remove_void_function_mutator]{{$}}
19+
20+
; RUN: cd / && %CLANG_EXEC -fembed-bitcode -g -DFLAG=1 -grecord-command-line %s -o %s.exe
21+
; RUN: cd %CURRENT_DIR
22+
; RUN: (unset TERM; %MULL_EXEC -test-framework CustomTest -mutators=all -reporters=IDE -ide-reporter-show-killed %s.exe 2>&1; test $? = 0) | %FILECHECK_EXEC %s --strict-whitespace --match-full-lines --check-prefix=WITH-RECORD-COMMAND-LINE
23+
; WITH-RECORD-COMMAND-LINE:[info] Found compilation flags in the input bitcode
24+
; WITH-RECORD-COMMAND-LINE-NOT:{{^.*[Ee]rror.*$}}
25+
**/
26+

tests/JunkDetection/CXXJunkDetectorTests.cpp

+8-4
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ TEST_P(CXXJunkDetectorTest, detectJunk) {
5555
std::copy(mutants.begin(), mutants.end(), std::back_inserter(points));
5656
}
5757

58-
ASTStorage astStorage(diagnostics, "", "");
58+
ASTStorage astStorage(diagnostics, "", "", {});
59+
5960
CXXJunkDetector detector(astStorage);
6061

6162
std::vector<MutationPoint *> nonJunkMutationPoints;
@@ -199,7 +200,8 @@ TEST(CXXJunkDetector, compdb_absolute_paths) {
199200
std::string cxxCompilationDatabasePath =
200201
fixtures::junk_detection_compdb_absolute_compile_commands_json_path();
201202

202-
ASTStorage astStorage(diagnostics, cxxCompilationDatabasePath, "");
203+
ASTStorage astStorage(diagnostics, cxxCompilationDatabasePath, "", {});
204+
203205
CXXJunkDetector detector(astStorage);
204206

205207
std::vector<MutationPoint *> nonJunkMutationPoints;
@@ -239,7 +241,8 @@ TEST(CXXJunkDetector, DISABLED_compdb_relative_paths) {
239241
std::string cxxCompilationDatabasePath =
240242
fixtures::junk_detection_compdb_relative_compile_commands_json_path();
241243

242-
ASTStorage astStorage(diagnostics, cxxCompilationDatabasePath, "");
244+
ASTStorage astStorage(diagnostics, cxxCompilationDatabasePath, "", {});
245+
243246
CXXJunkDetector detector(astStorage);
244247

245248
std::vector<MutationPoint *> nonJunkMutationPoints;
@@ -280,7 +283,8 @@ TEST(CXXJunkDetector, no_compdb) {
280283
std::string cxxCompilationFlags =
281284
std::string("-I ") + fixtures::junk_detection_compdb_include__path();
282285

283-
ASTStorage astStorage(diagnostics, "", cxxCompilationFlags);
286+
ASTStorage astStorage(diagnostics, "", cxxCompilationFlags, {});
287+
284288
CXXJunkDetector detector(astStorage);
285289

286290
std::vector<MutationPoint *> nonJunkMutationPoints;

0 commit comments

Comments
 (0)