]> granicus.if.org Git - clang/commitdiff
Implement basic support for importing source locations from one AST
authorDouglas Gregor <dgregor@apple.com>
Wed, 10 Feb 2010 00:15:17 +0000 (00:15 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 10 Feb 2010 00:15:17 +0000 (00:15 +0000)
into another AST, including their include history. Here's an example
error that involves a conflict merging a variable with different types
in two translation units (diagnosed in the third AST context into
which everything is merged).

/Volumes/Data/dgregor/Projects/llvm/tools/clang/test/ASTMerge/Inputs/var2.c:3:5:
error: external variable 'x2' declared with incompatible types in
different translation units ('int' vs. 'double')
int x2;
    ^
In file included from
/Volumes/Data/dgregor/Projects/llvm/tools/clang/test/ASTMerge/Inputs/var1.c:3:
/Volumes/Data/dgregor/Projects/llvm/tools/clang/test/ASTMerge/Inputs/var1.h:1:8:
note: declared here with type 'double'
double x2;
       ^

Although we maintain include history, we do not maintain macro
instantiation history across a merge. Instead, we map down to the
spelling location (for now!).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95732 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ASTImporter.h
lib/AST/ASTImporter.cpp
lib/Frontend/ASTMerge.cpp
test/ASTMerge/Inputs/var1.c
test/ASTMerge/Inputs/var2.c
test/ASTMerge/var.c

index 71b6443f50220c544e6738a4e5b9c0323e7350cb..bdc1a51e98bfa246a2803a927ee2407921e13b0b 100644 (file)
@@ -25,6 +25,7 @@ namespace clang {
   class DeclContext;
   class Diagnostic;
   class Expr;
+  class FileManager;
   class IdentifierInfo;
   class NestedNameSpecifier;
   class Stmt;
@@ -36,6 +37,9 @@ namespace clang {
     /// \brief The contexts we're importing to and from.
     ASTContext &ToContext, &FromContext;
     
+    /// \brief The file managers we're importing to and from.
+    FileManager &ToFileManager, &FromFileManager;
+    
     /// \brief The diagnostics object that we should use to emit diagnostics
     /// within the context we're importing to and from.
     Diagnostic &ToDiags, &FromDiags;
@@ -48,9 +52,15 @@ namespace clang {
     /// context to the corresponding declarations in the "to" context.
     llvm::DenseMap<Decl *, Decl *> ImportedDecls;
     
+    /// \brief Mapping from the already-imported FileIDs in the "from" source
+    /// manager to the corresponding FileIDs in the "to" source manager.
+    llvm::DenseMap<unsigned, FileID> ImportedFileIDs;
+    
   public:
-    ASTImporter(ASTContext &ToContext, Diagnostic &ToDiags,
-                ASTContext &FromContext, Diagnostic &FromDiags);
+    ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
+                Diagnostic &ToDiags,
+                ASTContext &FromContext, FileManager &FromFileManager,
+                Diagnostic &FromDiags);
     
     virtual ~ASTImporter();
     
@@ -102,7 +112,7 @@ namespace clang {
     /// \returns the equivalent nested-name-specifier in the "to"
     /// context, or NULL if an error occurred.
     NestedNameSpecifier *Import(NestedNameSpecifier *FromNNS);
-
+    
     /// \brief Import the given source location from the "from" context into
     /// the "to" context.
     ///
@@ -130,6 +140,13 @@ namespace clang {
     /// \returns the equivalent identifier in the "to" context.
     IdentifierInfo *Import(IdentifierInfo *FromId);
 
+    /// \brief Import the given file ID from the "from" context into the 
+    /// "to" context.
+    ///
+    /// \returns the equivalent file ID in the source manager of the "to"
+    /// context.
+    FileID Import(FileID);
+    
     /// \brief Cope with a name conflict when importing a declaration into the
     /// given context.
     ///
@@ -168,6 +185,12 @@ namespace clang {
     /// \brief Retrieve the context that AST nodes are being imported from.
     ASTContext &getFromContext() const { return FromContext; }
     
+    /// \brief Retrieve the file manager that AST nodes are being imported into.
+    FileManager &getToFileManager() const { return ToFileManager; }
+
+    /// \brief Retrieve the file manager that AST nodes are being imported from.
+    FileManager &getFromFileManager() const { return FromFileManager; }
+
     /// \brief Retrieve the diagnostics object to use to report errors within
     /// the context we're importing into.
     Diagnostic &getToDiags() const { return ToDiags; }
index 19ce88951367e04c7da6a2561c0280969bcd28f1..75917cf04c8a431b16280ca343494a06a25ee8b3 100644 (file)
 #include "clang/AST/ASTImporter.h"
 
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclVisitor.h"
 #include "clang/AST/TypeVisitor.h"
-#include "clang/AST/ASTDiagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/MemoryBuffer.h"
 
 using namespace clang;
 
@@ -444,7 +447,7 @@ QualType ASTNodeImporter::VisitObjCObjectPointerType(ObjCObjectPointerType *T) {
 // Import Declarations
 //----------------------------------------------------------------------------
 Decl *ASTNodeImporter::VisitDecl(Decl *D) {
-  Importer.FromDiag(SourceLocation(), diag::err_unsupported_ast_node)
+  Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node)
     << D->getDeclKindName();
   return 0;
 }
@@ -567,9 +570,12 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
   return ToVar;
 }
 
-ASTImporter::ASTImporter(ASTContext &ToContext, Diagnostic &ToDiags,
-                         ASTContext &FromContext, Diagnostic &FromDiags)
+ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
+                         Diagnostic &ToDiags,
+                         ASTContext &FromContext, FileManager &FromFileManager,
+                         Diagnostic &FromDiags)
   : ToContext(ToContext), FromContext(FromContext),
+    ToFileManager(ToFileManager), FromFileManager(FromFileManager),
     ToDiags(ToDiags), FromDiags(FromDiags) { 
   ImportedDecls[FromContext.getTranslationUnitDecl()]
     = ToContext.getTranslationUnitDecl();
@@ -658,14 +664,62 @@ SourceLocation ASTImporter::Import(SourceLocation FromLoc) {
   if (FromLoc.isInvalid())
     return SourceLocation();
 
-  // FIXME: Implement!
-  return SourceLocation();
+  SourceManager &FromSM = FromContext.getSourceManager();
+  
+  // For now, map everything down to its spelling location, so that we
+  // don't have to import macro instantiations.
+  // FIXME: Import macro instantiations!
+  FromLoc = FromSM.getSpellingLoc(FromLoc);
+  std::pair<FileID, unsigned> Decomposed = FromSM.getDecomposedLoc(FromLoc);
+  SourceManager &ToSM = ToContext.getSourceManager();
+  return ToSM.getLocForStartOfFile(Import(Decomposed.first))
+             .getFileLocWithOffset(Decomposed.second);
 }
 
 SourceRange ASTImporter::Import(SourceRange FromRange) {
   return SourceRange(Import(FromRange.getBegin()), Import(FromRange.getEnd()));
 }
 
+FileID ASTImporter::Import(FileID FromID) {
+  llvm::DenseMap<unsigned, FileID>::iterator Pos
+    = ImportedFileIDs.find(FromID.getHashValue());
+  if (Pos != ImportedFileIDs.end())
+    return Pos->second;
+  
+  SourceManager &FromSM = FromContext.getSourceManager();
+  SourceManager &ToSM = ToContext.getSourceManager();
+  const SrcMgr::SLocEntry &FromSLoc = FromSM.getSLocEntry(FromID);
+  assert(FromSLoc.isFile() && "Cannot handle macro instantiations yet");
+  
+  // Include location of this file.
+  SourceLocation ToIncludeLoc = Import(FromSLoc.getFile().getIncludeLoc());
+  
+  // Map the FileID for to the "to" source manager.
+  FileID ToID;
+  const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache();
+  if (Cache->Entry) {
+    // FIXME: We probably want to use getVirtualFile(), so we don't hit the
+    // disk again
+    // FIXME: We definitely want to re-use the existing MemoryBuffer, rather
+    // than mmap the files several times.
+    const FileEntry *Entry = ToFileManager.getFile(Cache->Entry->getName());
+    ToID = ToSM.createFileID(Entry, ToIncludeLoc, 
+                             FromSLoc.getFile().getFileCharacteristic());
+  } else {
+    // FIXME: We want to re-use the existing MemoryBuffer!
+    const llvm::MemoryBuffer *FromBuf = Cache->getBuffer();
+    llvm::MemoryBuffer *ToBuf
+      = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBufferStart(),
+                                             FromBuf->getBufferEnd(),
+                                             FromBuf->getBufferIdentifier());
+    ToID = ToSM.createFileIDForMemBuffer(ToBuf);
+  }
+  
+  
+  ImportedFileIDs[FromID.getHashValue()] = ToID;
+  return ToID;
+}
+
 DeclarationName ASTImporter::Import(DeclarationName FromName) {
   if (!FromName)
     return DeclarationName();
index e88d2953c3d53b865c0acd4b865709dc49150827..d51647bb161d03ddf109028f2c3a70ee2d59df9b 100644 (file)
@@ -44,8 +44,12 @@ void ASTMergeAction::ExecuteAction() {
 
     ASTDiags.SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
                               &Unit->getASTContext());
-    ASTImporter Importer(CI.getASTContext(), CI.getDiagnostics(),
-                         Unit->getASTContext(), ASTDiags);
+    ASTImporter Importer(CI.getASTContext(), 
+                         CI.getFileManager(),
+                         CI.getDiagnostics(),
+                         Unit->getASTContext(), 
+                         Unit->getFileManager(),
+                         ASTDiags);
 
     TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
     for (DeclContext::decl_iterator D = TU->decls_begin(), 
index c87e58b6ad9ec2e2ae327fd7f6db4b5c65d57220..465258988b015f8d428bdfb76c538c07bf31d5d5 100644 (file)
@@ -1,2 +1,3 @@
 int *x0;
 float **x1;
+#include "var1.h"
index 526a45b9f7c5b51dd3e5a486d314791ec9f5a013..e93a010cbfea2383506dbfe594115fbd46186fff 100644 (file)
@@ -1,2 +1,3 @@
 int *x0;
 double *x1;
+int x2;
index 4fda4acb9dc02570c669e735004f470d04017016..98ad7ab4a0794e6b647c76558158cdb296647419 100644 (file)
@@ -2,4 +2,8 @@
 // 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: error: external variable 'x1' declared with incompatible types in different translation units ('double *' vs. 'float **')
+// CHECK: var2.c:2:9: error: external variable 'x1' declared with incompatible types in different translation units ('double *' vs. 'float **')
+// CHECK: var1.c:2:9: note: declared here with type 'float **'
+// CHECK: var2.c:3:5: error: external variable 'x2' declared with incompatible types in different translation units ('int' vs. 'double')
+// CHECK: In file included from{{.*}}var1.c:3:
+// CHECK: var1.h:1:8: note: declared here with type 'double'