spyffe updated this revision to Diff 81661.
spyffe marked 2 inline comments as done.
spyffe added a comment.
Herald added a subscriber: jgosnell.

Applied Vassil and Vedant's comments.  I will commit this soon.


Repository:
  rL LLVM

https://reviews.llvm.org/D27180

Files:
  test/Import/clang-flags/Inputs/S.c
  test/Import/clang-flags/test.c
  test/Import/empty-struct/Inputs/S.c
  test/Import/empty-struct/test.c
  test/Import/error-in-expression/Inputs/S.c
  test/Import/error-in-expression/test.c
  test/Import/error-in-import/Inputs/S.c
  test/Import/error-in-import/test.c
  test/Import/missing-import/test.c
  tools/CMakeLists.txt
  tools/clang-import-test/CMakeLists.txt
  tools/clang-import-test/clang-import-test.cpp

Index: tools/clang-import-test/clang-import-test.cpp
===================================================================
--- tools/clang-import-test/clang-import-test.cpp
+++ tools/clang-import-test/clang-import-test.cpp
@@ -0,0 +1,319 @@
+//===-- import-test.cpp - ASTImporter/ExternalASTSource testbed -----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTImporter.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseAST.h"
+
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/Signals.h"
+
+#include <memory>
+#include <string>
+
+using namespace clang;
+
+static llvm::cl::opt<std::string> Expression(
+    "expression", llvm::cl::Required,
+    llvm::cl::desc("Path to a file containing the expression to parse"));
+
+static llvm::cl::list<std::string>
+    Imports("import", llvm::cl::ZeroOrMore,
+            llvm::cl::desc("Path to a file containing declarations to import"));
+
+static llvm::cl::list<std::string>
+    ClangArgs("Xcc", llvm::cl::ZeroOrMore,
+              llvm::cl::desc("Argument to pass to the CompilerInvocation"),
+              llvm::cl::CommaSeparated);
+
+namespace init_convenience {
+class TestDiagnosticConsumer : public DiagnosticConsumer {
+private:
+  std::unique_ptr<TextDiagnosticBuffer> Passthrough;
+  const LangOptions *LangOpts = nullptr;
+
+public:
+  TestDiagnosticConsumer()
+      : Passthrough(llvm::make_unique<TextDiagnosticBuffer>()) {}
+
+  virtual void BeginSourceFile(const LangOptions &LangOpts,
+                               const Preprocessor *PP = nullptr) override {
+    this->LangOpts = &LangOpts;
+    return Passthrough->BeginSourceFile(LangOpts, PP);
+  }
+
+  virtual void EndSourceFile() override {
+    this->LangOpts = nullptr;
+    Passthrough->EndSourceFile();
+  }
+
+  virtual bool IncludeInDiagnosticCounts() const override {
+    return Passthrough->IncludeInDiagnosticCounts();
+  }
+
+private:
+  static void PrintSourceForLocation(const SourceLocation &Loc,
+                                     SourceManager &SM) {
+    const char *LocData = SM.getCharacterData(Loc, /*Invalid=*/nullptr);
+    unsigned LocColumn =
+        SM.getSpellingColumnNumber(Loc, /*Invalid=*/nullptr) - 1;
+    FileID FID = SM.getFileID(Loc);
+    llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, Loc, /*Invalid=*/nullptr);
+
+    assert(LocData >= Buffer->getBufferStart() &&
+           LocData < Buffer->getBufferEnd());
+
+    const char *LineBegin = LocData - LocColumn;
+
+    assert(LineBegin >= Buffer->getBufferStart());
+
+    const char *LineEnd = nullptr;
+
+    for (LineEnd = LineBegin; *LineEnd != '\n' && *LineEnd != '\r' &&
+                              LineEnd < Buffer->getBufferEnd();
+         ++LineEnd)
+      ;
+
+    llvm::StringRef LineString(LineBegin, LineEnd - LineBegin);
+
+    llvm::errs() << LineString << '\n';
+    std::string Space(LocColumn, ' ');
+    llvm::errs() << Space.c_str() << '\n';
+  }
+
+  virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+                                const Diagnostic &Info) override {
+    if (Info.hasSourceManager() && LangOpts) {
+      SourceManager &SM = Info.getSourceManager();
+
+      if (Info.getLocation().isValid()) {
+        Info.getLocation().print(llvm::errs(), SM);
+        llvm::errs() << ": ";
+      }
+
+      SmallString<16> DiagText;
+      Info.FormatDiagnostic(DiagText);
+      llvm::errs() << DiagText << '\n';
+
+      if (Info.getLocation().isValid()) {
+        PrintSourceForLocation(Info.getLocation(), SM);
+      }
+
+      for (const CharSourceRange &Range : Info.getRanges()) {
+        bool Invalid = true;
+        StringRef Ref = Lexer::getSourceText(Range, SM, *LangOpts, &Invalid);
+        if (!Invalid) {
+          llvm::errs() << Ref.str() << '\n';
+        }
+      }
+    }
+    DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
+  }
+};
+
+std::unique_ptr<CompilerInstance>
+BuildCompilerInstance(ArrayRef<const char *> ClangArgv) {
+  auto Ins = llvm::make_unique<CompilerInstance>();
+  auto DC = llvm::make_unique<TestDiagnosticConsumer>();
+  const bool ShouldOwnClient = true;
+  Ins->createDiagnostics(DC.release(), ShouldOwnClient);
+
+  auto Inv = llvm::make_unique<CompilerInvocation>();
+
+  CompilerInvocation::CreateFromArgs(*Inv, ClangArgv.data(),
+                                     &ClangArgv.data()[ClangArgv.size()],
+                                     Ins->getDiagnostics());
+
+  Inv->getLangOpts()->CPlusPlus = true;
+  Inv->getLangOpts()->CPlusPlus11 = true;
+  Inv->getHeaderSearchOpts().UseLibcxx = true;
+  Inv->getLangOpts()->Bool = true;
+  Inv->getLangOpts()->WChar = true;
+  Inv->getLangOpts()->Blocks = true;
+  Inv->getLangOpts()->DebuggerSupport = true;
+  Inv->getLangOpts()->SpellChecking = false;
+  Inv->getLangOpts()->ThreadsafeStatics = false;
+  Inv->getLangOpts()->AccessControl = false;
+  Inv->getLangOpts()->DollarIdents = true;
+  Inv->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo);
+  Inv->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple();
+
+  Ins->setInvocation(Inv.release());
+
+  TargetInfo *TI = TargetInfo::CreateTargetInfo(
+      Ins->getDiagnostics(), Ins->getInvocation().TargetOpts);
+  Ins->setTarget(TI);
+  Ins->getTarget().adjust(Ins->getLangOpts());
+  Ins->createFileManager();
+  Ins->createSourceManager(Ins->getFileManager());
+  Ins->createPreprocessor(TU_Complete);
+
+  return Ins;
+}
+
+std::unique_ptr<ASTContext>
+BuildASTContext(CompilerInstance &CI, SelectorTable &ST, Builtin::Context &BC) {
+  auto AST = llvm::make_unique<ASTContext>(
+      CI.getLangOpts(), CI.getSourceManager(),
+      CI.getPreprocessor().getIdentifierTable(), ST, BC);
+  AST->InitBuiltinTypes(CI.getTarget());
+  return AST;
+}
+
+std::unique_ptr<CodeGenerator> BuildCodeGen(CompilerInstance &CI,
+                                            llvm::LLVMContext &LLVMCtx) {
+  StringRef ModuleName("$__module");
+  return std::unique_ptr<CodeGenerator>(CreateLLVMCodeGen(
+      CI.getDiagnostics(), ModuleName, CI.getHeaderSearchOpts(),
+      CI.getPreprocessorOpts(), CI.getCodeGenOpts(), LLVMCtx));
+}
+} // end namespace
+
+namespace {
+class TestExternalASTSource : public ExternalASTSource {
+private:
+  llvm::ArrayRef<std::unique_ptr<CompilerInstance>> ImportCIs;
+  std::map<CompilerInstance *, std::unique_ptr<ASTImporter>> ForwardImporters;
+  std::map<CompilerInstance *, std::unique_ptr<ASTImporter>> ReverseImporters;
+
+public:
+  TestExternalASTSource(
+      CompilerInstance &ExpressionCI,
+      llvm::ArrayRef<std::unique_ptr<CompilerInstance>> ImportCIs)
+      : ImportCIs(ImportCIs) {
+    for (const std::unique_ptr<CompilerInstance> &ImportCI : ImportCIs) {
+      ForwardImporters[ImportCI.get()] = llvm::make_unique<ASTImporter>(
+          ExpressionCI.getASTContext(), ExpressionCI.getFileManager(),
+          ImportCI->getASTContext(), ImportCI->getFileManager(),
+          /*MinimalImport=*/true);
+      ReverseImporters[ImportCI.get()] = llvm::make_unique<ASTImporter>(
+          ImportCI->getASTContext(), ImportCI->getFileManager(),
+          ExpressionCI.getASTContext(), ExpressionCI.getFileManager(),
+          /*MinimalImport=*/true);
+    }
+  }
+
+  bool FindExternalVisibleDeclsByName(const DeclContext *DC,
+                                      DeclarationName Name) override {
+    llvm::SmallVector<NamedDecl *, 1> Decls;
+
+    if (isa<TranslationUnitDecl>(DC)) {
+      for (const std::unique_ptr<CompilerInstance> &I : ImportCIs) {
+        DeclarationName FromName = ReverseImporters[I.get()]->Import(Name);
+        DeclContextLookupResult Result =
+            I->getASTContext().getTranslationUnitDecl()->lookup(FromName);
+        for (NamedDecl *FromD : Result) {
+          NamedDecl *D =
+              llvm::cast<NamedDecl>(ForwardImporters[I.get()]->Import(FromD));
+          Decls.push_back(D);
+        }
+      }
+    }
+    if (Decls.empty()) {
+      return false;
+    } else {
+      SetExternalVisibleDeclsForName(DC, Name, Decls);
+      return true;
+    }
+  }
+};
+
+void AddExternalSource(
+    CompilerInstance &CI,
+    llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports) {
+  ASTContext &AST = CI.getASTContext();
+  auto ES = llvm::make_unique<TestExternalASTSource>(CI, Imports);
+  AST.setExternalSource(ES.release());
+  AST.getTranslationUnitDecl()->setHasExternalVisibleStorage();
+}
+
+llvm::Error ParseSource(const std::string &Path, CompilerInstance &CI,
+                        CodeGenerator &CG) {
+  SourceManager &SM = CI.getSourceManager();
+  const FileEntry *FE = CI.getFileManager().getFile(Path);
+  if (!FE) {
+    return llvm::make_error<llvm::StringError>(
+        llvm::Twine("Couldn't open ", Path), std::error_code());
+  }
+  SM.setMainFileID(SM.createFileID(FE, SourceLocation(), SrcMgr::C_User));
+  ParseAST(CI.getPreprocessor(), &CG, CI.getASTContext());
+  return llvm::Error::success();
+}
+
+llvm::Expected<std::unique_ptr<CompilerInstance>>
+Parse(const std::string &Path,
+      llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports) {
+  std::vector<const char *> ClangArgv(ClangArgs.size());
+  std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(),
+                 [](const std::string &s) -> const char * { return s.data(); });
+  std::unique_ptr<CompilerInstance> CI =
+      init_convenience::BuildCompilerInstance(ClangArgv);
+  auto ST = llvm::make_unique<SelectorTable>();
+  auto BC = llvm::make_unique<Builtin::Context>();
+  std::unique_ptr<ASTContext> AST =
+      init_convenience::BuildASTContext(*CI, *ST, *BC);
+  CI->setASTContext(AST.release());
+  AddExternalSource(*CI, Imports);
+
+  auto LLVMCtx = llvm::make_unique<llvm::LLVMContext>();
+  std::unique_ptr<CodeGenerator> CG =
+      init_convenience::BuildCodeGen(*CI, *LLVMCtx);
+  CG->Initialize(CI->getASTContext());
+
+  CI->getDiagnosticClient().BeginSourceFile(CI->getLangOpts(),
+                                            &CI->getPreprocessor());
+  if (llvm::Error PE = ParseSource(Path, *CI, *CG)) {
+    return std::move(PE);
+  }
+  CI->getDiagnosticClient().EndSourceFile();
+  if (CI->getDiagnosticClient().getNumErrors()) {
+    return llvm::make_error<llvm::StringError>(
+        "Errors occured while parsing the expression.", std::error_code());
+  } else {
+    return std::move(CI);
+  }
+}
+} // end namespace
+
+int main(int argc, const char **argv) {
+  const bool DisableCrashReporting = true;
+  llvm::sys::PrintStackTraceOnErrorSignal(argv[0], DisableCrashReporting);
+  llvm::cl::ParseCommandLineOptions(argc, argv);
+  std::vector<std::unique_ptr<CompilerInstance>> ImportCIs;
+  for (auto I : Imports) {
+      llvm::Expected<std::unique_ptr<CompilerInstance>> ImportCI = Parse(I, {});
+      if (auto E = ImportCI.takeError()) {
+        llvm::errs() << llvm::toString(std::move(E));
+        exit(-1);
+      } else {
+        ImportCIs.push_back(std::move(*ImportCI));
+      }
+    }
+  llvm::Expected<std::unique_ptr<CompilerInstance>> ExpressionCI =
+      Parse(Expression, ImportCIs);
+  if (auto E = ExpressionCI.takeError()) {
+    llvm::errs() << llvm::toString(std::move(E));
+    exit(-1);
+  } else {
+    return 0;
+  }
+}
Index: tools/clang-import-test/CMakeLists.txt
===================================================================
--- tools/clang-import-test/CMakeLists.txt
+++ tools/clang-import-test/CMakeLists.txt
@@ -0,0 +1,18 @@
+set(LLVM_LINK_COMPONENTS
+  support
+)
+
+add_clang_tool(clang-import-test
+  clang-import-test.cpp
+  )
+
+set(CLANG_IMPORT_TEST_LIB_DEPS
+  clangAST
+  clangBasic
+  clangCodeGen
+  clangFrontend
+  )
+
+target_link_libraries(clang-import-test
+  ${CLANG_IMPORT_TEST_LIB_DEPS}
+  )
Index: tools/CMakeLists.txt
===================================================================
--- tools/CMakeLists.txt
+++ tools/CMakeLists.txt
@@ -5,6 +5,7 @@
 add_clang_subdirectory(clang-format)
 add_clang_subdirectory(clang-format-vs)
 add_clang_subdirectory(clang-fuzzer)
+add_clang_subdirectory(clang-import-test)
 add_clang_subdirectory(clang-offload-bundler)
 
 add_clang_subdirectory(c-index-test)
Index: test/Import/missing-import/test.c
===================================================================
--- test/Import/missing-import/test.c
+++ test/Import/missing-import/test.c
@@ -0,0 +1,6 @@
+// RUN: not clang-import-test -import %S/Inputs/S.c -expression %s 2>&1 | FileCheck %s
+// CHECK: {{.*}}Couldn't open{{.*}}Inputs/S.c{{.*}}
+void expr() {
+  struct S MyS;
+  void *MyPtr = &MyS;
+}
Index: test/Import/error-in-import/test.c
===================================================================
--- test/Import/error-in-import/test.c
+++ test/Import/error-in-import/test.c
@@ -0,0 +1,6 @@
+// RUN: not clang-import-test -import %S/Inputs/S.c -expression %s 2>&1 | FileCheck %s
+// CHECK: {{.*}}expected unqualified-id{{.*}}
+void expr() {
+  struct S MyS;
+  void *MyPtr = &MyS;
+}
Index: test/Import/error-in-import/Inputs/S.c
===================================================================
--- test/Import/error-in-import/Inputs/S.c
+++ test/Import/error-in-import/Inputs/S.c
@@ -0,0 +1,2 @@
+struct S [
+];
Index: test/Import/error-in-expression/test.c
===================================================================
--- test/Import/error-in-expression/test.c
+++ test/Import/error-in-expression/test.c
@@ -0,0 +1,6 @@
+// RUN: not clang-import-test -import %S/Inputs/S.c -expression %s 2>&1 | FileCheck %s
+// CHECK: {{.*}}no viable conversion{{.*}}
+void expr() {
+  struct S MyS;
+  void *MyPtr = MyS;
+}
Index: test/Import/error-in-expression/Inputs/S.c
===================================================================
--- test/Import/error-in-expression/Inputs/S.c
+++ test/Import/error-in-expression/Inputs/S.c
@@ -0,0 +1,2 @@
+struct S {
+};
Index: test/Import/empty-struct/test.c
===================================================================
--- test/Import/empty-struct/test.c
+++ test/Import/empty-struct/test.c
@@ -0,0 +1,5 @@
+// RUN: clang-import-test -import %S/Inputs/S.c -expression %s
+void expr() {
+  struct S MyS;
+  void *MyPtr = &MyS;
+}
Index: test/Import/empty-struct/Inputs/S.c
===================================================================
--- test/Import/empty-struct/Inputs/S.c
+++ test/Import/empty-struct/Inputs/S.c
@@ -0,0 +1,2 @@
+struct S {
+};
Index: test/Import/clang-flags/test.c
===================================================================
--- test/Import/clang-flags/test.c
+++ test/Import/clang-flags/test.c
@@ -0,0 +1,5 @@
+// RUN: clang-import-test -import %S/Inputs/S.c -expression %s -Xcc -DSTRUCT=struct
+void expr() {
+  STRUCT S MyS;
+  void *MyPtr = &MyS;
+}
Index: test/Import/clang-flags/Inputs/S.c
===================================================================
--- test/Import/clang-flags/Inputs/S.c
+++ test/Import/clang-flags/Inputs/S.c
@@ -0,0 +1,2 @@
+STRUCT S {
+};
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to