forked from OSchip/llvm-project
Adds support for auto-detection of compilation databases
from a source file and changes clang-check to make use of this. This makes clang-check just work on in-tree builds, and allows easy setup via a symlink per source directory to make clang-check work without any extra configuration. llvm-svn: 159990
This commit is contained in:
parent
1dc44dcedd
commit
65fd0e1fd3
|
@ -81,6 +81,13 @@ public:
|
|||
static CompilationDatabase *loadFromDirectory(StringRef BuildDirectory,
|
||||
std::string &ErrorMessage);
|
||||
|
||||
/// \brief Tries to detect a compilation database location and load it.
|
||||
///
|
||||
/// Looks for a compilation database in all parent paths by calling
|
||||
/// loadFromDirectory.
|
||||
static CompilationDatabase *autoDetectFromSource(StringRef SourceFile,
|
||||
std::string &ErrorMessage);
|
||||
|
||||
/// \brief Returns all compile commands in which the specified file was
|
||||
/// compiled.
|
||||
///
|
||||
|
@ -215,4 +222,3 @@ private:
|
|||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLING_COMPILATION_DATABASE_H
|
||||
|
||||
|
|
|
@ -232,6 +232,22 @@ FrontendActionFactory *newFrontendActionFactory(FactoryT *ConsumerFactory) {
|
|||
return new FrontendActionFactoryAdapter(ConsumerFactory);
|
||||
}
|
||||
|
||||
/// \brief Returns the absolute path of \c File, by prepending it with
|
||||
/// the current directory if \c File is not absolute.
|
||||
///
|
||||
/// Otherwise returns \c File.
|
||||
/// If 'File' starts with "./", the returned path will not contain the "./".
|
||||
/// Otherwise, the returned path will contain the literal path-concatenation of
|
||||
/// the current directory and \c File.
|
||||
///
|
||||
/// The difference to llvm::sys::fs::make_absolute is that we prefer
|
||||
/// ::getenv("PWD") if available.
|
||||
/// FIXME: Make this functionality available from llvm::sys::fs and delete
|
||||
/// this function.
|
||||
///
|
||||
/// \param File Either an absolute or relative path.
|
||||
std::string getAbsolutePath(StringRef File);
|
||||
|
||||
} // end namespace tooling
|
||||
} // end namespace clang
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Tooling/CompilationDatabase.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/YAMLParser.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
|
@ -121,6 +122,23 @@ CompilationDatabase::loadFromDirectory(StringRef BuildDirectory,
|
|||
return Database.take();
|
||||
}
|
||||
|
||||
CompilationDatabase *
|
||||
CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
|
||||
std::string &ErrorMessage) {
|
||||
llvm::SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile));
|
||||
StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
|
||||
while (!Directory.empty()) {
|
||||
std::string LoadErrorMessage;
|
||||
if (CompilationDatabase *DB = loadFromDirectory(Directory,
|
||||
LoadErrorMessage))
|
||||
return DB;
|
||||
Directory = llvm::sys::path::parent_path(Directory);
|
||||
}
|
||||
ErrorMessage = ("Could not auto-detect compilation database for file \"" +
|
||||
SourceFile + "\"").str();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FixedCompilationDatabase *
|
||||
FixedCompilationDatabase::loadFromCommandLine(int &Argc,
|
||||
const char **Argv,
|
||||
|
@ -283,4 +301,3 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
|
|||
|
||||
} // end namespace tooling
|
||||
} // end namespace clang
|
||||
|
||||
|
|
|
@ -115,20 +115,13 @@ bool runToolOnCode(clang::FrontendAction *ToolAction, const Twine &Code,
|
|||
return Invocation.run();
|
||||
}
|
||||
|
||||
/// \brief Returns the absolute path of 'File', by prepending it with
|
||||
/// 'BaseDirectory' if 'File' is not absolute.
|
||||
///
|
||||
/// Otherwise returns 'File'.
|
||||
/// If 'File' starts with "./", the returned path will not contain the "./".
|
||||
/// Otherwise, the returned path will contain the literal path-concatenation of
|
||||
/// 'BaseDirectory' and 'File'.
|
||||
///
|
||||
/// \param File Either an absolute or relative path.
|
||||
/// \param BaseDirectory An absolute path.
|
||||
static std::string getAbsolutePath(
|
||||
StringRef File, StringRef BaseDirectory) {
|
||||
std::string getAbsolutePath(StringRef File) {
|
||||
llvm::SmallString<1024> BaseDirectory;
|
||||
if (const char *PWD = ::getenv("PWD"))
|
||||
BaseDirectory = PWD;
|
||||
else
|
||||
llvm::sys::fs::current_path(BaseDirectory);
|
||||
SmallString<1024> PathStorage;
|
||||
assert(llvm::sys::path::is_absolute(BaseDirectory));
|
||||
if (llvm::sys::path::is_absolute(File)) {
|
||||
llvm::sys::path::native(File, PathStorage);
|
||||
return PathStorage.str();
|
||||
|
@ -240,14 +233,8 @@ ClangTool::ClangTool(const CompilationDatabase &Compilations,
|
|||
ArrayRef<std::string> SourcePaths)
|
||||
: Files((FileSystemOptions())),
|
||||
ArgsAdjuster(new ClangSyntaxOnlyAdjuster()) {
|
||||
llvm::SmallString<1024> BaseDirectory;
|
||||
if (const char *PWD = ::getenv("PWD"))
|
||||
BaseDirectory = PWD;
|
||||
else
|
||||
llvm::sys::fs::current_path(BaseDirectory);
|
||||
for (unsigned I = 0, E = SourcePaths.size(); I != E; ++I) {
|
||||
llvm::SmallString<1024> File(getAbsolutePath(
|
||||
SourcePaths[I], BaseDirectory));
|
||||
llvm::SmallString<1024> File(getAbsolutePath(SourcePaths[I]));
|
||||
|
||||
std::vector<CompileCommand> CompileCommandsForFile =
|
||||
Compilations.getCompileCommands(File.str());
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
// RUN: rm -rf %t
|
||||
// RUN: mkdir -p %t/abc/def/ijk/qwe
|
||||
// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %t/abc/def/ijk/qwe/test.cpp\",\"file\":\"%t/abc/def/ijk/qwe/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
|
||||
// RUN: cp "%s" "%t/abc/def/ijk/qwe/test.cpp"
|
||||
// RUN: PWD="%t/abc/def" clang-check "ijk/qwe/test.cpp" 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: C++ requires
|
||||
invalid;
|
|
@ -0,0 +1,8 @@
|
|||
// RUN: rm -rf %t
|
||||
// RUN: mkdir -p %t/abc/def/ijk/qwe
|
||||
// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %t/abc/def/ijk/qwe/test.cpp\",\"file\":\"%t/abc/def/ijk/qwe/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
|
||||
// RUN: cp "%s" "%t/abc/def/ijk/qwe/test.cpp"
|
||||
// RUN: clang-check "%t/abc/def/ijk/qwe/test.cpp" 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: C++ requires
|
||||
invalid;
|
|
@ -0,0 +1,8 @@
|
|||
// RUN: rm -rf %t
|
||||
// RUN: mkdir %t
|
||||
// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %t/test.cpp\",\"file\":\"%t/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
|
||||
// RUN: cp "%s" "%t/test.cpp"
|
||||
// RUN: clang-check "%t/test.cpp" 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: C++ requires
|
||||
invalid;
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: clang-check . "%s" -- -c 2>&1 | FileCheck %s
|
||||
// RUN: clang-check "%s" -- -c 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: C++ requires
|
||||
invalid;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// Add a path that doesn't exist as argv[0] for the compile command line:
|
||||
// RUN: echo '[{"directory":".","command":"/random/tool -c %t/test.cpp","file":"%t/test.cpp"}]' | sed -e 's/\\/\//g' > %t/compile_commands.json
|
||||
// RUN: cp "%s" "%t/test.cpp"
|
||||
// RUN: clang-check "%t" "%t/test.cpp" 2>&1|FileCheck %s
|
||||
// RUN: clang-check -p "%t" "%t/test.cpp" 2>&1|FileCheck %s
|
||||
// FIXME: Make the above easier.
|
||||
|
||||
#include <stddef.h>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
// RUN: echo "[{\"directory\":\"%t\",\"command\":\"clang -c test.cpp -I.\",\"file\":\"%t/test.cpp\"}]" | sed -e 's/\\/\//g' > %t/compile_commands.json
|
||||
// RUN: cp "%s" "%t/test.cpp"
|
||||
// RUN: touch "%t/clang-check-test.h"
|
||||
// RUN: clang-check "%t" "%t/test.cpp" 2>&1|FileCheck %s
|
||||
// RUN: clang-check -p "%t" "%t/test.cpp" 2>&1|FileCheck %s
|
||||
// FIXME: Make the above easier.
|
||||
|
||||
#include "clang-check-test.h"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// RUN: mkdir %t
|
||||
// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %t/test.cpp\",\"file\":\"%t/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
|
||||
// RUN: cp "%s" "%t/test.cpp"
|
||||
// RUN: PWD="%t" clang-check "%t" "test.cpp" 2>&1|FileCheck %s
|
||||
// RUN: PWD="%t" clang-check -p "%t" "test.cpp" 2>&1|FileCheck %s
|
||||
// FIXME: Make the above easier.
|
||||
|
||||
// CHECK: C++ requires
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// RUN: mkdir %t
|
||||
// RUN: echo '[{"directory":".","command":"clang++ -c %t/test.cpp","file":"%t/test.cpp"}]' | sed -e 's/\\/\//g' > %t/compile_commands.json
|
||||
// RUN: cp "%s" "%t/test.cpp"
|
||||
// RUN: clang-check "%t" "%t/test.cpp" 2>&1|FileCheck %s
|
||||
// RUN: clang-check -p "%t" "%t/test.cpp" 2>&1|FileCheck %s
|
||||
// FIXME: Make the above easier.
|
||||
|
||||
// CHECK: C++ requires
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: clang-check . "%s" -- -no-integrated-as -c 2>&1 | FileCheck %s
|
||||
// RUN: clang-check "%s" -- -no-integrated-as -c 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: C++ requires
|
||||
invalid;
|
||||
|
|
|
@ -42,8 +42,9 @@ using namespace clang::tooling;
|
|||
using namespace llvm;
|
||||
|
||||
cl::opt<std::string> BuildPath(
|
||||
cl::Positional,
|
||||
cl::desc("<build-path>"));
|
||||
"p",
|
||||
cl::desc("<build-path>"),
|
||||
cl::Optional);
|
||||
|
||||
cl::list<std::string> SourcePaths(
|
||||
cl::Positional,
|
||||
|
@ -56,8 +57,13 @@ int main(int argc, const char **argv) {
|
|||
cl::ParseCommandLineOptions(argc, argv);
|
||||
if (!Compilations) {
|
||||
std::string ErrorMessage;
|
||||
Compilations.reset(CompilationDatabase::loadFromDirectory(BuildPath,
|
||||
ErrorMessage));
|
||||
if (!BuildPath.empty()) {
|
||||
Compilations.reset(CompilationDatabase::loadFromDirectory(BuildPath,
|
||||
ErrorMessage));
|
||||
} else {
|
||||
Compilations.reset(CompilationDatabase::autoDetectFromSource(
|
||||
SourcePaths[0], ErrorMessage));
|
||||
}
|
||||
if (!Compilations)
|
||||
llvm::report_fatal_error(ErrorMessage);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue