Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 4ae8f29

Browse files
committed
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98836 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 7c647a1 commit 4ae8f29

File tree

9 files changed

+415
-128
lines changed

9 files changed

+415
-128
lines changed

Diff for: include/clang/Frontend/ASTUnit.h

+13-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef LLVM_CLANG_FRONTEND_ASTUNIT_H
1515
#define LLVM_CLANG_FRONTEND_ASTUNIT_H
1616

17+
#include "clang/Lex/PreprocessingRecord.h"
1718
#include "clang/Basic/SourceManager.h"
1819
#include "llvm/ADT/OwningPtr.h"
1920
#include "clang/Basic/FileManager.h"
@@ -53,7 +54,8 @@ class ASTUnit {
5354
llvm::OwningPtr<TargetInfo> Target;
5455
llvm::OwningPtr<Preprocessor> PP;
5556
llvm::OwningPtr<ASTContext> Ctx;
56-
57+
llvm::OwningPtr<PreprocessingRecord> Preprocessing;
58+
5759
/// Optional owned invocation, just used to make the invocation used in
5860
/// LoadFromCommandLine available.
5961
llvm::OwningPtr<CompilerInvocation> Invocation;
@@ -135,6 +137,12 @@ class ASTUnit {
135137
const ASTContext &getASTContext() const { return *Ctx.get(); }
136138
ASTContext &getASTContext() { return *Ctx.get(); }
137139

140+
const PreprocessingRecord &getPreprocessingRecord() const {
141+
return *Preprocessing.get();
142+
}
143+
PreprocessingRecord &getPreprocessingRecord() { return *Preprocessing.get(); }
144+
bool hasPreprocessingRecord() { return Preprocessing.get() != 0; }
145+
138146
const FileManager &getFileManager() const { return FileMgr; }
139147
FileManager &getFileManager() { return FileMgr; }
140148

@@ -204,7 +212,8 @@ class ASTUnit {
204212
static ASTUnit *LoadFromCompilerInvocation(CompilerInvocation *CI,
205213
Diagnostic &Diags,
206214
bool OnlyLocalDecls = false,
207-
bool CaptureDiagnostics = false);
215+
bool CaptureDiagnostics = false,
216+
bool WantPreprocessingRecord = false);
208217

209218
/// LoadFromCommandLine - Create an ASTUnit from a vector of command line
210219
/// arguments, which must specify exactly one source file.
@@ -227,7 +236,8 @@ class ASTUnit {
227236
bool OnlyLocalDecls = false,
228237
RemappedFile *RemappedFiles = 0,
229238
unsigned NumRemappedFiles = 0,
230-
bool CaptureDiagnostics = false);
239+
bool CaptureDiagnostics = false,
240+
bool WantPreprocessingRecord = false);
231241
};
232242

233243
} // namespace clang

Diff for: include/clang/Lex/PreprocessingRecord.h

+235
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
//===--- PreprocessingRecord.h - Record of Preprocessing --------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file defines the PreprocessingRecord class, which maintains a record
11+
// of what occurred during preprocessing.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
#ifndef LLVM_CLANG_LEX_PREPROCESSINGRECORD_H
15+
#define LLVM_CLANG_LEX_PREPROCESSINGRECORD_H
16+
17+
#include "clang/Lex/PPCallbacks.h"
18+
#include "clang/Basic/SourceLocation.h"
19+
#include "llvm/ADT/PointerUnion.h"
20+
#include "llvm/Support/Allocator.h"
21+
#include <vector>
22+
23+
namespace clang {
24+
class IdentifierInfo;
25+
class PreprocessingRecord;
26+
}
27+
28+
/// \brief Allocates memory within a Clang preprocessing record.
29+
void* operator new(size_t bytes, clang::PreprocessingRecord& PR,
30+
unsigned alignment = 8) throw();
31+
32+
/// \brief Frees memory allocated in a Clang preprocessing record.
33+
void operator delete(void* ptr, clang::PreprocessingRecord& PR,
34+
unsigned) throw();
35+
36+
namespace clang {
37+
/// \brief Base class that describes a preprocessed entity, which may be a
38+
/// preprocessor directive or macro instantiation.
39+
class PreprocessedEntity {
40+
public:
41+
/// \brief The kind of preprocessed entity an object describes.
42+
enum EntityKind {
43+
/// \brief A macro instantiation.
44+
MacroInstantiationKind,
45+
46+
/// \brief A preprocessing directive whose kind is not specified.
47+
///
48+
/// This kind will be used for any preprocessing directive that does not
49+
/// have a more specific kind within the \c DirectiveKind enumeration.
50+
PreprocessingDirectiveKind,
51+
52+
/// \brief A macro definition.
53+
MacroDefinitionKind,
54+
55+
FirstPreprocessingDirective = PreprocessingDirectiveKind,
56+
LastPreprocessingDirective = MacroDefinitionKind
57+
};
58+
59+
private:
60+
/// \brief The kind of preprocessed entity that this object describes.
61+
EntityKind Kind;
62+
63+
/// \brief The source range that covers this preprocessed entity.
64+
SourceRange Range;
65+
66+
protected:
67+
PreprocessedEntity(EntityKind Kind, SourceRange Range)
68+
: Kind(Kind), Range(Range) { }
69+
70+
public:
71+
/// \brief Retrieve the kind of preprocessed entity stored in this object.
72+
EntityKind getKind() const { return Kind; }
73+
74+
/// \brief Retrieve the source range that covers this entire preprocessed
75+
/// entity.
76+
SourceRange getSourceRange() const { return Range; }
77+
78+
// Implement isa/cast/dyncast/etc.
79+
static bool classof(const PreprocessedEntity *) { return true; }
80+
81+
// Only allow allocation of preprocessed entities using the allocator
82+
// in PreprocessingRecord or by doing a placement new.
83+
void* operator new(size_t bytes, PreprocessingRecord& PR,
84+
unsigned alignment = 8) throw() {
85+
return ::operator new(bytes, PR, alignment);
86+
}
87+
88+
void* operator new(size_t bytes, void* mem) throw() {
89+
return mem;
90+
}
91+
92+
void operator delete(void* ptr, PreprocessingRecord& PR,
93+
unsigned alignment) throw() {
94+
return ::operator delete(ptr, PR, alignment);
95+
}
96+
97+
void operator delete(void*, std::size_t) throw() { }
98+
void operator delete(void*, void*) throw() { }
99+
100+
private:
101+
// Make vanilla 'new' and 'delete' illegal for preprocessed entities.
102+
void* operator new(size_t bytes) throw();
103+
void operator delete(void* data) throw();
104+
};
105+
106+
/// \brief Records the location of a macro instantiation.
107+
class MacroInstantiation : public PreprocessedEntity {
108+
/// \brief The name of the macro being instantiation.
109+
IdentifierInfo *Name;
110+
111+
/// \brief The location of the definition of the macro being instantiated.
112+
SourceLocation DefinitionLocation;
113+
114+
public:
115+
MacroInstantiation(IdentifierInfo *Name, SourceRange Range,
116+
SourceLocation DefinitionLocation)
117+
: PreprocessedEntity(MacroInstantiationKind, Range), Name(Name),
118+
DefinitionLocation(DefinitionLocation) { }
119+
120+
/// \brief The name of the macro being instantiated.
121+
IdentifierInfo *getName() const { return Name; }
122+
123+
/// \brief The location of the definition of the macro being instantiated.
124+
/// FIXME: Could we just provide MacroInfo pointers instead, by teaching
125+
/// the preprocessor to hold on to them when we care to keep them around?
126+
SourceLocation getDefinitionLocation() const { return DefinitionLocation; }
127+
128+
// Implement isa/cast/dyncast/etc.
129+
static bool classof(const PreprocessedEntity *PE) {
130+
return PE->getKind() == MacroInstantiationKind;
131+
}
132+
static bool classof(const MacroInstantiation *) { return true; }
133+
134+
};
135+
136+
/// \brief Records the presence of a preprocessor directive.
137+
class PreprocessingDirective : public PreprocessedEntity {
138+
public:
139+
PreprocessingDirective(EntityKind Kind, SourceRange Range)
140+
: PreprocessedEntity(Kind, Range) { }
141+
142+
// Implement isa/cast/dyncast/etc.
143+
static bool classof(const PreprocessedEntity *PD) {
144+
return PD->getKind() >= FirstPreprocessingDirective &&
145+
PD->getKind() <= LastPreprocessingDirective;
146+
}
147+
static bool classof(const PreprocessingDirective *) { return true; }
148+
};
149+
150+
/// \brief Record the location of a macro definition.
151+
class MacroDefinition : public PreprocessingDirective {
152+
/// \brief The name of the macro being defined.
153+
const IdentifierInfo *Name;
154+
155+
/// \brief The location of the macro name in the macro definition.
156+
SourceLocation Location;
157+
158+
public:
159+
explicit MacroDefinition(const IdentifierInfo *Name, SourceLocation Location,
160+
SourceRange Range)
161+
: PreprocessingDirective(MacroDefinitionKind, Range), Name(Name),
162+
Location(Location) { }
163+
164+
/// \brief Retrieve the name of the macro being defined.
165+
const IdentifierInfo *getMacroName() const { return Name; }
166+
167+
/// \brief Retrieve the location of the macro name in the definition.
168+
SourceLocation getLocation() const { return Location; }
169+
170+
// Implement isa/cast/dyncast/etc.
171+
static bool classof(const PreprocessingDirective *PD) {
172+
return PD->getKind() == MacroDefinitionKind;
173+
}
174+
static bool classof(const MacroDefinition *) { return true; }
175+
};
176+
177+
/// \brief A record of the steps taken while preprocessing a source file,
178+
/// including the various preprocessing directives processed, macros
179+
/// instantiated, etc.
180+
class PreprocessingRecord {
181+
/// \brief Allocator used to store preprocessing objects.
182+
llvm::BumpPtrAllocator BumpAlloc;
183+
184+
/// \brief The set of preprocessed entities in this record, in order they
185+
/// were seen.
186+
std::vector<PreprocessedEntity *> PreprocessedEntities;
187+
188+
public:
189+
/// \brief Allocate memory in the preprocessing record.
190+
void *Allocate(unsigned Size, unsigned Align = 8) {
191+
return BumpAlloc.Allocate(Size, Align);
192+
}
193+
194+
/// \brief Deallocate memory in the preprocessing record.
195+
void Deallocate(void *Ptr) { }
196+
197+
// Iteration over the preprocessed entities.
198+
typedef std::vector<PreprocessedEntity *>::iterator iterator;
199+
typedef std::vector<PreprocessedEntity *>::const_iterator const_iterator;
200+
iterator begin() { return PreprocessedEntities.begin(); }
201+
iterator end() { return PreprocessedEntities.end(); }
202+
const_iterator begin() const { return PreprocessedEntities.begin(); }
203+
const_iterator end() const { return PreprocessedEntities.end(); }
204+
205+
/// \brief Add a new preprocessed entity to this record.
206+
void addPreprocessedEntity(PreprocessedEntity *Entity);
207+
};
208+
209+
/// \brief Preprocessor callback action used to populate a preprocessing
210+
/// record.
211+
class PopulatePreprocessingRecord : public PPCallbacks {
212+
/// \brief The preprocessing record this action will populate.
213+
PreprocessingRecord &Record;
214+
215+
public:
216+
explicit PopulatePreprocessingRecord(PreprocessingRecord &Record)
217+
: Record(Record) { }
218+
219+
virtual void MacroExpands(const Token &Id, const MacroInfo* MI);
220+
virtual void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI);
221+
};
222+
223+
} // end namespace clang
224+
225+
inline void* operator new(size_t bytes, clang::PreprocessingRecord& PR,
226+
unsigned alignment) throw() {
227+
return PR.Allocate(bytes, alignment);
228+
}
229+
230+
inline void operator delete(void* ptr, clang::PreprocessingRecord& PR,
231+
unsigned) throw() {
232+
PR.Deallocate(ptr);
233+
}
234+
235+
#endif // LLVM_CLANG_LEX_PREPROCESSINGRECORD_H

Diff for: lib/Frontend/ASTUnit.cpp

+15-3
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,8 @@ class TopLevelDeclTrackerAction : public ASTFrontendAction {
278278
ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
279279
Diagnostic &Diags,
280280
bool OnlyLocalDecls,
281-
bool CaptureDiagnostics) {
281+
bool CaptureDiagnostics,
282+
bool WantPreprocessingRecord) {
282283
// Create the compiler instance to use for building the AST.
283284
CompilerInstance Clang;
284285
llvm::OwningPtr<ASTUnit> AST;
@@ -328,6 +329,15 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
328329
// Create the preprocessor.
329330
Clang.createPreprocessor();
330331

332+
// If the ASTUnit was requested to store information about preprocessing,
333+
// create storage for that information and attach an appropriate callback to
334+
// populate that storage.
335+
if (WantPreprocessingRecord) {
336+
AST->Preprocessing.reset(new PreprocessingRecord);
337+
Clang.getPreprocessor().addPPCallbacks(
338+
new PopulatePreprocessingRecord(*AST->Preprocessing));
339+
}
340+
331341
Act.reset(new TopLevelDeclTrackerAction(*AST));
332342
if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
333343
/*IsAST=*/false))
@@ -367,7 +377,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
367377
bool OnlyLocalDecls,
368378
RemappedFile *RemappedFiles,
369379
unsigned NumRemappedFiles,
370-
bool CaptureDiagnostics) {
380+
bool CaptureDiagnostics,
381+
bool WantPreprocessingRecord) {
371382
llvm::SmallVector<const char *, 16> Args;
372383
Args.push_back("<clang>"); // FIXME: Remove dummy argument.
373384
Args.insert(Args.end(), ArgBegin, ArgEnd);
@@ -419,5 +430,6 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
419430

420431
CI->getFrontendOpts().DisableFree = true;
421432
return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
422-
CaptureDiagnostics);
433+
CaptureDiagnostics,
434+
WantPreprocessingRecord);
423435
}

Diff for: lib/Lex/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ add_clang_library(clangLex
1616
PPMacroExpansion.cpp
1717
PTHLexer.cpp
1818
Pragma.cpp
19+
PreprocessingRecord.cpp
1920
Preprocessor.cpp
2021
PreprocessorLexer.cpp
2122
ScratchBuffer.cpp

Diff for: lib/Lex/PreprocessingRecord.cpp

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//===--- PreprocessingRecord.cpp - Record of Preprocessing ------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file implements the PreprocessingRecord class, which maintains a record
11+
// of what occurred during preprocessing, and its helpers.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
#include "clang/Lex/PreprocessingRecord.h"
15+
#include "clang/Lex/MacroInfo.h"
16+
#include "clang/Lex/Token.h"
17+
18+
using namespace clang;
19+
20+
void PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) {
21+
PreprocessedEntities.push_back(Entity);
22+
}
23+
24+
void PopulatePreprocessingRecord::MacroExpands(const Token &Id,
25+
const MacroInfo* MI) {
26+
Record.addPreprocessedEntity(
27+
new (Record) MacroInstantiation(Id.getIdentifierInfo(),
28+
Id.getLocation(),
29+
MI->getDefinitionLoc()));
30+
}
31+
32+
void PopulatePreprocessingRecord::MacroDefined(const IdentifierInfo *II,
33+
const MacroInfo *MI) {
34+
SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc());
35+
Record.addPreprocessedEntity(
36+
new (Record) MacroDefinition(II, MI->getDefinitionLoc(), R));
37+
}

0 commit comments

Comments
 (0)