[cfe-commits] r95683 - in /cfe/trunk: include/clang/Driver/CC1Options.td include/clang/Frontend/FrontendAction.h include/clang/Frontend/FrontendActions.h include/clang/Frontend/FrontendOptions.h lib/AST/ASTImporter.cpp lib/Frontend/ASTMerge.cpp lib/Frontend/CMakeLists.txt lib/Frontend/CompilerInvocation.cpp test/ASTMerge/ test/ASTMerge/Inputs/ test/ASTMerge/Inputs/var1.c test/ASTMerge/Inputs/var2.c test/ASTMerge/var.c tools/driver/cc1_main.cpp

Douglas Gregor dgregor at apple.com
Tue Feb 9 11:21:46 PST 2010


Author: dgregor
Date: Tue Feb  9 13:21:46 2010
New Revision: 95683

URL: http://llvm.org/viewvc/llvm-project?rev=95683&view=rev
Log:
Introduce a testbed for merging multiple ASTs into a single AST
context with the AST importer. WIP, still useless but at least it has
a test.

Added:
    cfe/trunk/lib/Frontend/ASTMerge.cpp   (with props)
    cfe/trunk/test/ASTMerge/
    cfe/trunk/test/ASTMerge/Inputs/
    cfe/trunk/test/ASTMerge/Inputs/var1.c   (with props)
    cfe/trunk/test/ASTMerge/Inputs/var2.c   (with props)
    cfe/trunk/test/ASTMerge/var.c   (with props)
Modified:
    cfe/trunk/include/clang/Driver/CC1Options.td
    cfe/trunk/include/clang/Frontend/FrontendAction.h
    cfe/trunk/include/clang/Frontend/FrontendActions.h
    cfe/trunk/include/clang/Frontend/FrontendOptions.h
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/Frontend/CMakeLists.txt
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/tools/driver/cc1_main.cpp

Modified: cfe/trunk/include/clang/Driver/CC1Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=95683&r1=95682&r2=95683&view=diff

==============================================================================
--- cfe/trunk/include/clang/Driver/CC1Options.td (original)
+++ cfe/trunk/include/clang/Driver/CC1Options.td Tue Feb  9 13:21:46 2010
@@ -200,6 +200,9 @@
 // CompilerInvocation out of a driver-derived argument vector.
 def cc1 : Flag<"-cc1">;
 
+def ast_merge : Separate<"-ast-merge">,
+  MetaVarName<"<ast file>">,
+  HelpText<"Merge the given AST file into the translation unit being compiled.">;
 def code_completion_at : Separate<"-code-completion-at">,
   MetaVarName<"<file>:<line>:<column>">,
   HelpText<"Dump code-completion information at a location">;

Modified: cfe/trunk/include/clang/Frontend/FrontendAction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendAction.h?rev=95683&r1=95682&r2=95683&view=diff

==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendAction.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendAction.h Tue Feb  9 13:21:46 2010
@@ -18,6 +18,7 @@
 class ASTUnit;
 class ASTConsumer;
 class CompilerInstance;
+class ASTMergeAction;
 
 /// FrontendAction - Abstract base class for actions which can be performed by
 /// the frontend.
@@ -25,6 +26,7 @@
   std::string CurrentFile;
   llvm::OwningPtr<ASTUnit> CurrentASTUnit;
   CompilerInstance *Instance;
+  friend class ASTMergeAction;
 
 protected:
   /// @name Implementation Action Interface
@@ -104,6 +106,10 @@
     return *CurrentASTUnit;
   }
 
+  ASTUnit *takeCurrentASTUnit() {
+    return CurrentASTUnit.take();
+  }
+
   void setCurrentFile(llvm::StringRef Value, ASTUnit *AST = 0);
 
   /// @}

Modified: cfe/trunk/include/clang/Frontend/FrontendActions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendActions.h?rev=95683&r1=95682&r2=95683&view=diff

==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendActions.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendActions.h Tue Feb  9 13:21:46 2010
@@ -11,6 +11,8 @@
 #define LLVM_CLANG_FRONTEND_FRONTENDACTIONS_H
 
 #include "clang/Frontend/FrontendAction.h"
+#include <string>
+#include <vector>
 
 namespace clang {
 class FixItRewriter;
@@ -119,6 +121,43 @@
   virtual bool hasCodeCompletionSupport() const { return true; }
 };
 
+/**
+ * \brief Frontend action adaptor that merges ASTs together.
+ *
+ * This action takes an existing AST file and "merges" it into the AST
+ * context, producing a merged context. This action is an action
+ * adaptor, which forwards most of its calls to another action that
+ * will consume the merged context.
+ */
+class ASTMergeAction : public FrontendAction {
+  /// \brief The action that the merge action adapts.
+  FrontendAction *AdaptedAction;
+  
+  /// \brief The set of AST files to merge.
+  std::vector<std::string> ASTFiles;
+
+protected:
+  virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+                                         llvm::StringRef InFile);
+
+  virtual bool BeginSourceFileAction(CompilerInstance &CI,
+                                     llvm::StringRef Filename);
+
+  virtual void ExecuteAction();
+  virtual void EndSourceFileAction();
+
+public:
+  ASTMergeAction(FrontendAction *AdaptedAction,
+                 std::string *ASTFiles, unsigned NumASTFiles);
+  virtual ~ASTMergeAction();
+
+  virtual bool usesPreprocessorOnly() const;
+  virtual bool usesCompleteTranslationUnit();
+  virtual bool hasPCHSupport() const;
+  virtual bool hasASTSupport() const;
+  virtual bool hasCodeCompletionSupport() const;
+};
+
 //===----------------------------------------------------------------------===//
 // Code Gen AST Actions
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/include/clang/Frontend/FrontendOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendOptions.h?rev=95683&r1=95682&r2=95683&view=diff

==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendOptions.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendOptions.h Tue Feb  9 13:21:46 2010
@@ -110,6 +110,9 @@
   /// The list of plugins to load.
   std::vector<std::string> Plugins;
 
+  /// \brief The list of AST files to merge.
+  std::vector<std::string> ASTMergeFiles;
+
 public:
   FrontendOptions() {
     DebugCodeCompletionPrinter = 1;

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=95683&r1=95682&r2=95683&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Tue Feb  9 13:21:46 2010
@@ -30,6 +30,7 @@
     explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) { }
     
     using TypeVisitor<ASTNodeImporter, QualType>::Visit;
+    using DeclVisitor<ASTNodeImporter, Decl *>::Visit;
 
     // Importing types
     QualType VisitBuiltinType(BuiltinType *T);
@@ -440,6 +441,13 @@
   if (!DC)
     return 0;
     
+  DeclContext *LexicalDC = DC;
+  if (D->getDeclContext() != D->getLexicalDeclContext()) {
+    LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
+    if (!LexicalDC)
+      return 0;
+  }
+
   // Import the name of this declaration.
   DeclarationName Name = Importer.Import(D->getDeclName());
   if (D->getDeclName() && !Name)
@@ -455,11 +463,11 @@
   
   // Try to find a variable in our own ("to") context with the same name and
   // in the same context as the variable we're importing.
-  if (!D->isFileVarDecl()) {
+  if (D->isFileVarDecl()) {
     VarDecl *MergeWithVar = 0;
     llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
     unsigned IDNS = Decl::IDNS_Ordinary;
-    for (DeclContext::lookup_result Lookup = DC->lookup(D->getDeclName());
+    for (DeclContext::lookup_result Lookup = DC->lookup(Name);
          Lookup.first != Lookup.second; 
          ++Lookup.first) {
       if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
@@ -517,16 +525,22 @@
   TypeSourceInfo *TInfo = 0;
   if (TypeSourceInfo *FromTInfo = D->getTypeSourceInfo()) {
     TInfo = Importer.Import(FromTInfo);
+#if 0
+    // FIXME: Tolerate failures in translation type source
+    // information, at least until it is implemented.
     if (!TInfo)
       return 0;
+#endif
   }
   
   // Create the imported variable.
   VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc, 
                                    Name.getAsIdentifierInfo(), T, TInfo,
                                    D->getStorageClass());
+  ToVar->setLexicalDeclContext(LexicalDC);
   Importer.getImportedDecls()[D] = ToVar;
-  
+  LexicalDC->addDecl(ToVar);
+
   // Merge the initializer.
   // FIXME: Can we really import any initializer? Alternatively, we could force
   // ourselves to import every declaration of a variable and then only use
@@ -542,7 +556,12 @@
 ASTImporter::ASTImporter(ASTContext &ToContext, Diagnostic &ToDiags,
                          ASTContext &FromContext, Diagnostic &FromDiags)
   : ToContext(ToContext), FromContext(FromContext),
-    ToDiags(ToDiags), FromDiags(FromDiags) { }
+    ToDiags(ToDiags), FromDiags(FromDiags) { 
+  ImportedDecls[FromContext.getTranslationUnitDecl()]
+    = ToContext.getTranslationUnitDecl();
+}
+
+ASTImporter::~ASTImporter() { }
 
 QualType ASTImporter::Import(QualType FromT) {
   if (FromT.isNull())
@@ -566,6 +585,73 @@
   return ToContext.getQualifiedType(ToT, FromT.getQualifiers());
 }
 
+TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) {
+  // FIXME: Implement!
+  return 0;
+}
+
+Decl *ASTImporter::Import(Decl *FromD) {
+  if (!FromD)
+    return 0;
+
+  // Check whether we've already imported this declaration.  
+  llvm::DenseMap<Decl *, Decl *>::iterator Pos = ImportedDecls.find(FromD);
+  if (Pos != ImportedDecls.end())
+    return Pos->second;
+  
+  // Import the type
+  ASTNodeImporter Importer(*this);
+  Decl *ToD = Importer.Visit(FromD);
+  if (!ToD)
+    return 0;
+  
+  // Record the imported declaration.
+  ImportedDecls[FromD] = ToD;
+  return ToD;
+}
+
+DeclContext *ASTImporter::ImportContext(DeclContext *FromDC) {
+  if (!FromDC)
+    return FromDC;
+
+  return cast_or_null<DeclContext>(Import(cast<Decl>(FromDC)));
+}
+
+Expr *ASTImporter::Import(Expr *FromE) {
+  if (!FromE)
+    return 0;
+
+  return cast_or_null<Expr>(Import(cast<Stmt>(FromE)));
+}
+
+Stmt *ASTImporter::Import(Stmt *FromS) {
+  if (!FromS)
+    return 0;
+
+  // FIXME: Implement!
+  return 0;
+}
+
+NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) {
+  if (!FromNNS)
+    return 0;
+
+  // FIXME: Implement!
+  return 0;
+}
+
+SourceLocation ASTImporter::Import(SourceLocation FromLoc) {
+  if (FromLoc.isInvalid())
+    return SourceLocation();
+
+  // FIXME: Implement!
+  return SourceLocation();
+}
+
+SourceRange ASTImporter::Import(SourceRange FromRange) {
+  return SourceRange(Import(FromRange.getBegin()), Import(FromRange.getEnd()));
+}
+
 DeclarationName ASTImporter::Import(DeclarationName FromName) {
   if (!FromName)
     return DeclarationName();

Added: cfe/trunk/lib/Frontend/ASTMerge.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ASTMerge.cpp?rev=95683&view=auto

==============================================================================
--- cfe/trunk/lib/Frontend/ASTMerge.cpp (added)
+++ cfe/trunk/lib/Frontend/ASTMerge.cpp Tue Feb  9 13:21:46 2010
@@ -0,0 +1,98 @@
+//===-- ASTMerge.cpp - AST Merging Frontent Action --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTImporter.h"
+
+using namespace clang;
+
+ASTConsumer *ASTMergeAction::CreateASTConsumer(CompilerInstance &CI,
+                                               llvm::StringRef InFile) {
+  return AdaptedAction->CreateASTConsumer(CI, InFile);
+}
+
+bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI,
+                                           llvm::StringRef Filename) {
+  // FIXME: This is a hack. We need a better way to communicate the
+  // AST file, compiler instance, and file name than member variables
+  // of FrontendAction.
+  AdaptedAction->setCurrentFile(getCurrentFile(), takeCurrentASTUnit());
+  AdaptedAction->setCompilerInstance(&CI);
+  return AdaptedAction->BeginSourceFileAction(CI, Filename);
+}
+
+void ASTMergeAction::ExecuteAction() {
+  CompilerInstance &CI = getCompilerInstance();
+
+  for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) {
+    ASTUnit *Unit = ASTUnit::LoadFromPCHFile(ASTFiles[I], CI.getDiagnostics(),
+                                             false, true);
+    if (!Unit)
+      continue;
+
+    ASTImporter Importer(CI.getASTContext(), CI.getDiagnostics(),
+                         Unit->getASTContext(), CI.getDiagnostics());
+
+    TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
+    for (DeclContext::decl_iterator D = TU->decls_begin(), 
+                                 DEnd = TU->decls_end();
+         D != DEnd; ++D) {
+      // FIXME: We only merge variables whose names start with x. Why
+      // would anyone want anything else?
+      if (VarDecl *VD = dyn_cast<VarDecl>(*D))
+        if (VD->getIdentifier() && 
+            *VD->getIdentifier()->getNameStart() == 'x') {
+          Decl *Merged = Importer.Import(VD);
+          if (Merged)
+            Merged->dump();
+        }
+    }
+
+    delete Unit;
+  }
+
+
+  return AdaptedAction->ExecuteAction();
+}
+
+void ASTMergeAction::EndSourceFileAction() {
+  return AdaptedAction->EndSourceFileAction();
+}
+
+ASTMergeAction::ASTMergeAction(FrontendAction *AdaptedAction,
+                               std::string *ASTFiles, unsigned NumASTFiles)
+  : AdaptedAction(AdaptedAction), ASTFiles(ASTFiles, ASTFiles + NumASTFiles) {
+  assert(AdaptedAction && "ASTMergeAction needs an action to adapt");
+}
+
+ASTMergeAction::~ASTMergeAction() { 
+  delete AdaptedAction;
+}
+
+bool ASTMergeAction::usesPreprocessorOnly() const {
+  return AdaptedAction->usesPreprocessorOnly();
+}
+
+bool ASTMergeAction::usesCompleteTranslationUnit() {
+  return AdaptedAction->usesCompleteTranslationUnit();
+}
+
+bool ASTMergeAction::hasPCHSupport() const {
+  return AdaptedAction->hasPCHSupport();
+}
+
+bool ASTMergeAction::hasASTSupport() const {
+  return AdaptedAction->hasASTSupport();
+}
+
+bool ASTMergeAction::hasCodeCompletionSupport() const {
+  return AdaptedAction->hasCodeCompletionSupport();
+}

Propchange: cfe/trunk/lib/Frontend/ASTMerge.cpp

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/lib/Frontend/ASTMerge.cpp

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/lib/Frontend/ASTMerge.cpp

------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/lib/Frontend/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CMakeLists.txt?rev=95683&r1=95682&r2=95683&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/CMakeLists.txt (original)
+++ cfe/trunk/lib/Frontend/CMakeLists.txt Tue Feb  9 13:21:46 2010
@@ -2,6 +2,7 @@
 
 add_clang_library(clangFrontend
   ASTConsumers.cpp
+  ASTMerge.cpp
   ASTUnit.cpp
   AnalysisConsumer.cpp
   Backend.cpp

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=95683&r1=95682&r2=95683&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Tue Feb  9 13:21:46 2010
@@ -367,6 +367,10 @@
     Res.push_back("-load");
     Res.push_back(Opts.Plugins[i]);
   }
+  for (unsigned i = 0, e = Opts.ASTMergeFiles.size(); i != e; ++i) {
+    Res.push_back("-ast-merge");
+    Res.push_back(Opts.ASTMergeFiles[i]);
+  }
 }
 
 static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
@@ -929,6 +933,7 @@
   Opts.ShowTimers = Args.hasArg(OPT_ftime_report);
   Opts.ShowVersion = Args.hasArg(OPT_version);
   Opts.ViewClassInheritance = getLastArgValue(Args, OPT_cxx_inheritance_view);
+  Opts.ASTMergeFiles = getAllArgValues(Args, OPT_ast_merge);
 
   FrontendOptions::InputKind DashX = FrontendOptions::IK_None;
   if (const Arg *A = Args.getLastArg(OPT_x)) {

Added: cfe/trunk/test/ASTMerge/Inputs/var1.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/var1.c?rev=95683&view=auto

==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/var1.c (added)
+++ cfe/trunk/test/ASTMerge/Inputs/var1.c Tue Feb  9 13:21:46 2010
@@ -0,0 +1,3 @@
+// RUN: true
+int *x0;
+float **x1;

Propchange: cfe/trunk/test/ASTMerge/Inputs/var1.c

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/ASTMerge/Inputs/var1.c

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/ASTMerge/Inputs/var1.c

------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/ASTMerge/Inputs/var2.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/var2.c?rev=95683&view=auto

==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/var2.c (added)
+++ cfe/trunk/test/ASTMerge/Inputs/var2.c Tue Feb  9 13:21:46 2010
@@ -0,0 +1,3 @@
+// RUN: true
+int *x0;
+double *x1;

Propchange: cfe/trunk/test/ASTMerge/Inputs/var2.c

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/ASTMerge/Inputs/var2.c

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/ASTMerge/Inputs/var2.c

------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/ASTMerge/var.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/var.c?rev=95683&view=auto

==============================================================================
--- cfe/trunk/test/ASTMerge/var.c (added)
+++ cfe/trunk/test/ASTMerge/var.c Tue Feb  9 13:21:46 2010
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/var1.c
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/var2.c
+// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+
+// CHECK: declared with incompatible types

Propchange: cfe/trunk/test/ASTMerge/var.c

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/ASTMerge/var.c

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/ASTMerge/var.c

------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/tools/driver/cc1_main.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/driver/cc1_main.cpp?rev=95683&r1=95682&r2=95683&view=diff

==============================================================================
--- cfe/trunk/tools/driver/cc1_main.cpp (original)
+++ cfe/trunk/tools/driver/cc1_main.cpp Tue Feb  9 13:21:46 2010
@@ -51,7 +51,7 @@
   exit(1);
 }
 
-static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
+static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
   using namespace clang::frontend;
 
   switch (CI.getFrontendOpts().ProgramAction) {
@@ -112,6 +112,21 @@
   }
 }
 
+static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
+  // Create the underlying action.
+  FrontendAction *Act = CreateFrontendBaseAction(CI);
+  if (!Act)
+    return 0;
+
+  // If there are any AST files to merge, create a frontend action
+  // adaptor to perform the merge.
+  if (!CI.getFrontendOpts().ASTMergeFiles.empty())
+    Act = new ASTMergeAction(Act, &CI.getFrontendOpts().ASTMergeFiles[0],
+                             CI.getFrontendOpts().ASTMergeFiles.size());
+
+  return Act;
+}
+
 // FIXME: Define the need for this testing away.
 static int cc1_test(Diagnostic &Diags,
                     const char **ArgBegin, const char **ArgEnd) {





More information about the cfe-commits mailing list