Эх сурвалжийг харах

[Tooling] add a Heuristic field indicating that a CompileCommand was guessed.

Summary:
Use cases:
 - a tool that dumps the heuristic used for each header in a project can
   be used to evaluate changes to the heuristic
 - we want to expose this information to users in clangd as it affects
   accuracy/reliability of editor features
 - express interpolation tests more directly

Reviewers: ilya-biryukov, klimek

Subscribers: ioeric, kadircet, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D60194

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@357770 91177308-0d34-0410-b5e6-96231b3b80d8
Sam McCall 6 жил өмнө
parent
commit
151df10ca7

+ 7 - 1
include/clang/Tooling/CompilationDatabase.h

@@ -59,9 +59,15 @@ struct CompileCommand {
   /// The output file associated with the command.
   /// The output file associated with the command.
   std::string Output;
   std::string Output;
 
 
+  /// If this compile command was guessed rather than read from an authoritative
+  /// source, a short human-readable explanation.
+  /// e.g. "inferred from foo/bar.h".
+  std::string Heuristic;
+
   friend bool operator==(const CompileCommand &LHS, const CompileCommand &RHS) {
   friend bool operator==(const CompileCommand &LHS, const CompileCommand &RHS) {
     return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
     return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
-           LHS.CommandLine == RHS.CommandLine && LHS.Output == RHS.Output;
+           LHS.CommandLine == RHS.CommandLine && LHS.Output == RHS.Output &&
+           LHS.Heuristic == RHS.Heuristic;
   }
   }
 
 
   friend bool operator!=(const CompileCommand &LHS, const CompileCommand &RHS) {
   friend bool operator!=(const CompileCommand &LHS, const CompileCommand &RHS) {

+ 1 - 0
lib/Tooling/InterpolatingCompilationDatabase.cpp

@@ -226,6 +226,7 @@ struct TransferableCommand {
           LangStandard::getLangStandardForKind(Std).getName()).str());
           LangStandard::getLangStandardForKind(Std).getName()).str());
     }
     }
     Result.CommandLine.push_back(Filename);
     Result.CommandLine.push_back(Filename);
+    Result.Heuristic = "inferred from " + Cmd.Filename;
     return Result;
     return Result;
   }
   }
 
 

+ 28 - 9
unittests/Tooling/CompilationDatabaseTest.cpp

@@ -673,6 +673,27 @@ protected:
     return llvm::join(Results[0].CommandLine, " ");
     return llvm::join(Results[0].CommandLine, " ");
   }
   }
 
 
+  // Parse the file whose command was used out of the Heuristic string.
+  std::string getProxy(llvm::StringRef F) {
+    auto Results =
+        inferMissingCompileCommands(llvm::make_unique<MemCDB>(Entries))
+            ->getCompileCommands(path(F));
+    if (Results.empty())
+      return "none";
+    StringRef Proxy = Results.front().Heuristic;
+    if (!Proxy.consume_front("inferred from "))
+      return "";
+    // We have a proxy file, convert back to a unix relative path.
+    // This is a bit messy, but we do need to test these strings somehow...
+    llvm::SmallString<32> TempDir;
+    llvm::sys::path::system_temp_directory(false, TempDir);
+    Proxy.consume_front(TempDir);
+    Proxy.consume_front(llvm::sys::path::get_separator());
+    llvm::SmallString<32> Result = Proxy;
+    llvm::sys::path::native(Result, llvm::sys::path::Style::posix);
+    return Result.str();
+  }
+
   MemCDB::EntryMap Entries;
   MemCDB::EntryMap Entries;
 };
 };
 
 
@@ -682,18 +703,16 @@ TEST_F(InterpolateTest, Nearby) {
   add("an/other/foo.cpp");
   add("an/other/foo.cpp");
 
 
   // great: dir and name both match (prefix or full, case insensitive)
   // great: dir and name both match (prefix or full, case insensitive)
-  EXPECT_EQ(getCommand("dir/f.cpp"), "clang -D dir/foo.cpp");
-  EXPECT_EQ(getCommand("dir/FOO.cpp"), "clang -D dir/foo.cpp");
+  EXPECT_EQ(getProxy("dir/f.cpp"), "dir/foo.cpp");
+  EXPECT_EQ(getProxy("dir/FOO.cpp"), "dir/foo.cpp");
   // no name match. prefer matching dir, break ties by alpha
   // no name match. prefer matching dir, break ties by alpha
-  EXPECT_EQ(getCommand("dir/a.cpp"), "clang -D dir/bar.cpp");
+  EXPECT_EQ(getProxy("dir/a.cpp"), "dir/bar.cpp");
   // an exact name match beats one segment of directory match
   // an exact name match beats one segment of directory match
-  EXPECT_EQ(getCommand("some/other/bar.h"),
-            "clang -D dir/bar.cpp -x c++-header");
+  EXPECT_EQ(getProxy("some/other/bar.h"), "dir/bar.cpp");
   // two segments of directory match beat a prefix name match
   // two segments of directory match beat a prefix name match
-  EXPECT_EQ(getCommand("an/other/b.cpp"), "clang -D an/other/foo.cpp");
+  EXPECT_EQ(getProxy("an/other/b.cpp"), "an/other/foo.cpp");
   // if nothing matches at all, we still get the closest alpha match
   // if nothing matches at all, we still get the closest alpha match
-  EXPECT_EQ(getCommand("below/some/obscure/path.cpp"),
-            "clang -D an/other/foo.cpp");
+  EXPECT_EQ(getProxy("below/some/obscure/path.cpp"), "an/other/foo.cpp");
 }
 }
 
 
 TEST_F(InterpolateTest, Language) {
 TEST_F(InterpolateTest, Language) {
@@ -727,7 +746,7 @@ TEST_F(InterpolateTest, Case) {
   add("FOO/BAR/BAZ/SHOUT.cc");
   add("FOO/BAR/BAZ/SHOUT.cc");
   add("foo/bar/baz/quiet.cc");
   add("foo/bar/baz/quiet.cc");
   // Case mismatches are completely ignored, so we choose the name match.
   // Case mismatches are completely ignored, so we choose the name match.
-  EXPECT_EQ(getCommand("foo/bar/baz/shout.C"), "clang -D FOO/BAR/BAZ/SHOUT.cc");
+  EXPECT_EQ(getProxy("foo/bar/baz/shout.C"), "FOO/BAR/BAZ/SHOUT.cc");
 }
 }
 
 
 TEST_F(InterpolateTest, Aliasing) {
 TEST_F(InterpolateTest, Aliasing) {