diff clang/unittests/CrossTU/CrossTranslationUnitTest.cpp @ 207:2e18cbf3894f

LLVM12
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Tue, 08 Jun 2021 06:07:14 +0900
parents 1d019706d866
children c4bab56944e8
line wrap: on
line diff
--- a/clang/unittests/CrossTU/CrossTranslationUnitTest.cpp	Mon May 25 11:55:54 2020 +0900
+++ b/clang/unittests/CrossTU/CrossTranslationUnitTest.cpp	Tue Jun 08 06:07:14 2021 +0900
@@ -7,10 +7,12 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/CrossTU/CrossTranslationUnit.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ParentMapContext.h"
 #include "clang/Frontend/CompilerInstance.h"
-#include "clang/AST/ASTConsumer.h"
 #include "clang/Frontend/FrontendAction.h"
 #include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/ToolOutputFile.h"
@@ -27,7 +29,7 @@
   explicit CTUASTConsumer(clang::CompilerInstance &CI, bool *Success)
       : CTU(CI), Success(Success) {}
 
-  void HandleTranslationUnit(ASTContext &Ctx) {
+  void HandleTranslationUnit(ASTContext &Ctx) override {
     auto FindFInTU = [](const TranslationUnitDecl *TU) {
       const FunctionDecl *FD = nullptr;
       for (const Decl *D : TU->decls()) {
@@ -43,6 +45,10 @@
     assert(FD && FD->getName() == "f");
     bool OrigFDHasBody = FD->hasBody();
 
+    const DynTypedNodeList ParentsBeforeImport =
+        Ctx.getParentMapContext().getParents<Decl>(*FD);
+    ASSERT_FALSE(ParentsBeforeImport.empty());
+
     // Prepare the index file and the AST file.
     int ASTFD;
     llvm::SmallString<256> ASTFileName;
@@ -85,29 +91,28 @@
       *Success = NewFD && NewFD->hasBody() && !OrigFDHasBody;
 
       if (NewFD) {
-        // Check GetImportedFromSourceLocation.
-        llvm::Optional<std::pair<SourceLocation, ASTUnit *>> SLocResult =
-            CTU.getImportedFromSourceLocation(NewFD->getLocation());
-        EXPECT_TRUE(SLocResult);
-        if (SLocResult) {
-          SourceLocation OrigSLoc = (*SLocResult).first;
-          ASTUnit *OrigUnit = (*SLocResult).second;
-          // OrigUnit is created internally by CTU (is not the
-          // ASTWithDefinition).
-          TranslationUnitDecl *OrigTU =
-              OrigUnit->getASTContext().getTranslationUnitDecl();
-          const FunctionDecl *FDWithDefinition = FindFInTU(OrigTU);
-          EXPECT_TRUE(FDWithDefinition);
-          if (FDWithDefinition) {
-            EXPECT_EQ(FDWithDefinition->getName(), "f");
-            EXPECT_TRUE(FDWithDefinition->isThisDeclarationADefinition());
-            EXPECT_EQ(OrigSLoc, FDWithDefinition->getLocation());
-          }
-        }
+        // Check parent map.
+        const DynTypedNodeList ParentsAfterImport =
+            Ctx.getParentMapContext().getParents<Decl>(*FD);
+        const DynTypedNodeList ParentsOfImported =
+            Ctx.getParentMapContext().getParents<Decl>(*NewFD);
+        EXPECT_TRUE(
+            checkParentListsEq(ParentsBeforeImport, ParentsAfterImport));
+        EXPECT_FALSE(ParentsOfImported.empty());
       }
     }
   }
 
+  static bool checkParentListsEq(const DynTypedNodeList &L1,
+                                 const DynTypedNodeList &L2) {
+    if (L1.size() != L2.size())
+      return false;
+    for (unsigned int I = 0; I < L1.size(); ++I)
+      if (L1[I] != L2[I])
+        return false;
+    return true;
+  }
+
 private:
   CrossTranslationUnitContext CTU;
   bool *Success;
@@ -122,6 +127,7 @@
   std::unique_ptr<clang::ASTConsumer>
   CreateASTConsumer(clang::CompilerInstance &CI, StringRef) override {
     CI.getAnalyzerOpts()->CTUImportThreshold = OverrideLimit;
+    CI.getAnalyzerOpts()->CTUImportCppThreshold = OverrideLimit;
     return std::make_unique<CTUASTConsumer>(CI, Success);
   }
 
@@ -162,7 +168,7 @@
   IndexFile.os().flush();
   EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName));
   llvm::Expected<llvm::StringMap<std::string>> IndexOrErr =
-      parseCrossTUIndex(IndexFileName, "");
+      parseCrossTUIndex(IndexFileName);
   EXPECT_TRUE((bool)IndexOrErr);
   llvm::StringMap<std::string> ParsedIndex = IndexOrErr.get();
   for (const auto &E : Index) {
@@ -173,24 +179,98 @@
     EXPECT_TRUE(Index.count(E.getKey()));
 }
 
-TEST(CrossTranslationUnit, CTUDirIsHandledCorrectly) {
-  llvm::StringMap<std::string> Index;
-  Index["a"] = "/b/c/d";
-  std::string IndexText = createCrossTUIndexString(Index);
+TEST(CrossTranslationUnit, EmptyInvocationListIsNotValid) {
+  auto Input = "";
+
+  llvm::Expected<InvocationListTy> Result = parseInvocationList(Input);
+  EXPECT_FALSE(static_cast<bool>(Result));
+  bool IsWrongFromatError = false;
+  llvm::handleAllErrors(Result.takeError(), [&](IndexError &Err) {
+    IsWrongFromatError =
+        Err.getCode() == index_error_code::invocation_list_wrong_format;
+  });
+  EXPECT_TRUE(IsWrongFromatError);
+}
+
+TEST(CrossTranslationUnit, AmbiguousInvocationListIsDetected) {
+  // The same source file occurs twice (for two different architecture) in
+  // this test case. The disambiguation is the responsibility of the user.
+  auto Input = R"(
+  /tmp/main.cpp:
+    - clang++
+    - -c
+    - -m32
+    - -o
+    - main32.o
+    - /tmp/main.cpp
+  /tmp/main.cpp:
+    - clang++
+    - -c
+    - -m64
+    - -o
+    - main64.o
+    - /tmp/main.cpp
+  )";
+
+  llvm::Expected<InvocationListTy> Result = parseInvocationList(Input);
+  EXPECT_FALSE(static_cast<bool>(Result));
+  bool IsAmbiguousError = false;
+  llvm::handleAllErrors(Result.takeError(), [&](IndexError &Err) {
+    IsAmbiguousError =
+        Err.getCode() == index_error_code::invocation_list_ambiguous;
+  });
+  EXPECT_TRUE(IsAmbiguousError);
+}
 
-  int IndexFD;
-  llvm::SmallString<256> IndexFileName;
-  ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("index", "txt", IndexFD,
-                                                  IndexFileName));
-  llvm::ToolOutputFile IndexFile(IndexFileName, IndexFD);
-  IndexFile.os() << IndexText;
-  IndexFile.os().flush();
-  EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName));
-  llvm::Expected<llvm::StringMap<std::string>> IndexOrErr =
-      parseCrossTUIndex(IndexFileName, "/ctudir");
-  EXPECT_TRUE((bool)IndexOrErr);
-  llvm::StringMap<std::string> ParsedIndex = IndexOrErr.get();
-  EXPECT_EQ(ParsedIndex["a"], "/ctudir/b/c/d");
+TEST(CrossTranslationUnit, SingleInvocationCanBeParsed) {
+  auto Input = R"(
+  /tmp/main.cpp:
+    - clang++
+    - /tmp/main.cpp
+  )";
+  llvm::Expected<InvocationListTy> Result = parseInvocationList(Input);
+  EXPECT_TRUE(static_cast<bool>(Result));
+
+  EXPECT_EQ(Result->size(), 1u);
+
+  auto It = Result->find("/tmp/main.cpp");
+  EXPECT_TRUE(It != Result->end());
+  EXPECT_EQ(It->getValue()[0], "clang++");
+  EXPECT_EQ(It->getValue()[1], "/tmp/main.cpp");
+}
+
+TEST(CrossTranslationUnit, MultipleInvocationsCanBeParsed) {
+  auto Input = R"(
+  /tmp/main.cpp:
+    - clang++
+    - /tmp/other.o
+    - /tmp/main.cpp
+  /tmp/other.cpp:
+    - g++
+    - -c
+    - -o
+    - /tmp/other.o
+    - /tmp/other.cpp
+  )";
+  llvm::Expected<InvocationListTy> Result = parseInvocationList(Input);
+  EXPECT_TRUE(static_cast<bool>(Result));
+
+  EXPECT_EQ(Result->size(), 2u);
+
+  auto It = Result->find("/tmp/main.cpp");
+  EXPECT_TRUE(It != Result->end());
+  EXPECT_EQ(It->getKey(), "/tmp/main.cpp");
+  EXPECT_EQ(It->getValue()[0], "clang++");
+  EXPECT_EQ(It->getValue()[1], "/tmp/other.o");
+  EXPECT_EQ(It->getValue()[2], "/tmp/main.cpp");
+
+  It = Result->find("/tmp/other.cpp");
+  EXPECT_TRUE(It != Result->end());
+  EXPECT_EQ(It->getValue()[0], "g++");
+  EXPECT_EQ(It->getValue()[1], "-c");
+  EXPECT_EQ(It->getValue()[2], "-o");
+  EXPECT_EQ(It->getValue()[3], "/tmp/other.o");
+  EXPECT_EQ(It->getValue()[4], "/tmp/other.cpp");
 }
 
 } // end namespace cross_tu