Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Junk detection: read compilation database flags from bitcode #663

Merged
merged 3 commits into from
Mar 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions include/mull/BitcodeMetadataReader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include <map>
#include <memory>
#include <vector>

namespace mull {
class Bitcode;

class BitcodeMetadataReader {
public:
std::map<std::string, std::string>
getCompilationDatabase(std::vector<std::unique_ptr<mull::Bitcode>> &bitcode);
};

} // namespace mull
6 changes: 3 additions & 3 deletions include/mull/JunkDetection/CXX/ASTStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ class ThreadSafeASTUnit {
class ASTStorage {
public:
ASTStorage(Diagnostics &diagnostics, const std::string &cxxCompilationDatabasePath,
const std::string &cxxCompilationFlags);
const std::string &cxxCompilationFlags,
const std::map<std::string, std::string> &bitcodeCompilationFlags);

ThreadSafeASTUnit *findAST(const MutationPoint *point);

clang::Expr *getMutantASTNode(MutationPoint *mutationPoint);
void setMutantASTNode(MutationPoint *mutationPoint,
clang::Expr *mutantExpression);
void setMutantASTNode(MutationPoint *mutationPoint, clang::Expr *mutantExpression);

private:
Diagnostics &diagnostics;
Expand Down
13 changes: 12 additions & 1 deletion include/mull/JunkDetection/CXX/CompilationDatabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,26 @@ class CompilationDatabase {
private:
std::string flags;
};
class BitcodeFlags {
public:
explicit BitcodeFlags(std::map<std::string, std::string> bitcodeFlags)
: bitcodeFlags(std::move(bitcodeFlags)) {}
const std::map<std::string, std::string> &getFlags() const {
return bitcodeFlags;
}
private:
std::map<std::string, std::string> bitcodeFlags;
};

public:
CompilationDatabase(Diagnostics &diagnostics, Path path, Flags flags);
CompilationDatabase(Diagnostics &diagnostics, Path path, Flags flags, BitcodeFlags bitcodeFlags);

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

private:
const std::vector<std::string> extraFlags;
const std::map<std::string, std::vector<std::string>> database;
const std::map<std::string, std::vector<std::string>> bitcodeFlags;
};

} // namespace mull
7 changes: 7 additions & 0 deletions include/mull/Path.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

#include <string>

namespace mull {
std::string absoluteFilePath(const std::string &directory, const std::string &filePath);
}
31 changes: 31 additions & 0 deletions lib/BitcodeMetadataReader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "mull/BitcodeMetadataReader.h"

#include "mull/Bitcode.h"
#include "mull/Path.h"

#include <llvm/IR/DebugInfoMetadata.h>
#include <llvm/IR/Module.h>

std::map<std::string, std::string> mull::BitcodeMetadataReader::getCompilationDatabase(
std::vector<std::unique_ptr<mull::Bitcode>> &bitcode) {
std::map<std::string, std::string> bitcodeCompilationFlags;
if (bitcode.empty()) {
return bitcodeCompilationFlags;
}
for (auto &bitcodeModule: bitcode) {
llvm::Module *module = bitcodeModule->getModule();

for (llvm::DICompileUnit *unit : module->debug_compile_units()) {
llvm::StringRef directory = unit->getDirectory();
llvm::StringRef fileName = unit->getFilename();
std::string unitFullPath = absoluteFilePath(directory, fileName);

llvm::StringRef unitFlags = unit->getFlags();

if (!unitFlags.empty()) {
bitcodeCompilationFlags[unitFullPath] = unitFlags.str();
}
}
}
return bitcodeCompilationFlags;
}
3 changes: 3 additions & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ set(mull_sources
Driver.cpp
Sandbox/ProcessSandbox.cpp
BitcodeLoader.cpp
BitcodeMetadataReader.cpp
MutationsFinder.cpp

Instrumentation/DynamicCallTree.cpp
Expand Down Expand Up @@ -72,6 +73,8 @@ set(mull_sources
Parallelization/Tasks/FunctionFilterTask.cpp
Parallelization/Tasks/InstructionSelectionTask.cpp

Path.cpp

Config/ConfigurationOptions.cpp
Config/Configuration.cpp
TestFrameworks/TestFramework.cpp
Expand Down
6 changes: 4 additions & 2 deletions lib/JunkDetection/CXX/ASTStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,12 @@ clang::Decl *ThreadSafeASTUnit::getDecl(clang::SourceLocation &location) {
}

ASTStorage::ASTStorage(Diagnostics &diagnostics, const std::string &cxxCompilationDatabasePath,
const std::string &cxxCompilationFlags)
const std::string &cxxCompilationFlags,
const std::map<std::string, std::string> &bitcodeCompilationFlags)
: diagnostics(diagnostics),
compilationDatabase(diagnostics, CompilationDatabase::Path(cxxCompilationDatabasePath),
CompilationDatabase::Flags(cxxCompilationFlags)) {}
CompilationDatabase::Flags(cxxCompilationFlags),
CompilationDatabase::BitcodeFlags(bitcodeCompilationFlags)) {}

ThreadSafeASTUnit *ASTStorage::findAST(const MutationPoint *point) {
assert(point);
Expand Down
59 changes: 53 additions & 6 deletions lib/JunkDetection/CXX/CompilationDatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,28 +107,75 @@ loadDatabaseFromFile(Diagnostics &diagnostics, const std::string &path,
return database;
}

static std::map<std::string, std::vector<std::string>>
createBitcodeFlags(Diagnostics &diagnostics, CompilationDatabase::BitcodeFlags &bitcodeFlags,
const std::vector<std::string> &extraFlags) {
const std::map<std::string, std::string> &bitcodeFlagsMap = bitcodeFlags.getFlags();

std::map<std::string, std::vector<std::string>> mergedBitcodeFlags;

for (auto const &bitcodeFileEntry : bitcodeFlagsMap) {
std::vector<std::string> fileFlagsArray = flagsFromString(bitcodeFileEntry.second);

fileFlagsArray = filterFlags(fileFlagsArray, true);

/// Remove file name from the list of flags
fileFlagsArray.erase(
std::remove(fileFlagsArray.begin(), fileFlagsArray.end(), bitcodeFileEntry.first),
fileFlagsArray.end());

for (const auto &extraFlag : extraFlags) {
fileFlagsArray.push_back(extraFlag);
}

mergedBitcodeFlags[bitcodeFileEntry.first] = fileFlagsArray;
}

return mergedBitcodeFlags;
}

CompilationDatabase::CompilationDatabase(Diagnostics &diagnostics, CompilationDatabase::Path path,
CompilationDatabase::Flags flags)
CompilationDatabase::Flags flags,
CompilationDatabase::BitcodeFlags bitcodeFlags)
: extraFlags(filterFlags(flagsFromString(flags.getFlags()), false)),
database(loadDatabaseFromFile(diagnostics, path.getPath(), extraFlags)) {}
database(loadDatabaseFromFile(diagnostics, path.getPath(), extraFlags)),
bitcodeFlags(createBitcodeFlags(diagnostics, bitcodeFlags, extraFlags)) {}

const std::vector<std::string> &
CompilationDatabase::compilationFlagsForFile(const std::string &filepath) const {
if (database.empty()) {
if (database.empty() && bitcodeFlags.empty()) {
return extraFlags;
}

auto it = database.find(filepath);
if (it != database.end()) {
/// Look in bitcode flags
auto it = bitcodeFlags.find(filepath);
if (it != bitcodeFlags.end()) {
return it->second;
}
auto filename = llvm::sys::path::filename(filepath);
it = bitcodeFlags.find(filename);
if (it != bitcodeFlags.end()) {
return it->second;
}

llvm::SmallString<128> dotlessPath(filepath);
llvm::sys::path::remove_dots(dotlessPath, true);
it = bitcodeFlags.find(dotlessPath.str());
if (it != bitcodeFlags.end()) {
return it->second;
}

/// Look in compilation database
it = database.find(filepath);
if (it != database.end()) {
return it->second;
}
filename = llvm::sys::path::filename(filepath);
it = database.find(filename);
if (it != database.end()) {
return it->second;
}

llvm::SmallString<128> dotlessPath(filepath);
llvm::sys::path::remove_dots(dotlessPath, true);
it = database.find(dotlessPath.str());
if (it != database.end()) {
Expand Down
10 changes: 10 additions & 0 deletions lib/Path.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include "mull/Path.h"

#include <llvm/Support/Path.h>

std::string mull::absoluteFilePath(const std::string &directory, const std::string &filePath) {
if (!filePath.empty() && !llvm::sys::path::is_absolute(filePath)) {
return directory + llvm::sys::path::get_separator().str() + filePath;
}
return filePath;
}
10 changes: 2 additions & 8 deletions lib/SourceLocation.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "mull/SourceLocation.h"

#import "mull/Path.h"

#include <string>
#include <utility>

Expand All @@ -8,17 +10,9 @@
#include <llvm/IR/DebugLoc.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Instruction.h>
#include <llvm/Support/Path.h>

namespace mull {

std::string absoluteFilePath(const std::string &directory, const std::string &filePath) {
if (!filePath.empty() && !llvm::sys::path::is_absolute(filePath)) {
return directory + llvm::sys::path::get_separator().str() + filePath;
}
return filePath;
}

SourceLocation::SourceLocation(std::string unitDirectory, std::string unitFilePath,
std::string directory, std::string filePath, int line, int column)
: unitDirectory(std::move(unitDirectory)), unitFilePath(std::move(unitFilePath)),
Expand Down
1 change: 1 addition & 0 deletions tests-lit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ set(LIT_EXEC lit)
set(FILECHECK_EXEC filecheck)

set(LIT_COMMAND
LLVM_VERSION_MAJOR=${LLVM_VERSION_MAJOR}
CURRENT_DIR=${CMAKE_CURRENT_SOURCE_DIR}
MULL_EXEC=$<TARGET_FILE:mull-cxx>
CLANG_EXEC=${CLANG_EXEC}
Expand Down
9 changes: 9 additions & 0 deletions tests-lit/lit.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,19 @@ current_dir = os.environ.get('CURRENT_DIR', '')
clang_exec = os.environ.get('CLANG_EXEC', '')
mull_exec = os.environ.get('MULL_EXEC', '')
filecheck_exec = os.environ.get('FILECHECK_EXEC', '')
llvm_major_version = os.environ.get('LLVM_VERSION_MAJOR', '')
assert llvm_major_version

config.substitutions.append(('%CURRENT_DIR', current_dir))
config.substitutions.append(('%CLANG_EXEC', clang_exec))
config.substitutions.append(('%MULL_EXEC', mull_exec))
config.substitutions.append(('%FILECHECK_EXEC', filecheck_exec))

config.suffixes = ['.cpp']

class MullConfig():
llvm_8_or_higher = False
def __init__(self, llvm_8_or_higher):
self.llvm_8_or_higher = llvm_8_or_higher

config.mull = MullConfig(int(llvm_major_version) >= 8)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
if not config.mull.llvm_8_or_higher:
config.unsupported = True
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ifndef FLAG
#error "FLAG is not defined"
#endif

int sum(int a, int b) {
return a + b;
}

int main() {
return sum(-2, 2);
}

/**
; RUN: cd / && %CLANG_EXEC -fembed-bitcode -g -DFLAG=1 %s -o %s.exe
; RUN: cd %CURRENT_DIR
; 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
; WITHOUT-RECORD-COMMAND-LINE-NOT:Found compilation flags in the input bitcode
; WITHOUT-RECORD-COMMAND-LINE:{{^.*}}sample.cpp:5:13: warning: Survived: Remove Void Call: removed llvm.dbg.declare [remove_void_function_mutator]{{$}}

; RUN: cd / && %CLANG_EXEC -fembed-bitcode -g -DFLAG=1 -grecord-command-line %s -o %s.exe
; RUN: cd %CURRENT_DIR
; 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
; WITH-RECORD-COMMAND-LINE:[info] Found compilation flags in the input bitcode
; WITH-RECORD-COMMAND-LINE-NOT:{{^.*[Ee]rror.*$}}
**/

12 changes: 8 additions & 4 deletions tests/JunkDetection/CXXJunkDetectorTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ TEST_P(CXXJunkDetectorTest, detectJunk) {
std::copy(mutants.begin(), mutants.end(), std::back_inserter(points));
}

ASTStorage astStorage(diagnostics, "", "");
ASTStorage astStorage(diagnostics, "", "", {});

CXXJunkDetector detector(astStorage);

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

ASTStorage astStorage(diagnostics, cxxCompilationDatabasePath, "");
ASTStorage astStorage(diagnostics, cxxCompilationDatabasePath, "", {});

CXXJunkDetector detector(astStorage);

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

ASTStorage astStorage(diagnostics, cxxCompilationDatabasePath, "");
ASTStorage astStorage(diagnostics, cxxCompilationDatabasePath, "", {});

CXXJunkDetector detector(astStorage);

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

ASTStorage astStorage(diagnostics, "", cxxCompilationFlags);
ASTStorage astStorage(diagnostics, "", cxxCompilationFlags, {});

CXXJunkDetector detector(astStorage);

std::vector<MutationPoint *> nonJunkMutationPoints;
Expand Down
Loading