[cfe-commits] r98836 - in /cfe/trunk: include/clang/Frontend/ASTUnit.h include/clang/Lex/PreprocessingRecord.h lib/Frontend/ASTUnit.cpp lib/Lex/CMakeLists.txt lib/Lex/PreprocessingRecord.cpp test/Index/annotate-tokens-pp.c tools/CIndex/CIndex.cpp tools/CIndex/CXCursor.cpp tools/CIndex/CXCursor.h

Douglas Gregor dgregor at apple.com
Thu Mar 18 10:52:53 PDT 2010


Author: dgregor
Date: Thu Mar 18 12:52:52 2010
New Revision: 98836

URL: http://llvm.org/viewvc/llvm-project?rev=98836&view=rev
Log:
Introduce the notion of a "preprocessing record", which keeps track of
the macro definitions and macro instantiations that are found
during preprocessing. Preprocessing records are *not* generated by
default; rather, we provide a PPCallbacks subclass that hooks into the
existing callback mechanism to record this activity.

The only client of preprocessing records is CIndex, which keeps track
of macro definitions and instantations so that they can be exposed via
cursors. At present, only token annotation uses these facilities, and
only for macro instantiations; both will change in the near
future. However, with this change, token annotation properly annotates
macro instantiations that do not produce any tokens and instantiations
of macros that are later undef'd, improving our consistency.

Preprocessing directives that are not macro definitions are still
handled by clang_annotateTokens() via re-lexing, so that we don't have
to track every preprocessing directive in the preprocessing record.

Performance impact of preprocessing records is still TBD, although it
is limited to CIndex and therefore out of the path of the main compiler.

Added:
    cfe/trunk/include/clang/Lex/PreprocessingRecord.h   (with props)
    cfe/trunk/lib/Lex/PreprocessingRecord.cpp   (with props)
Modified:
    cfe/trunk/include/clang/Frontend/ASTUnit.h
    cfe/trunk/lib/Frontend/ASTUnit.cpp
    cfe/trunk/lib/Lex/CMakeLists.txt
    cfe/trunk/test/Index/annotate-tokens-pp.c
    cfe/trunk/tools/CIndex/CIndex.cpp
    cfe/trunk/tools/CIndex/CXCursor.cpp
    cfe/trunk/tools/CIndex/CXCursor.h

Modified: cfe/trunk/include/clang/Frontend/ASTUnit.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/ASTUnit.h?rev=98836&r1=98835&r2=98836&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/ASTUnit.h (original)
+++ cfe/trunk/include/clang/Frontend/ASTUnit.h Thu Mar 18 12:52:52 2010
@@ -14,6 +14,7 @@
 #ifndef LLVM_CLANG_FRONTEND_ASTUNIT_H
 #define LLVM_CLANG_FRONTEND_ASTUNIT_H
 
+#include "clang/Lex/PreprocessingRecord.h"
 #include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/OwningPtr.h"
 #include "clang/Basic/FileManager.h"
@@ -53,7 +54,8 @@
   llvm::OwningPtr<TargetInfo>       Target;
   llvm::OwningPtr<Preprocessor>     PP;
   llvm::OwningPtr<ASTContext>       Ctx;
-
+  llvm::OwningPtr<PreprocessingRecord> Preprocessing;
+  
   /// Optional owned invocation, just used to make the invocation used in
   /// LoadFromCommandLine available.
   llvm::OwningPtr<CompilerInvocation> Invocation;
@@ -135,6 +137,12 @@
   const ASTContext &getASTContext() const { return *Ctx.get(); }
         ASTContext &getASTContext()       { return *Ctx.get(); }
 
+  const PreprocessingRecord &getPreprocessingRecord() const { 
+    return *Preprocessing.get(); 
+  }
+  PreprocessingRecord &getPreprocessingRecord() { return *Preprocessing.get(); }
+  bool hasPreprocessingRecord() { return Preprocessing.get() != 0; }
+    
   const FileManager &getFileManager() const { return FileMgr; }
         FileManager &getFileManager()       { return FileMgr; }
 
@@ -204,7 +212,8 @@
   static ASTUnit *LoadFromCompilerInvocation(CompilerInvocation *CI,
                                              Diagnostic &Diags,
                                              bool OnlyLocalDecls = false,
-                                             bool CaptureDiagnostics = false);
+                                             bool CaptureDiagnostics = false,
+                                         bool WantPreprocessingRecord = false);
 
   /// LoadFromCommandLine - Create an ASTUnit from a vector of command line
   /// arguments, which must specify exactly one source file.
@@ -227,7 +236,8 @@
                                       bool OnlyLocalDecls = false,
                                       RemappedFile *RemappedFiles = 0,
                                       unsigned NumRemappedFiles = 0,
-                                      bool CaptureDiagnostics = false);
+                                      bool CaptureDiagnostics = false,
+                                      bool WantPreprocessingRecord = false);
 };
 
 } // namespace clang

Added: cfe/trunk/include/clang/Lex/PreprocessingRecord.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/PreprocessingRecord.h?rev=98836&view=auto
==============================================================================
--- cfe/trunk/include/clang/Lex/PreprocessingRecord.h (added)
+++ cfe/trunk/include/clang/Lex/PreprocessingRecord.h Thu Mar 18 12:52:52 2010
@@ -0,0 +1,235 @@
+//===--- PreprocessingRecord.h - Record of Preprocessing --------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the PreprocessingRecord class, which maintains a record
+//  of what occurred during preprocessing.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_LEX_PREPROCESSINGRECORD_H
+#define LLVM_CLANG_LEX_PREPROCESSINGRECORD_H
+
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/Support/Allocator.h"
+#include <vector>
+
+namespace clang {
+  class IdentifierInfo;
+  class PreprocessingRecord;
+}
+
+/// \brief Allocates memory within a Clang preprocessing record.
+void* operator new(size_t bytes, clang::PreprocessingRecord& PR,
+                   unsigned alignment = 8) throw();
+
+/// \brief Frees memory allocated in a Clang preprocessing record.
+void operator delete(void* ptr, clang::PreprocessingRecord& PR,
+                     unsigned) throw();
+
+namespace clang {
+  /// \brief Base class that describes a preprocessed entity, which may be a
+  /// preprocessor directive or macro instantiation.
+  class PreprocessedEntity {
+  public:
+    /// \brief The kind of preprocessed entity an object describes.
+    enum EntityKind {
+      /// \brief A macro instantiation.
+      MacroInstantiationKind,
+      
+      /// \brief A preprocessing directive whose kind is not specified.
+      ///
+      /// This kind will be used for any preprocessing directive that does not
+      /// have a more specific kind within the \c DirectiveKind enumeration.
+      PreprocessingDirectiveKind,
+      
+      /// \brief A macro definition.
+      MacroDefinitionKind,
+      
+      FirstPreprocessingDirective = PreprocessingDirectiveKind,
+      LastPreprocessingDirective = MacroDefinitionKind
+    };
+
+  private:
+    /// \brief The kind of preprocessed entity that this object describes.
+    EntityKind Kind;
+    
+    /// \brief The source range that covers this preprocessed entity.
+    SourceRange Range;
+    
+  protected:
+    PreprocessedEntity(EntityKind Kind, SourceRange Range)
+      : Kind(Kind), Range(Range) { }
+    
+  public:
+    /// \brief Retrieve the kind of preprocessed entity stored in this object.
+    EntityKind getKind() const { return Kind; }
+    
+    /// \brief Retrieve the source range that covers this entire preprocessed 
+    /// entity.
+    SourceRange getSourceRange() const { return Range; }
+    
+    // Implement isa/cast/dyncast/etc.
+    static bool classof(const PreprocessedEntity *) { return true; }
+
+    // Only allow allocation of preprocessed entities using the allocator 
+    // in PreprocessingRecord or by doing a placement new.
+    void* operator new(size_t bytes, PreprocessingRecord& PR,
+                       unsigned alignment = 8) throw() {
+      return ::operator new(bytes, PR, alignment);
+    }
+    
+    void* operator new(size_t bytes, void* mem) throw() {
+      return mem;
+    }
+    
+    void operator delete(void* ptr, PreprocessingRecord& PR, 
+                         unsigned alignment) throw() {
+      return ::operator delete(ptr, PR, alignment);
+    }
+    
+    void operator delete(void*, std::size_t) throw() { }
+    void operator delete(void*, void*) throw() { }
+    
+  private:
+    // Make vanilla 'new' and 'delete' illegal for preprocessed entities.
+    void* operator new(size_t bytes) throw();
+    void operator delete(void* data) throw();
+  };
+  
+  /// \brief Records the location of a macro instantiation.
+  class MacroInstantiation : public PreprocessedEntity {
+    /// \brief The name of the macro being instantiation.
+    IdentifierInfo *Name;
+    
+    /// \brief The location of the definition of the macro being instantiated.
+    SourceLocation DefinitionLocation;
+    
+  public:
+    MacroInstantiation(IdentifierInfo *Name, SourceRange Range,
+                       SourceLocation DefinitionLocation)
+      : PreprocessedEntity(MacroInstantiationKind, Range), Name(Name), 
+        DefinitionLocation(DefinitionLocation) { }
+    
+    /// \brief The name of the macro being instantiated.
+    IdentifierInfo *getName() const { return Name; }
+    
+    /// \brief The location of the definition of the macro being instantiated.
+    /// FIXME: Could we just provide MacroInfo pointers instead, by teaching
+    /// the preprocessor to hold on to them when we care to keep them around?
+    SourceLocation getDefinitionLocation() const { return DefinitionLocation; }
+
+    // Implement isa/cast/dyncast/etc.
+    static bool classof(const PreprocessedEntity *PE) {
+      return PE->getKind() == MacroInstantiationKind;
+    }
+    static bool classof(const MacroInstantiation *) { return true; }
+
+  };
+  
+  /// \brief Records the presence of a preprocessor directive.
+  class PreprocessingDirective : public PreprocessedEntity {
+  public:
+    PreprocessingDirective(EntityKind Kind, SourceRange Range) 
+      : PreprocessedEntity(Kind, Range) { }
+    
+    // Implement isa/cast/dyncast/etc.
+    static bool classof(const PreprocessedEntity *PD) { 
+      return PD->getKind() >= FirstPreprocessingDirective &&
+             PD->getKind() <= LastPreprocessingDirective;
+    }
+    static bool classof(const PreprocessingDirective *) { return true; }    
+  };
+  
+  /// \brief Record the location of a macro definition.
+  class MacroDefinition : public PreprocessingDirective {
+    /// \brief The name of the macro being defined.
+    const IdentifierInfo *Name;
+    
+    /// \brief The location of the macro name in the macro definition.
+    SourceLocation Location;
+
+  public:
+    explicit MacroDefinition(const IdentifierInfo *Name, SourceLocation Location,
+                             SourceRange Range)
+      : PreprocessingDirective(MacroDefinitionKind, Range), Name(Name), 
+        Location(Location) { }
+    
+    /// \brief Retrieve the name of the macro being defined.
+    const IdentifierInfo *getMacroName() const { return Name; }
+    
+    /// \brief Retrieve the location of the macro name in the definition.
+    SourceLocation getLocation() const { return Location; }
+    
+    // Implement isa/cast/dyncast/etc.
+    static bool classof(const PreprocessingDirective *PD) {
+      return PD->getKind() == MacroDefinitionKind;
+    }
+    static bool classof(const MacroDefinition *) { return true; }
+  };
+    
+  /// \brief A record of the steps taken while preprocessing a source file,
+  /// including the various preprocessing directives processed, macros 
+  /// instantiated, etc.
+  class PreprocessingRecord {
+    /// \brief Allocator used to store preprocessing objects.
+    llvm::BumpPtrAllocator BumpAlloc;
+
+    /// \brief The set of preprocessed entities in this record, in order they
+    /// were seen.
+    std::vector<PreprocessedEntity *> PreprocessedEntities;
+    
+  public:
+    /// \brief Allocate memory in the preprocessing record.
+    void *Allocate(unsigned Size, unsigned Align = 8) {
+      return BumpAlloc.Allocate(Size, Align);
+    }
+    
+    /// \brief Deallocate memory in the preprocessing record.
+    void Deallocate(void *Ptr) { }
+    
+    // Iteration over the preprocessed entities.
+    typedef std::vector<PreprocessedEntity *>::iterator iterator;
+    typedef std::vector<PreprocessedEntity *>::const_iterator const_iterator;
+    iterator begin() { return PreprocessedEntities.begin(); }
+    iterator end() { return PreprocessedEntities.end(); }
+    const_iterator begin() const { return PreprocessedEntities.begin(); }
+    const_iterator end() const { return PreprocessedEntities.end(); }
+    
+    /// \brief Add a new preprocessed entity to this record.
+    void addPreprocessedEntity(PreprocessedEntity *Entity);
+  };
+  
+  /// \brief Preprocessor callback action used to populate a preprocessing
+  /// record.
+  class PopulatePreprocessingRecord : public PPCallbacks {
+    /// \brief The preprocessing record this action will populate.
+    PreprocessingRecord &Record;
+    
+  public:
+    explicit PopulatePreprocessingRecord(PreprocessingRecord &Record)
+      : Record(Record) { }
+    
+    virtual void MacroExpands(const Token &Id, const MacroInfo* MI);
+    virtual void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI);
+  };
+  
+} // end namespace clang
+
+inline void* operator new(size_t bytes, clang::PreprocessingRecord& PR,
+                          unsigned alignment) throw() {
+  return PR.Allocate(bytes, alignment);
+}
+
+inline void operator delete(void* ptr, clang::PreprocessingRecord& PR,
+                            unsigned) throw() {
+  PR.Deallocate(ptr);
+}
+
+#endif // LLVM_CLANG_LEX_PREPROCESSINGRECORD_H

Propchange: cfe/trunk/include/clang/Lex/PreprocessingRecord.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/include/clang/Lex/PreprocessingRecord.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/include/clang/Lex/PreprocessingRecord.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/lib/Frontend/ASTUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ASTUnit.cpp?rev=98836&r1=98835&r2=98836&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/ASTUnit.cpp (original)
+++ cfe/trunk/lib/Frontend/ASTUnit.cpp Thu Mar 18 12:52:52 2010
@@ -278,7 +278,8 @@
 ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
                                              Diagnostic &Diags,
                                              bool OnlyLocalDecls,
-                                             bool CaptureDiagnostics) {
+                                             bool CaptureDiagnostics,
+                                             bool WantPreprocessingRecord) {
   // Create the compiler instance to use for building the AST.
   CompilerInstance Clang;
   llvm::OwningPtr<ASTUnit> AST;
@@ -328,6 +329,15 @@
   // Create the preprocessor.
   Clang.createPreprocessor();
 
+  // If the ASTUnit was requested to store information about preprocessing,
+  // create storage for that information and attach an appropriate callback to 
+  // populate that storage.
+  if (WantPreprocessingRecord) {
+    AST->Preprocessing.reset(new PreprocessingRecord);
+    Clang.getPreprocessor().addPPCallbacks(
+                          new PopulatePreprocessingRecord(*AST->Preprocessing));
+  }
+      
   Act.reset(new TopLevelDeclTrackerAction(*AST));
   if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
                            /*IsAST=*/false))
@@ -367,7 +377,8 @@
                                       bool OnlyLocalDecls,
                                       RemappedFile *RemappedFiles,
                                       unsigned NumRemappedFiles,
-                                      bool CaptureDiagnostics) {
+                                      bool CaptureDiagnostics,
+                                      bool WantPreprocessingRecord) {
   llvm::SmallVector<const char *, 16> Args;
   Args.push_back("<clang>"); // FIXME: Remove dummy argument.
   Args.insert(Args.end(), ArgBegin, ArgEnd);
@@ -419,5 +430,6 @@
 
   CI->getFrontendOpts().DisableFree = true;
   return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
-                                    CaptureDiagnostics);
+                                    CaptureDiagnostics, 
+                                    WantPreprocessingRecord);
 }

Modified: cfe/trunk/lib/Lex/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/CMakeLists.txt?rev=98836&r1=98835&r2=98836&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/CMakeLists.txt (original)
+++ cfe/trunk/lib/Lex/CMakeLists.txt Thu Mar 18 12:52:52 2010
@@ -16,6 +16,7 @@
   PPMacroExpansion.cpp
   PTHLexer.cpp
   Pragma.cpp
+  PreprocessingRecord.cpp
   Preprocessor.cpp
   PreprocessorLexer.cpp
   ScratchBuffer.cpp

Added: cfe/trunk/lib/Lex/PreprocessingRecord.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PreprocessingRecord.cpp?rev=98836&view=auto
==============================================================================
--- cfe/trunk/lib/Lex/PreprocessingRecord.cpp (added)
+++ cfe/trunk/lib/Lex/PreprocessingRecord.cpp Thu Mar 18 12:52:52 2010
@@ -0,0 +1,37 @@
+//===--- PreprocessingRecord.cpp - Record of Preprocessing ------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements the PreprocessingRecord class, which maintains a record
+//  of what occurred during preprocessing, and its helpers.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Token.h"
+
+using namespace clang;
+
+void PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) {
+  PreprocessedEntities.push_back(Entity);
+}
+
+void PopulatePreprocessingRecord::MacroExpands(const Token &Id, 
+                                               const MacroInfo* MI) {
+  Record.addPreprocessedEntity(
+                        new (Record) MacroInstantiation(Id.getIdentifierInfo(),
+                                                       Id.getLocation(),
+                                                      MI->getDefinitionLoc()));
+}
+
+void PopulatePreprocessingRecord::MacroDefined(const IdentifierInfo *II, 
+                                               const MacroInfo *MI) {
+  SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc());
+  Record.addPreprocessedEntity(
+                  new (Record) MacroDefinition(II, MI->getDefinitionLoc(), R));
+}

Propchange: cfe/trunk/lib/Lex/PreprocessingRecord.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/lib/Lex/PreprocessingRecord.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/lib/Lex/PreprocessingRecord.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/Index/annotate-tokens-pp.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/annotate-tokens-pp.c?rev=98836&r1=98835&r2=98836&view=diff
==============================================================================
--- cfe/trunk/test/Index/annotate-tokens-pp.c (original)
+++ cfe/trunk/test/Index/annotate-tokens-pp.c Thu Mar 18 12:52:52 2010
@@ -1,32 +1,58 @@
+#define NOTHING(X,Y)
+#define STILL_NOTHING NOTHING(honk,warble)
 #define BAR baz
 #define WIBBLE(X, Y) X##Y
-float WIBBLE(int, float);
-int BAR;
+NOTHING(more,junk) float WIBBLE(int, float);
+int BAR STILL_NOTHING;
 #include "foo.h"
+#undef BAR
 
-// RUN: c-index-test -test-annotate-tokens=%s:1:1:6:1 -I%S/Inputs %s | FileCheck %s
-// CHECK: Punctuation: "#" [1:1 - 1:2] preprocessing directive=
-// CHECK: Identifier: "define" [1:2 - 1:8] preprocessing directive=
-// CHECK: Identifier: "BAR" [1:9 - 1:12] preprocessing directive=
-// CHECK: Identifier: "baz" [1:13 - 1:16] preprocessing directive=
+// RUN: c-index-test -test-annotate-tokens=%s:2:1:9:1 -I%S/Inputs %s | FileCheck %s
 // CHECK: Punctuation: "#" [2:1 - 2:2] preprocessing directive=
 // CHECK: Identifier: "define" [2:2 - 2:8] preprocessing directive=
-// CHECK: Identifier: "WIBBLE" [2:9 - 2:15] preprocessing directive=
-// CHECK: Punctuation: "(" [2:15 - 2:16] preprocessing directive=
-// CHECK: Identifier: "X" [2:16 - 2:17] preprocessing directive=
-// CHECK: Punctuation: "," [2:17 - 2:18] preprocessing directive=
-// CHECK: Identifier: "Y" [2:19 - 2:20] preprocessing directive=
-// CHECK: Punctuation: ")" [2:20 - 2:21] preprocessing directive=
-// CHECK: Identifier: "WIBBLE" [3:7 - 3:13] macro instantiation=
-// CHECK: Punctuation: "(" [3:13 - 3:14]
-// CHECK: Keyword: "int" [3:14 - 3:17]
-// CHECK: Punctuation: "," [3:17 - 3:18]
-// CHECK: Keyword: "float" [3:19 - 3:24]
-// CHECK: Punctuation: ")" [3:24 - 3:25]
-// CHECK: Punctuation: ";" [3:25 - 3:26]
-// CHECK: Keyword: "int" [4:1 - 4:4]
-// CHECK: Identifier: "BAR" [4:5 - 4:8] macro instantiation=
-// CHECK: Punctuation: ";" [4:8 - 4:9]
-// CHECK: Punctuation: "#" [5:1 - 5:2] preprocessing directive=
-// CHECK: Identifier: "include" [5:2 - 5:9] preprocessing directive=
-// CHECK: Literal: ""foo.h"" [5:10 - 5:17] preprocessing directive=
+// CHECK: Identifier: "STILL_NOTHING" [2:9 - 2:22] preprocessing directive=
+// CHECK: Identifier: "NOTHING" [2:23 - 2:30] preprocessing directive=
+// CHECK: Punctuation: "(" [2:30 - 2:31] preprocessing directive=
+// CHECK: Identifier: "honk" [2:31 - 2:35] preprocessing directive=
+// CHECK: Punctuation: "," [2:35 - 2:36] preprocessing directive=
+// CHECK: Identifier: "warble" [2:36 - 2:42] preprocessing directive=
+// CHECK: Punctuation: ")" [2:42 - 2:43] preprocessing directive=
+// CHECK: Punctuation: "#" [3:1 - 3:2] preprocessing directive=
+// CHECK: Identifier: "define" [3:2 - 3:8] preprocessing directive=
+// CHECK: Identifier: "BAR" [3:9 - 3:12] preprocessing directive=
+// CHECK: Identifier: "baz" [3:13 - 3:16] preprocessing directive=
+// CHECK: Punctuation: "#" [4:1 - 4:2] preprocessing directive=
+// CHECK: Identifier: "define" [4:2 - 4:8] preprocessing directive=
+// CHECK: Identifier: "WIBBLE" [4:9 - 4:15] preprocessing directive=
+// CHECK: Punctuation: "(" [4:15 - 4:16] preprocessing directive=
+// CHECK: Identifier: "X" [4:16 - 4:17] preprocessing directive=
+// CHECK: Punctuation: "," [4:17 - 4:18] preprocessing directive=
+// CHECK: Identifier: "Y" [4:19 - 4:20] preprocessing directive=
+// CHECK: Punctuation: ")" [4:20 - 4:21] preprocessing directive=
+// CHECK: Identifier: "X" [4:22 - 4:23] preprocessing directive=
+// CHECK: Punctuation: "##" [4:23 - 4:25] preprocessing directive=
+// CHECK: Identifier: "Y" [4:25 - 4:26] preprocessing directive=
+// CHECK: Identifier: "NOTHING" [5:1 - 5:8] macro instantiation=NOTHING
+// CHECK: Punctuation: "(" [5:8 - 5:9]
+// CHECK: Identifier: "more" [5:9 - 5:13]
+// CHECK: Punctuation: "," [5:13 - 5:14]
+// CHECK: Identifier: "junk" [5:14 - 5:18]
+// CHECK: Punctuation: ")" [5:18 - 5:19]
+// CHECK: Keyword: "float" [5:20 - 5:25]
+// CHECK: Identifier: "WIBBLE" [5:26 - 5:32] macro instantiation=WIBBLE
+// CHECK: Punctuation: "(" [5:32 - 5:33]
+// CHECK: Keyword: "int" [5:33 - 5:36]
+// CHECK: Punctuation: "," [5:36 - 5:37]
+// CHECK: Keyword: "float" [5:38 - 5:43]
+// CHECK: Punctuation: ")" [5:43 - 5:44]
+// CHECK: Punctuation: ";" [5:44 - 5:45]
+// CHECK: Keyword: "int" [6:1 - 6:4]
+// CHECK: Identifier: "BAR" [6:5 - 6:8] macro instantiation=BAR
+// CHECK: Identifier: "STILL_NOTHING" [6:9 - 6:22] macro instantiation=STILL_NOTHING
+// CHECK: Punctuation: ";" [6:22 - 6:23]
+// CHECK: Punctuation: "#" [7:1 - 7:2] preprocessing directive=
+// CHECK: Identifier: "include" [7:2 - 7:9] preprocessing directive=
+// CHECK: Literal: ""foo.h"" [7:10 - 7:17] preprocessing directive=
+// CHECK: Punctuation: "#" [8:1 - 8:2] preprocessing directive=
+// CHECK: Identifier: "undef" [8:2 - 8:7] preprocessing directive=
+// CHECK: Identifier: "BAR" [8:8 - 8:11] preprocessing directive=

Modified: cfe/trunk/tools/CIndex/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CIndex.cpp?rev=98836&r1=98835&r2=98836&view=diff
==============================================================================
--- cfe/trunk/tools/CIndex/CIndex.cpp (original)
+++ cfe/trunk/tools/CIndex/CIndex.cpp Thu Mar 18 12:52:52 2010
@@ -1008,7 +1008,8 @@
                                    CXXIdx->getOnlyLocalDecls(),
                                    RemappedFiles.data(),
                                    RemappedFiles.size(),
-                                   /*CaptureDiagnostics=*/true));
+                                   /*CaptureDiagnostics=*/true,
+                                   /*WantPreprocessingRecord=*/true));
 
     // FIXME: Until we have broader testing, just drop the entire AST if we
     // encountered an error.
@@ -1438,6 +1439,10 @@
     return createCXString("");
   }
 
+  if (C.kind == CXCursor_MacroInstantiation)
+    return createCXString(getCursorMacroInstantiation(C)->getName()
+                                                           ->getNameStart());
+
   if (clang_isDeclaration(C.kind))
     return getDeclSpelling(getCursorDecl(C));
 
@@ -1656,7 +1661,8 @@
   }
 
   if (C.kind == CXCursor_MacroInstantiation) {
-    SourceLocation L = cxcursor::getCursorMacroInstantiation(C).getBegin();
+    SourceLocation L
+      = cxcursor::getCursorMacroInstantiation(C)->getSourceRange().getBegin();
     return cxloc::translateSourceLocation(getCursorContext(C), L);
   }
   
@@ -1717,7 +1723,7 @@
   }
 
   if (C.kind == CXCursor_MacroInstantiation) {
-    SourceRange R = cxcursor::getCursorMacroInstantiation(C);
+    SourceRange R = cxcursor::getCursorMacroInstantiation(C)->getSourceRange();
     return cxloc::translateSourceRange(getCursorContext(C), R);
   }
   
@@ -2030,16 +2036,36 @@
 //===----------------------------------------------------------------------===//
 
 namespace {
-/// IgnoringDiagClient - This is a diagnostic client that just ignores all
-/// diags.
-class IgnoringDiagClient : public DiagnosticClient {
-  void HandleDiagnostic(Diagnostic::Level DiagLevel,
-                        const DiagnosticInfo &Info) {
-    // Just ignore it.
-  }
-};
+  class ComparePreprocessedEntityLocation {
+    SourceManager &SM;
+
+  public:
+    explicit ComparePreprocessedEntityLocation(SourceManager &SM) : SM(SM) { }
+
+    bool operator()(const PreprocessedEntity *Entity, SourceLocation Loc) {
+      return SM.isBeforeInTranslationUnit(Entity->getSourceRange().getEnd(), 
+                                          Loc);
+    }
+
+    bool operator()(SourceLocation Loc, const PreprocessedEntity *Entity) {
+      return SM.isBeforeInTranslationUnit(Loc, 
+                                          Entity->getSourceRange().getBegin());
+    }
+
+    bool operator()(const PreprocessedEntity *Entity, SourceRange R) {
+      return SM.isBeforeInTranslationUnit(Entity->getSourceRange().getEnd(), 
+                                          R.getBegin());
+    }
+
+    bool operator()(SourceRange R, const PreprocessedEntity *Entity) {
+      return SM.isBeforeInTranslationUnit(R.getEnd(), 
+                                          Entity->getSourceRange().getBegin());
+    }
+  };
 }
 
+
+
 /* CXToken layout:
  *   int_data[0]: a CXTokenKind
  *   int_data[1]: starting token location
@@ -2298,13 +2324,13 @@
   if (RelexOkay) {
     Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
               CXXUnit->getASTContext().getLangOptions(),
-              Buffer.begin(), Buffer.data() + BeginLocInfo.second, Buffer.end());
+              Buffer.begin(), Buffer.data() + BeginLocInfo.second, 
+              Buffer.end());
     Lex.SetCommentRetentionState(true);
     
     // Lex tokens in raw mode until we hit the end of the range, to avoid 
     // entering #includes or expanding macros.
     std::vector<Token> TokenStream;
-    Preprocessor &PP = CXXUnit->getPreprocessor();
     while (true) {
       Token Tok;
       Lex.LexFromRawLexer(Tok);
@@ -2339,84 +2365,30 @@
         continue;
       }
       
-      // If this is a ## token, change its kind to unknown so that
-      // repreprocessing it will not produce an error.
-      if (Tok.is(tok::hashhash))
-        Tok.setKind(tok::unknown);
-      
-      // If this raw token is an identifier, the raw lexer won't have
-      // looked up the corresponding identifier info for it.  Do this
-      // now so that it will be macro expanded when we re-preprocess
-      // it.
-      if (Tok.is(tok::identifier)) {
-        // Change the kind of this identifier to the appropriate token kind, e.g.
-        // turning "for" into a keyword.
-        Tok.setKind(PP.LookUpIdentifierInfo(Tok)->getTokenID());
-      }
-      
-      TokenStream.push_back(Tok);
-      
       if (Tok.is(tok::eof))
         break;
     }
+  }
+   
+  if (CXXUnit->hasPreprocessingRecord()) {
+    PreprocessingRecord &PPRec = CXXUnit->getPreprocessingRecord();
+    std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+      Entities = std::equal_range(PPRec.begin(), PPRec.end(), RegionOfInterest,
+                                  ComparePreprocessedEntityLocation(SourceMgr));
+    for (; Entities.first != Entities.second; ++Entities.first) {
+      PreprocessedEntity *Entity = *Entities.first;
+      if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(Entity)) {
+        SourceLocation Loc = MI->getSourceRange().getBegin();
+        if (Loc.isFileID()) {
+          Annotated[Loc.getRawEncoding()]
+            = MakeMacroInstantiationCursor(MI, CXXUnit);
+        }
 
-    // Temporarily change the diagnostics object so that we ignore any
-    // generated diagnostics from this pass.
-    IgnoringDiagClient TmpDC;
-    Diagnostic TmpDiags(&TmpDC);
-    Diagnostic *OldDiags = &PP.getDiagnostics();
-    PP.setDiagnostics(TmpDiags);
-
-    // Inform the preprocessor that we don't want comments.
-    PP.SetCommentRetentionState(false, false);
-    
-    // Enter the tokens we just lexed.  This will cause them to be macro expanded
-    // but won't enter sub-files (because we removed #'s).
-    PP.EnterTokenStream(&TokenStream[0], TokenStream.size(), false, false);
-
-    // Lex all the tokens.
-    Token Tok;
-    PP.Lex(Tok);
-    while (Tok.isNot(tok::eof)) {
-      // Ignore non-macro tokens.
-      if (!Tok.getLocation().isMacroID()) {
-        PP.Lex(Tok);
-        continue;
-      }
-
-      // Okay, we have the first token of a macro expansion. Keep
-      // track of the range of the macro expansion.
-      std::pair<SourceLocation, SourceLocation> LLoc =
-        SourceMgr.getInstantiationRange(Tok.getLocation());
-
-      // Ignore tokens whose instantiation location was not the main file.
-      if (SourceMgr.getFileID(LLoc.first) != BeginLocInfo.first) {
-        PP.Lex(Tok);
         continue;
       }
 
-      assert(SourceMgr.getFileID(LLoc.second) == BeginLocInfo.first &&
-             "Start and end of expansion must be in the same ultimate file!");
-
-      // Okay, eat this token, getting the next one.
-      PP.Lex(Tok);
-
-      // Skip all the rest of the tokens that are part of this macro
-      // instantiation.  It would be really nice to pop up a window with all the
-      // spelling of the tokens or something.
-      while (!Tok.is(tok::eof) &&
-             SourceMgr.getInstantiationLoc(Tok.getLocation()) == LLoc.first)
-        PP.Lex(Tok);
-
-      CXCursor Cursor
-        = cxcursor::MakeMacroInstantiationCursor(SourceRange(LLoc.first, 
-                                                             LLoc.second), 
-                                                 CXXUnit);
-      Annotated[LLoc.first.getRawEncoding()] = Cursor;
+      // FIXME: expose other preprocessed entities.
     }
-
-    // Restore diagnostics object back to its own thing.
-    PP.setDiagnostics(*OldDiags);
   }
   
   for (unsigned I = 0; I != NumTokens; ++I) {

Modified: cfe/trunk/tools/CIndex/CXCursor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CXCursor.cpp?rev=98836&r1=98835&r2=98836&view=diff
==============================================================================
--- cfe/trunk/tools/CIndex/CXCursor.cpp (original)
+++ cfe/trunk/tools/CIndex/CXCursor.cpp Thu Mar 18 12:52:52 2010
@@ -314,22 +314,15 @@
                                       reinterpret_cast<uintptr_t> (C.data[1])));
 }
 
-CXCursor cxcursor::MakeMacroInstantiationCursor(SourceRange Range, 
+CXCursor cxcursor::MakeMacroInstantiationCursor(MacroInstantiation *MI, 
                                                 ASTUnit *TU) {
-  CXCursor C = { CXCursor_MacroInstantiation, 
-                 { reinterpret_cast<void *>(Range.getBegin().getRawEncoding()),
-                   reinterpret_cast<void *>(Range.getEnd().getRawEncoding()),
-                   TU }
-               };
+  CXCursor C = { CXCursor_MacroInstantiation, { MI, 0, TU } };
   return C;
 }
 
-SourceRange cxcursor::getCursorMacroInstantiation(CXCursor C) {
+MacroInstantiation *cxcursor::getCursorMacroInstantiation(CXCursor C) {
   assert(C.kind == CXCursor_MacroInstantiation);
-  return SourceRange(SourceLocation::getFromRawEncoding(
-                                      reinterpret_cast<uintptr_t> (C.data[0])),
-                     SourceLocation::getFromRawEncoding(
-                                      reinterpret_cast<uintptr_t> (C.data[1])));
+  return static_cast<MacroInstantiation *>(C.data[0]);
 }
 
 Decl *cxcursor::getCursorDecl(CXCursor Cursor) {

Modified: cfe/trunk/tools/CIndex/CXCursor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CXCursor.h?rev=98836&r1=98835&r2=98836&view=diff
==============================================================================
--- cfe/trunk/tools/CIndex/CXCursor.h (original)
+++ cfe/trunk/tools/CIndex/CXCursor.h Thu Mar 18 12:52:52 2010
@@ -25,6 +25,7 @@
 class Attr;
 class Decl;
 class Expr;
+class MacroInstantiation;
 class NamedDecl;
 class ObjCInterfaceDecl;
 class ObjCProtocolDecl;
@@ -80,11 +81,11 @@
 SourceRange getCursorPreprocessingDirective(CXCursor C);
 
 /// \brief Create a macro instantiation cursor.
-CXCursor MakeMacroInstantiationCursor(SourceRange Range, ASTUnit *TU);
+CXCursor MakeMacroInstantiationCursor(MacroInstantiation *, ASTUnit *TU);
 
 /// \brief Unpack a given macro instantiation cursor to retrieve its
 /// source range.
-SourceRange getCursorMacroInstantiation(CXCursor C);
+MacroInstantiation *getCursorMacroInstantiation(CXCursor C);
 
 Decl *getCursorDecl(CXCursor Cursor);
 Expr *getCursorExpr(CXCursor Cursor);





More information about the cfe-commits mailing list