aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManuel Klimek <klimek@google.com>2012-07-10 13:10:51 +0000
committerManuel Klimek <klimek@google.com>2012-07-10 13:10:51 +0000
commit8fa2fb859a4cb8e67d9763225281d9b0aa9cb59f (patch)
treebaba2e136725c1e8cba0ce410db39759981af927
parent3f6d513d51a382371669f4d0b943fa830fffeef2 (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159990 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Tooling/CompilationDatabase.h8
-rw-r--r--include/clang/Tooling/Tooling.h16
-rw-r--r--lib/Tooling/CompilationDatabase.cpp19
-rw-r--r--lib/Tooling/Tooling.cpp27
-rw-r--r--test/Tooling/auto-detect-from-source-parent-of-cwd.cpp8
-rw-r--r--test/Tooling/auto-detect-from-source-parent.cpp8
-rw-r--r--test/Tooling/auto-detect-from-source.cpp8
-rw-r--r--test/Tooling/clang-check-args.cpp2
-rw-r--r--test/Tooling/clang-check-builtin-headers.cpp2
-rw-r--r--test/Tooling/clang-check-chdir.cpp2
-rw-r--r--test/Tooling/clang-check-pwd.cpp2
-rw-r--r--test/Tooling/clang-check.cpp2
-rw-r--r--test/Tooling/multi-jobs.cpp2
-rw-r--r--tools/clang-check/ClangCheck.cpp14
14 files changed, 88 insertions, 32 deletions
diff --git a/include/clang/Tooling/CompilationDatabase.h b/include/clang/Tooling/CompilationDatabase.h
index 625c8eced4..0dec6f8f87 100644
--- a/include/clang/Tooling/CompilationDatabase.h
+++ b/include/clang/Tooling/CompilationDatabase.h
@@ -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
-
diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h
index 0e1dd58ac9..03f9d0b4bc 100644
--- a/include/clang/Tooling/Tooling.h
+++ b/include/clang/Tooling/Tooling.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
diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp
index 227fa82926..8e911123bc 100644
--- a/lib/Tooling/CompilationDatabase.cpp
+++ b/lib/Tooling/CompilationDatabase.cpp
@@ -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
-
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
index abac182b21..5d41172a91 100644
--- a/lib/Tooling/Tooling.cpp
+++ b/lib/Tooling/Tooling.cpp
@@ -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());
diff --git a/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp b/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp
new file mode 100644
index 0000000000..7a4f9af6c4
--- /dev/null
+++ b/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp
@@ -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;
diff --git a/test/Tooling/auto-detect-from-source-parent.cpp b/test/Tooling/auto-detect-from-source-parent.cpp
new file mode 100644
index 0000000000..cb5fd56328
--- /dev/null
+++ b/test/Tooling/auto-detect-from-source-parent.cpp
@@ -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;
diff --git a/test/Tooling/auto-detect-from-source.cpp b/test/Tooling/auto-detect-from-source.cpp
new file mode 100644
index 0000000000..40a2a1c9fe
--- /dev/null
+++ b/test/Tooling/auto-detect-from-source.cpp
@@ -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;
diff --git a/test/Tooling/clang-check-args.cpp b/test/Tooling/clang-check-args.cpp
index ab1585f073..9ba5d45f50 100644
--- a/test/Tooling/clang-check-args.cpp
+++ b/test/Tooling/clang-check-args.cpp
@@ -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;
diff --git a/test/Tooling/clang-check-builtin-headers.cpp b/test/Tooling/clang-check-builtin-headers.cpp
index fda68ccbc0..504d197ea9 100644
--- a/test/Tooling/clang-check-builtin-headers.cpp
+++ b/test/Tooling/clang-check-builtin-headers.cpp
@@ -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>
diff --git a/test/Tooling/clang-check-chdir.cpp b/test/Tooling/clang-check-chdir.cpp
index d9f172848b..29b5abb4c9 100644
--- a/test/Tooling/clang-check-chdir.cpp
+++ b/test/Tooling/clang-check-chdir.cpp
@@ -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"
diff --git a/test/Tooling/clang-check-pwd.cpp b/test/Tooling/clang-check-pwd.cpp
index 8dd9e6e926..374c579245 100644
--- a/test/Tooling/clang-check-pwd.cpp
+++ b/test/Tooling/clang-check-pwd.cpp
@@ -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
diff --git a/test/Tooling/clang-check.cpp b/test/Tooling/clang-check.cpp
index ff90b88417..91ab01b01b 100644
--- a/test/Tooling/clang-check.cpp
+++ b/test/Tooling/clang-check.cpp
@@ -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
diff --git a/test/Tooling/multi-jobs.cpp b/test/Tooling/multi-jobs.cpp
index 1de56345cf..a3eb7039c0 100644
--- a/test/Tooling/multi-jobs.cpp
+++ b/test/Tooling/multi-jobs.cpp
@@ -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;
diff --git a/tools/clang-check/ClangCheck.cpp b/tools/clang-check/ClangCheck.cpp
index d68e282949..ef4a3ace0c 100644
--- a/tools/clang-check/ClangCheck.cpp
+++ b/tools/clang-check/ClangCheck.cpp
@@ -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);
}