Move clang-cc.h to lib/Frontend/Utils.h, and move the associated .cpp
files to lib/Frontend.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72099 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
new file mode 100644
index 0000000..0065828
--- /dev/null
+++ b/lib/Frontend/CacheTokens.cpp
@@ -0,0 +1,658 @@
+//===--- CacheTokens.cpp - Caching of lexer tokens for PTH support --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides a possible implementation of PTH support for Clang that is
+// based on caching lexed tokens and identifiers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Streams.h"
+
+// FIXME: put this somewhere else?
+#ifndef S_ISDIR
+#define S_ISDIR(x) (((x)&_S_IFDIR)!=0)
+#endif
+
+using namespace clang;
+using namespace clang::io;
+
+//===----------------------------------------------------------------------===//
+// PTH-specific stuff.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN PTHEntry {
+ Offset TokenData, PPCondData;
+
+public:
+ PTHEntry() {}
+
+ PTHEntry(Offset td, Offset ppcd)
+ : TokenData(td), PPCondData(ppcd) {}
+
+ Offset getTokenOffset() const { return TokenData; }
+ Offset getPPCondTableOffset() const { return PPCondData; }
+};
+
+
+class VISIBILITY_HIDDEN PTHEntryKeyVariant {
+ union { const FileEntry* FE; const char* Path; };
+ enum { IsFE = 0x1, IsDE = 0x2, IsNoExist = 0x0 } Kind;
+ struct stat *StatBuf;
+public:
+ PTHEntryKeyVariant(const FileEntry *fe)
+ : FE(fe), Kind(IsFE), StatBuf(0) {}
+
+ PTHEntryKeyVariant(struct stat* statbuf, const char* path)
+ : Path(path), Kind(IsDE), StatBuf(new struct stat(*statbuf)) {}
+
+ PTHEntryKeyVariant(const char* path)
+ : Path(path), Kind(IsNoExist), StatBuf(0) {}
+
+ bool isFile() const { return Kind == IsFE; }
+
+ const char* getCString() const {
+ return Kind == IsFE ? FE->getName() : Path;
+ }
+
+ unsigned getKind() const { return (unsigned) Kind; }
+
+ void EmitData(llvm::raw_ostream& Out) {
+ switch (Kind) {
+ case IsFE:
+ // Emit stat information.
+ ::Emit32(Out, FE->getInode());
+ ::Emit32(Out, FE->getDevice());
+ ::Emit16(Out, FE->getFileMode());
+ ::Emit64(Out, FE->getModificationTime());
+ ::Emit64(Out, FE->getSize());
+ break;
+ case IsDE:
+ // Emit stat information.
+ ::Emit32(Out, (uint32_t) StatBuf->st_ino);
+ ::Emit32(Out, (uint32_t) StatBuf->st_dev);
+ ::Emit16(Out, (uint16_t) StatBuf->st_mode);
+ ::Emit64(Out, (uint64_t) StatBuf->st_mtime);
+ ::Emit64(Out, (uint64_t) StatBuf->st_size);
+ delete StatBuf;
+ break;
+ default:
+ break;
+ }
+ }
+
+ unsigned getRepresentationLength() const {
+ return Kind == IsNoExist ? 0 : 4 + 4 + 2 + 8 + 8;
+ }
+};
+
+class VISIBILITY_HIDDEN FileEntryPTHEntryInfo {
+public:
+ typedef PTHEntryKeyVariant key_type;
+ typedef key_type key_type_ref;
+
+ typedef PTHEntry data_type;
+ typedef const PTHEntry& data_type_ref;
+
+ static unsigned ComputeHash(PTHEntryKeyVariant V) {
+ return BernsteinHash(V.getCString());
+ }
+
+ static std::pair<unsigned,unsigned>
+ EmitKeyDataLength(llvm::raw_ostream& Out, PTHEntryKeyVariant V,
+ const PTHEntry& E) {
+
+ unsigned n = strlen(V.getCString()) + 1 + 1;
+ ::Emit16(Out, n);
+
+ unsigned m = V.getRepresentationLength() + (V.isFile() ? 4 + 4 : 0);
+ ::Emit8(Out, m);
+
+ return std::make_pair(n, m);
+ }
+
+ static void EmitKey(llvm::raw_ostream& Out, PTHEntryKeyVariant V, unsigned n){
+ // Emit the entry kind.
+ ::Emit8(Out, (unsigned) V.getKind());
+ // Emit the string.
+ Out.write(V.getCString(), n - 1);
+ }
+
+ static void EmitData(llvm::raw_ostream& Out, PTHEntryKeyVariant V,
+ const PTHEntry& E, unsigned) {
+
+
+ // For file entries emit the offsets into the PTH file for token data
+ // and the preprocessor blocks table.
+ if (V.isFile()) {
+ ::Emit32(Out, E.getTokenOffset());
+ ::Emit32(Out, E.getPPCondTableOffset());
+ }
+
+ // Emit any other data associated with the key (i.e., stat information).
+ V.EmitData(Out);
+ }
+};
+
+class OffsetOpt {
+ bool valid;
+ Offset off;
+public:
+ OffsetOpt() : valid(false) {}
+ bool hasOffset() const { return valid; }
+ Offset getOffset() const { assert(valid); return off; }
+ void setOffset(Offset o) { off = o; valid = true; }
+};
+} // end anonymous namespace
+
+typedef OnDiskChainedHashTableGenerator<FileEntryPTHEntryInfo> PTHMap;
+typedef llvm::DenseMap<const IdentifierInfo*,uint32_t> IDMap;
+typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy;
+
+namespace {
+class VISIBILITY_HIDDEN PTHWriter {
+ IDMap IM;
+ llvm::raw_fd_ostream& Out;
+ Preprocessor& PP;
+ uint32_t idcount;
+ PTHMap PM;
+ CachedStrsTy CachedStrs;
+ Offset CurStrOffset;
+ std::vector<llvm::StringMapEntry<OffsetOpt>*> StrEntries;
+
+ //// Get the persistent id for the given IdentifierInfo*.
+ uint32_t ResolveID(const IdentifierInfo* II);
+
+ /// Emit a token to the PTH file.
+ void EmitToken(const Token& T);
+
+ void Emit8(uint32_t V) {
+ Out << (unsigned char)(V);
+ }
+
+ void Emit16(uint32_t V) { ::Emit16(Out, V); }
+
+ void Emit24(uint32_t V) {
+ Out << (unsigned char)(V);
+ Out << (unsigned char)(V >> 8);
+ Out << (unsigned char)(V >> 16);
+ assert((V >> 24) == 0);
+ }
+
+ void Emit32(uint32_t V) { ::Emit32(Out, V); }
+
+ void EmitBuf(const char *Ptr, unsigned NumBytes) {
+ Out.write(Ptr, NumBytes);
+ }
+
+ /// EmitIdentifierTable - Emits two tables to the PTH file. The first is
+ /// a hashtable mapping from identifier strings to persistent IDs.
+ /// The second is a straight table mapping from persistent IDs to string data
+ /// (the keys of the first table).
+ std::pair<Offset, Offset> EmitIdentifierTable();
+
+ /// EmitFileTable - Emit a table mapping from file name strings to PTH
+ /// token data.
+ Offset EmitFileTable() { return PM.Emit(Out); }
+
+ PTHEntry LexTokens(Lexer& L);
+ Offset EmitCachedSpellings();
+
+public:
+ PTHWriter(llvm::raw_fd_ostream& out, Preprocessor& pp)
+ : Out(out), PP(pp), idcount(0), CurStrOffset(0) {}
+
+ PTHMap &getPM() { return PM; }
+ void GeneratePTH(const std::string *MainFile = 0);
+};
+} // end anonymous namespace
+
+uint32_t PTHWriter::ResolveID(const IdentifierInfo* II) {
+ // Null IdentifierInfo's map to the persistent ID 0.
+ if (!II)
+ return 0;
+
+ IDMap::iterator I = IM.find(II);
+ if (I != IM.end())
+ return I->second; // We've already added 1.
+
+ IM[II] = ++idcount; // Pre-increment since '0' is reserved for NULL.
+ return idcount;
+}
+
+void PTHWriter::EmitToken(const Token& T) {
+ // Emit the token kind, flags, and length.
+ Emit32(((uint32_t) T.getKind()) | ((((uint32_t) T.getFlags())) << 8)|
+ (((uint32_t) T.getLength()) << 16));
+
+ if (!T.isLiteral()) {
+ Emit32(ResolveID(T.getIdentifierInfo()));
+ } else {
+ // We cache *un-cleaned* spellings. This gives us 100% fidelity with the
+ // source code.
+ const char* s = T.getLiteralData();
+ unsigned len = T.getLength();
+
+ // Get the string entry.
+ llvm::StringMapEntry<OffsetOpt> *E = &CachedStrs.GetOrCreateValue(s, s+len);
+
+ // If this is a new string entry, bump the PTH offset.
+ if (!E->getValue().hasOffset()) {
+ E->getValue().setOffset(CurStrOffset);
+ StrEntries.push_back(E);
+ CurStrOffset += len + 1;
+ }
+
+ // Emit the relative offset into the PTH file for the spelling string.
+ Emit32(E->getValue().getOffset());
+ }
+
+ // Emit the offset into the original source file of this token so that we
+ // can reconstruct its SourceLocation.
+ Emit32(PP.getSourceManager().getFileOffset(T.getLocation()));
+}
+
+PTHEntry PTHWriter::LexTokens(Lexer& L) {
+ // Pad 0's so that we emit tokens to a 4-byte alignment.
+ // This speed up reading them back in.
+ Pad(Out, 4);
+ Offset off = (Offset) Out.tell();
+
+ // Keep track of matching '#if' ... '#endif'.
+ typedef std::vector<std::pair<Offset, unsigned> > PPCondTable;
+ PPCondTable PPCond;
+ std::vector<unsigned> PPStartCond;
+ bool ParsingPreprocessorDirective = false;
+ Token Tok;
+
+ do {
+ L.LexFromRawLexer(Tok);
+ NextToken:
+
+ if ((Tok.isAtStartOfLine() || Tok.is(tok::eof)) &&
+ ParsingPreprocessorDirective) {
+ // Insert an eom token into the token cache. It has the same
+ // position as the next token that is not on the same line as the
+ // preprocessor directive. Observe that we continue processing
+ // 'Tok' when we exit this branch.
+ Token Tmp = Tok;
+ Tmp.setKind(tok::eom);
+ Tmp.clearFlag(Token::StartOfLine);
+ Tmp.setIdentifierInfo(0);
+ EmitToken(Tmp);
+ ParsingPreprocessorDirective = false;
+ }
+
+ if (Tok.is(tok::identifier)) {
+ Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
+ EmitToken(Tok);
+ continue;
+ }
+
+ if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) {
+ // Special processing for #include. Store the '#' token and lex
+ // the next token.
+ assert(!ParsingPreprocessorDirective);
+ Offset HashOff = (Offset) Out.tell();
+ EmitToken(Tok);
+
+ // Get the next token.
+ L.LexFromRawLexer(Tok);
+
+ // If we see the start of line, then we had a null directive "#".
+ if (Tok.isAtStartOfLine())
+ goto NextToken;
+
+ // Did we see 'include'/'import'/'include_next'?
+ if (Tok.isNot(tok::identifier)) {
+ EmitToken(Tok);
+ continue;
+ }
+
+ IdentifierInfo* II = PP.LookUpIdentifierInfo(Tok);
+ Tok.setIdentifierInfo(II);
+ tok::PPKeywordKind K = II->getPPKeywordID();
+
+ ParsingPreprocessorDirective = true;
+
+ switch (K) {
+ case tok::pp_not_keyword:
+ // Invalid directives "#foo" can occur in #if 0 blocks etc, just pass
+ // them through.
+ default:
+ break;
+
+ case tok::pp_include:
+ case tok::pp_import:
+ case tok::pp_include_next: {
+ // Save the 'include' token.
+ EmitToken(Tok);
+ // Lex the next token as an include string.
+ L.setParsingPreprocessorDirective(true);
+ L.LexIncludeFilename(Tok);
+ L.setParsingPreprocessorDirective(false);
+ assert(!Tok.isAtStartOfLine());
+ if (Tok.is(tok::identifier))
+ Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
+
+ break;
+ }
+ case tok::pp_if:
+ case tok::pp_ifdef:
+ case tok::pp_ifndef: {
+ // Add an entry for '#if' and friends. We initially set the target
+ // index to 0. This will get backpatched when we hit #endif.
+ PPStartCond.push_back(PPCond.size());
+ PPCond.push_back(std::make_pair(HashOff, 0U));
+ break;
+ }
+ case tok::pp_endif: {
+ // Add an entry for '#endif'. We set the target table index to itself.
+ // This will later be set to zero when emitting to the PTH file. We
+ // use 0 for uninitialized indices because that is easier to debug.
+ unsigned index = PPCond.size();
+ // Backpatch the opening '#if' entry.
+ assert(!PPStartCond.empty());
+ assert(PPCond.size() > PPStartCond.back());
+ assert(PPCond[PPStartCond.back()].second == 0);
+ PPCond[PPStartCond.back()].second = index;
+ PPStartCond.pop_back();
+ // Add the new entry to PPCond.
+ PPCond.push_back(std::make_pair(HashOff, index));
+ EmitToken(Tok);
+
+ // Some files have gibberish on the same line as '#endif'.
+ // Discard these tokens.
+ do
+ L.LexFromRawLexer(Tok);
+ while (Tok.isNot(tok::eof) && !Tok.isAtStartOfLine());
+ // We have the next token in hand.
+ // Don't immediately lex the next one.
+ goto NextToken;
+ }
+ case tok::pp_elif:
+ case tok::pp_else: {
+ // Add an entry for #elif or #else.
+ // This serves as both a closing and opening of a conditional block.
+ // This means that its entry will get backpatched later.
+ unsigned index = PPCond.size();
+ // Backpatch the previous '#if' entry.
+ assert(!PPStartCond.empty());
+ assert(PPCond.size() > PPStartCond.back());
+ assert(PPCond[PPStartCond.back()].second == 0);
+ PPCond[PPStartCond.back()].second = index;
+ PPStartCond.pop_back();
+ // Now add '#elif' as a new block opening.
+ PPCond.push_back(std::make_pair(HashOff, 0U));
+ PPStartCond.push_back(index);
+ break;
+ }
+ }
+ }
+
+ EmitToken(Tok);
+ }
+ while (Tok.isNot(tok::eof));
+
+ assert(PPStartCond.empty() && "Error: imblanced preprocessor conditionals.");
+
+ // Next write out PPCond.
+ Offset PPCondOff = (Offset) Out.tell();
+
+ // Write out the size of PPCond so that clients can identifer empty tables.
+ Emit32(PPCond.size());
+
+ for (unsigned i = 0, e = PPCond.size(); i!=e; ++i) {
+ Emit32(PPCond[i].first - off);
+ uint32_t x = PPCond[i].second;
+ assert(x != 0 && "PPCond entry not backpatched.");
+ // Emit zero for #endifs. This allows us to do checking when
+ // we read the PTH file back in.
+ Emit32(x == i ? 0 : x);
+ }
+
+ return PTHEntry(off, PPCondOff);
+}
+
+Offset PTHWriter::EmitCachedSpellings() {
+ // Write each cached strings to the PTH file.
+ Offset SpellingsOff = Out.tell();
+
+ for (std::vector<llvm::StringMapEntry<OffsetOpt>*>::iterator
+ I = StrEntries.begin(), E = StrEntries.end(); I!=E; ++I)
+ EmitBuf((*I)->getKeyData(), (*I)->getKeyLength()+1 /*nul included*/);
+
+ return SpellingsOff;
+}
+
+void PTHWriter::GeneratePTH(const std::string *MainFile) {
+ // Generate the prologue.
+ Out << "cfe-pth";
+ Emit32(PTHManager::Version);
+
+ // Leave 4 words for the prologue.
+ Offset PrologueOffset = Out.tell();
+ for (unsigned i = 0; i < 4; ++i)
+ Emit32(0);
+
+ // Write the name of the MainFile.
+ if (MainFile && !MainFile->empty()) {
+ Emit16(MainFile->length());
+ EmitBuf(MainFile->data(), MainFile->length());
+ } else {
+ // String with 0 bytes.
+ Emit16(0);
+ }
+ Emit8(0);
+
+ // Iterate over all the files in SourceManager. Create a lexer
+ // for each file and cache the tokens.
+ SourceManager &SM = PP.getSourceManager();
+ const LangOptions &LOpts = PP.getLangOptions();
+
+ for (SourceManager::fileinfo_iterator I = SM.fileinfo_begin(),
+ E = SM.fileinfo_end(); I != E; ++I) {
+ const SrcMgr::ContentCache &C = *I->second;
+ const FileEntry *FE = C.Entry;
+
+ // FIXME: Handle files with non-absolute paths.
+ llvm::sys::Path P(FE->getName());
+ if (!P.isAbsolute())
+ continue;
+
+ const llvm::MemoryBuffer *B = C.getBuffer();
+ if (!B) continue;
+
+ FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);
+ Lexer L(FID, SM, LOpts);
+ PM.insert(FE, LexTokens(L));
+ }
+
+ // Write out the identifier table.
+ const std::pair<Offset,Offset> &IdTableOff = EmitIdentifierTable();
+
+ // Write out the cached strings table.
+ Offset SpellingOff = EmitCachedSpellings();
+
+ // Write out the file table.
+ Offset FileTableOff = EmitFileTable();
+
+ // Finally, write the prologue.
+ Out.seek(PrologueOffset);
+ Emit32(IdTableOff.first);
+ Emit32(IdTableOff.second);
+ Emit32(FileTableOff);
+ Emit32(SpellingOff);
+}
+
+namespace {
+/// StatListener - A simple "interpose" object used to monitor stat calls
+/// invoked by FileManager while processing the original sources used
+/// as input to PTH generation. StatListener populates the PTHWriter's
+/// file map with stat information for directories as well as negative stats.
+/// Stat information for files are populated elsewhere.
+class StatListener : public StatSysCallCache {
+ PTHMap &PM;
+public:
+ StatListener(PTHMap &pm) : PM(pm) {}
+ ~StatListener() {}
+
+ int stat(const char *path, struct stat *buf) {
+ int result = ::stat(path, buf);
+
+ if (result != 0) // Failed 'stat'.
+ PM.insert(path, PTHEntry());
+ else if (S_ISDIR(buf->st_mode)) {
+ // Only cache directories with absolute paths.
+ if (!llvm::sys::Path(path).isAbsolute())
+ return result;
+
+ PM.insert(PTHEntryKeyVariant(buf, path), PTHEntry());
+ }
+
+ return result;
+ }
+};
+} // end anonymous namespace
+
+
+void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) {
+ // Get the name of the main file.
+ const SourceManager &SrcMgr = PP.getSourceManager();
+ const FileEntry *MainFile = SrcMgr.getFileEntryForID(SrcMgr.getMainFileID());
+ llvm::sys::Path MainFilePath(MainFile->getName());
+ std::string MainFileName;
+
+ if (!MainFilePath.isAbsolute()) {
+ llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
+ P.appendComponent(MainFilePath.toString());
+ MainFileName = P.toString();
+ } else {
+ MainFileName = MainFilePath.toString();
+ }
+
+ // Create the PTHWriter.
+ PTHWriter PW(*OS, PP);
+
+ // Install the 'stat' system call listener in the FileManager.
+ PP.getFileManager().setStatCache(new StatListener(PW.getPM()));
+
+ // Lex through the entire file. This will populate SourceManager with
+ // all of the header information.
+ Token Tok;
+ PP.EnterMainSourceFile();
+ do { PP.Lex(Tok); } while (Tok.isNot(tok::eof));
+
+ // Generate the PTH file.
+ PP.getFileManager().setStatCache(0);
+ PW.GeneratePTH(&MainFileName);
+}
+
+//===----------------------------------------------------------------------===//
+
+class PTHIdKey {
+public:
+ const IdentifierInfo* II;
+ uint32_t FileOffset;
+};
+
+namespace {
+class VISIBILITY_HIDDEN PTHIdentifierTableTrait {
+public:
+ typedef PTHIdKey* key_type;
+ typedef key_type key_type_ref;
+
+ typedef uint32_t data_type;
+ typedef data_type data_type_ref;
+
+ static unsigned ComputeHash(PTHIdKey* key) {
+ return BernsteinHash(key->II->getName());
+ }
+
+ static std::pair<unsigned,unsigned>
+ EmitKeyDataLength(llvm::raw_ostream& Out, const PTHIdKey* key, uint32_t) {
+ unsigned n = strlen(key->II->getName()) + 1;
+ ::Emit16(Out, n);
+ return std::make_pair(n, sizeof(uint32_t));
+ }
+
+ static void EmitKey(llvm::raw_ostream& Out, PTHIdKey* key, unsigned n) {
+ // Record the location of the key data. This is used when generating
+ // the mapping from persistent IDs to strings.
+ key->FileOffset = Out.tell();
+ Out.write(key->II->getName(), n);
+ }
+
+ static void EmitData(llvm::raw_ostream& Out, PTHIdKey*, uint32_t pID,
+ unsigned) {
+ ::Emit32(Out, pID);
+ }
+};
+} // end anonymous namespace
+
+/// EmitIdentifierTable - Emits two tables to the PTH file. The first is
+/// a hashtable mapping from identifier strings to persistent IDs. The second
+/// is a straight table mapping from persistent IDs to string data (the
+/// keys of the first table).
+///
+std::pair<Offset,Offset> PTHWriter::EmitIdentifierTable() {
+ // Build two maps:
+ // (1) an inverse map from persistent IDs -> (IdentifierInfo*,Offset)
+ // (2) a map from (IdentifierInfo*, Offset)* -> persistent IDs
+
+ // Note that we use 'calloc', so all the bytes are 0.
+ PTHIdKey *IIDMap = (PTHIdKey*)calloc(idcount, sizeof(PTHIdKey));
+
+ // Create the hashtable.
+ OnDiskChainedHashTableGenerator<PTHIdentifierTableTrait> IIOffMap;
+
+ // Generate mapping from persistent IDs -> IdentifierInfo*.
+ for (IDMap::iterator I = IM.begin(), E = IM.end(); I != E; ++I) {
+ // Decrement by 1 because we are using a vector for the lookup and
+ // 0 is reserved for NULL.
+ assert(I->second > 0);
+ assert(I->second-1 < idcount);
+ unsigned idx = I->second-1;
+
+ // Store the mapping from persistent ID to IdentifierInfo*
+ IIDMap[idx].II = I->first;
+
+ // Store the reverse mapping in a hashtable.
+ IIOffMap.insert(&IIDMap[idx], I->second);
+ }
+
+ // Write out the inverse map first. This causes the PCIDKey entries to
+ // record PTH file offsets for the string data. This is used to write
+ // the second table.
+ Offset StringTableOffset = IIOffMap.Emit(Out);
+
+ // Now emit the table mapping from persistent IDs to PTH file offsets.
+ Offset IDOff = Out.tell();
+ Emit32(idcount); // Emit the number of identifiers.
+ for (unsigned i = 0 ; i < idcount; ++i)
+ Emit32(IIDMap[i].FileOffset);
+
+ // Finally, release the inverse map.
+ free(IIDMap);
+
+ return std::make_pair(IDOff, StringTableOffset);
+}
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
new file mode 100644
index 0000000..4cee280
--- /dev/null
+++ b/lib/Frontend/DependencyFile.cpp
@@ -0,0 +1,171 @@
+//===--- DependencyFile.cpp - Generate dependency file --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This code generates dependency files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/DirectoryLookup.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/System/Path.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN DependencyFileCallback : public PPCallbacks {
+ std::vector<std::string> Files;
+ llvm::StringSet<> FilesSet;
+ const Preprocessor *PP;
+ std::vector<std::string> Targets;
+ llvm::raw_ostream *OS;
+ bool IncludeSystemHeaders;
+ bool PhonyTarget;
+private:
+ bool FileMatchesDepCriteria(const char *Filename,
+ SrcMgr::CharacteristicKind FileType);
+ void OutputDependencyFile();
+
+public:
+ DependencyFileCallback(const Preprocessor *_PP,
+ llvm::raw_ostream *_OS,
+ const std::vector<std::string> &_Targets,
+ bool _IncludeSystemHeaders,
+ bool _PhonyTarget)
+ : PP(_PP), Targets(_Targets), OS(_OS),
+ IncludeSystemHeaders(_IncludeSystemHeaders), PhonyTarget(_PhonyTarget) {}
+
+ ~DependencyFileCallback() {
+ OutputDependencyFile();
+ OS->flush();
+ delete OS;
+ }
+
+ virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType);
+};
+}
+
+
+
+void clang::AttachDependencyFileGen(Preprocessor *PP, llvm::raw_ostream *OS,
+ std::vector<std::string> &Targets,
+ bool IncludeSystemHeaders,
+ bool PhonyTarget) {
+ assert(!Targets.empty() && "Target required for dependency generation");
+
+ DependencyFileCallback *PPDep =
+ new DependencyFileCallback(PP, OS, Targets, IncludeSystemHeaders,
+ PhonyTarget);
+ PP->setPPCallbacks(PPDep);
+}
+
+/// FileMatchesDepCriteria - Determine whether the given Filename should be
+/// considered as a dependency.
+bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename,
+ SrcMgr::CharacteristicKind FileType) {
+ if (strcmp("<built-in>", Filename) == 0)
+ return false;
+
+ if (IncludeSystemHeaders)
+ return true;
+
+ return FileType == SrcMgr::C_User;
+}
+
+void DependencyFileCallback::FileChanged(SourceLocation Loc,
+ FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType) {
+ if (Reason != PPCallbacks::EnterFile)
+ return;
+
+ // Dependency generation really does want to go all the way to the
+ // file entry for a source location to find out what is depended on.
+ // We do not want #line markers to affect dependency generation!
+ SourceManager &SM = PP->getSourceManager();
+
+ const FileEntry *FE =
+ SM.getFileEntryForID(SM.getFileID(SM.getInstantiationLoc(Loc)));
+ if (FE == 0) return;
+
+ const char *Filename = FE->getName();
+ if (!FileMatchesDepCriteria(Filename, FileType))
+ return;
+
+ // Remove leading "./"
+ if (Filename[0] == '.' && Filename[1] == '/')
+ Filename = &Filename[2];
+
+ if (FilesSet.insert(Filename))
+ Files.push_back(Filename);
+}
+
+void DependencyFileCallback::OutputDependencyFile() {
+ // Write out the dependency targets, trying to avoid overly long
+ // lines when possible. We try our best to emit exactly the same
+ // dependency file as GCC (4.2), assuming the included files are the
+ // same.
+ const unsigned MaxColumns = 75;
+ unsigned Columns = 0;
+
+ for (std::vector<std::string>::iterator
+ I = Targets.begin(), E = Targets.end(); I != E; ++I) {
+ unsigned N = I->length();
+ if (Columns == 0) {
+ Columns += N;
+ *OS << *I;
+ } else if (Columns + N + 2 > MaxColumns) {
+ Columns = N + 2;
+ *OS << " \\\n " << *I;
+ } else {
+ Columns += N + 1;
+ *OS << ' ' << *I;
+ }
+ }
+
+ *OS << ':';
+ Columns += 1;
+
+ // Now add each dependency in the order it was seen, but avoiding
+ // duplicates.
+ for (std::vector<std::string>::iterator I = Files.begin(),
+ E = Files.end(); I != E; ++I) {
+ // Start a new line if this would exceed the column limit. Make
+ // sure to leave space for a trailing " \" in case we need to
+ // break the line on the next iteration.
+ unsigned N = I->length();
+ if (Columns + (N + 1) + 2 > MaxColumns) {
+ *OS << " \\\n ";
+ Columns = 2;
+ }
+ *OS << ' ' << *I;
+ Columns += N + 1;
+ }
+ *OS << '\n';
+
+ // Create phony targets if requested.
+ if (PhonyTarget) {
+ // Skip the first entry, this is always the input file itself.
+ for (std::vector<std::string>::iterator I = Files.begin() + 1,
+ E = Files.end(); I != E; ++I) {
+ *OS << '\n';
+ *OS << *I << ":\n";
+ }
+ }
+}
+
diff --git a/lib/Frontend/DiagChecker.cpp b/lib/Frontend/DiagChecker.cpp
new file mode 100644
index 0000000..2eaf2fe
--- /dev/null
+++ b/lib/Frontend/DiagChecker.cpp
@@ -0,0 +1,301 @@
+//===--- DiagChecker.cpp - Diagnostic Checking Functions ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Process the input files and check that the diagnostic messages are expected.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Sema/ParseAST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Preprocessor.h"
+using namespace clang;
+
+typedef TextDiagnosticBuffer::DiagList DiagList;
+typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
+
+static void EmitError(Preprocessor &PP, SourceLocation Pos, const char *String){
+ unsigned ID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error, String);
+ PP.Diag(Pos, ID);
+}
+
+
+// USING THE DIAGNOSTIC CHECKER:
+//
+// Indicating that a line expects an error or a warning is simple. Put a comment
+// on the line that has the diagnostic, use "expected-{error,warning}" to tag
+// if it's an expected error or warning, and place the expected text between {{
+// and }} markers. The full text doesn't have to be included, only enough to
+// ensure that the correct diagnostic was emitted.
+//
+// Here's an example:
+//
+// int A = B; // expected-error {{use of undeclared identifier 'B'}}
+//
+// You can place as many diagnostics on one line as you wish. To make the code
+// more readable, you can use slash-newline to separate out the diagnostics.
+//
+// The simple syntax above allows each specification to match exactly one error.
+// You can use the extended syntax to customize this. The extended syntax is
+// "expected-<type> <n> {{diag text}}", where <type> is one of "error",
+// "warning" or "note", and <n> is a positive integer. This allows the
+// diagnostic to appear as many times as specified. Example:
+//
+// void f(); // expected-note 2 {{previous declaration is here}}
+//
+
+/// FindDiagnostics - Go through the comment and see if it indicates expected
+/// diagnostics. If so, then put them in a diagnostic list.
+///
+static void FindDiagnostics(const char *CommentStart, unsigned CommentLen,
+ DiagList &ExpectedDiags,
+ Preprocessor &PP, SourceLocation Pos,
+ const char *ExpectedStr) {
+ const char *CommentEnd = CommentStart+CommentLen;
+ unsigned ExpectedStrLen = strlen(ExpectedStr);
+
+ // Find all expected-foo diagnostics in the string and add them to
+ // ExpectedDiags.
+ while (CommentStart != CommentEnd) {
+ CommentStart = std::find(CommentStart, CommentEnd, 'e');
+ if (unsigned(CommentEnd-CommentStart) < ExpectedStrLen) return;
+
+ // If this isn't expected-foo, ignore it.
+ if (memcmp(CommentStart, ExpectedStr, ExpectedStrLen)) {
+ ++CommentStart;
+ continue;
+ }
+
+ CommentStart += ExpectedStrLen;
+
+ // Skip whitespace.
+ while (CommentStart != CommentEnd &&
+ isspace(CommentStart[0]))
+ ++CommentStart;
+
+ // Default, if we find the '{' now, is 1 time.
+ int Times = 1;
+ int Temp = 0;
+ // In extended syntax, there could be a digit now.
+ while (CommentStart != CommentEnd &&
+ CommentStart[0] >= '0' && CommentStart[0] <= '9') {
+ Temp *= 10;
+ Temp += CommentStart[0] - '0';
+ ++CommentStart;
+ }
+ if (Temp > 0)
+ Times = Temp;
+
+ // Skip whitespace again.
+ while (CommentStart != CommentEnd &&
+ isspace(CommentStart[0]))
+ ++CommentStart;
+
+ // We should have a {{ now.
+ if (CommentEnd-CommentStart < 2 ||
+ CommentStart[0] != '{' || CommentStart[1] != '{') {
+ if (std::find(CommentStart, CommentEnd, '{') != CommentEnd)
+ EmitError(PP, Pos, "bogus characters before '{{' in expected string");
+ else
+ EmitError(PP, Pos, "cannot find start ('{{') of expected string");
+ return;
+ }
+ CommentStart += 2;
+
+ // Find the }}.
+ const char *ExpectedEnd = CommentStart;
+ while (1) {
+ ExpectedEnd = std::find(ExpectedEnd, CommentEnd, '}');
+ if (CommentEnd-ExpectedEnd < 2) {
+ EmitError(PP, Pos, "cannot find end ('}}') of expected string");
+ return;
+ }
+
+ if (ExpectedEnd[1] == '}')
+ break;
+
+ ++ExpectedEnd; // Skip over singular }'s
+ }
+
+ std::string Msg(CommentStart, ExpectedEnd);
+ std::string::size_type FindPos;
+ while ((FindPos = Msg.find("\\n")) != std::string::npos)
+ Msg.replace(FindPos, 2, "\n");
+ // Add is possibly multiple times.
+ for (int i = 0; i < Times; ++i)
+ ExpectedDiags.push_back(std::make_pair(Pos, Msg));
+
+ CommentStart = ExpectedEnd;
+ }
+}
+
+/// FindExpectedDiags - Lex the main source file to find all of the
+// expected errors and warnings.
+static void FindExpectedDiags(Preprocessor &PP,
+ DiagList &ExpectedErrors,
+ DiagList &ExpectedWarnings,
+ DiagList &ExpectedNotes) {
+ // Create a raw lexer to pull all the comments out of the main file. We don't
+ // want to look in #include'd headers for expected-error strings.
+ FileID FID = PP.getSourceManager().getMainFileID();
+
+ // Create a lexer to lex all the tokens of the main file in raw mode.
+ Lexer RawLex(FID, PP.getSourceManager(), PP.getLangOptions());
+
+ // Return comments as tokens, this is how we find expected diagnostics.
+ RawLex.SetCommentRetentionState(true);
+
+ Token Tok;
+ Tok.setKind(tok::comment);
+ while (Tok.isNot(tok::eof)) {
+ RawLex.Lex(Tok);
+ if (!Tok.is(tok::comment)) continue;
+
+ std::string Comment = PP.getSpelling(Tok);
+ if (Comment.empty()) continue;
+
+
+ // Find all expected errors.
+ FindDiagnostics(&Comment[0], Comment.size(), ExpectedErrors, PP,
+ Tok.getLocation(), "expected-error");
+
+ // Find all expected warnings.
+ FindDiagnostics(&Comment[0], Comment.size(), ExpectedWarnings, PP,
+ Tok.getLocation(), "expected-warning");
+
+ // Find all expected notes.
+ FindDiagnostics(&Comment[0], Comment.size(), ExpectedNotes, PP,
+ Tok.getLocation(), "expected-note");
+ };
+}
+
+/// PrintProblem - This takes a diagnostic map of the delta between expected and
+/// seen diagnostics. If there's anything in it, then something unexpected
+/// happened. Print the map out in a nice format and return "true". If the map
+/// is empty and we're not going to print things, then return "false".
+///
+static bool PrintProblem(SourceManager &SourceMgr,
+ const_diag_iterator diag_begin,
+ const_diag_iterator diag_end,
+ const char *Msg) {
+ if (diag_begin == diag_end) return false;
+
+ fprintf(stderr, "%s\n", Msg);
+
+ for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I)
+ fprintf(stderr, " Line %d: %s\n",
+ SourceMgr.getInstantiationLineNumber(I->first),
+ I->second.c_str());
+
+ return true;
+}
+
+/// CompareDiagLists - Compare two diagnostic lists and return the difference
+/// between them.
+///
+static bool CompareDiagLists(SourceManager &SourceMgr,
+ const_diag_iterator d1_begin,
+ const_diag_iterator d1_end,
+ const_diag_iterator d2_begin,
+ const_diag_iterator d2_end,
+ const char *MsgLeftOnly,
+ const char *MsgRightOnly) {
+ DiagList LeftOnly;
+ DiagList Left(d1_begin, d1_end);
+ DiagList Right(d2_begin, d2_end);
+
+ for (const_diag_iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
+ unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(I->first);
+ const std::string &Diag1 = I->second;
+
+ DiagList::iterator II, IE;
+ for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
+ unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first);
+ if (LineNo1 != LineNo2) continue;
+
+ const std::string &Diag2 = II->second;
+ if (Diag2.find(Diag1) != std::string::npos ||
+ Diag1.find(Diag2) != std::string::npos) {
+ break;
+ }
+ }
+ if (II == IE) {
+ // Not found.
+ LeftOnly.push_back(*I);
+ } else {
+ // Found. The same cannot be found twice.
+ Right.erase(II);
+ }
+ }
+ // Now all that's left in Right are those that were not matched.
+
+ return PrintProblem(SourceMgr, LeftOnly.begin(), LeftOnly.end(), MsgLeftOnly)
+ | PrintProblem(SourceMgr, Right.begin(), Right.end(), MsgRightOnly);
+}
+
+/// CheckResults - This compares the expected results to those that
+/// were actually reported. It emits any discrepencies. Return "true" if there
+/// were problems. Return "false" otherwise.
+///
+static bool CheckResults(Preprocessor &PP,
+ const DiagList &ExpectedErrors,
+ const DiagList &ExpectedWarnings,
+ const DiagList &ExpectedNotes) {
+ const DiagnosticClient *DiagClient = PP.getDiagnostics().getClient();
+ assert(DiagClient != 0 &&
+ "DiagChecker requires a valid TextDiagnosticBuffer");
+ const TextDiagnosticBuffer &Diags =
+ static_cast<const TextDiagnosticBuffer&>(*DiagClient);
+ SourceManager &SourceMgr = PP.getSourceManager();
+
+ // We want to capture the delta between what was expected and what was
+ // seen.
+ //
+ // Expected \ Seen - set expected but not seen
+ // Seen \ Expected - set seen but not expected
+ bool HadProblem = false;
+
+ // See if there are error mismatches.
+ HadProblem |= CompareDiagLists(SourceMgr,
+ ExpectedErrors.begin(), ExpectedErrors.end(),
+ Diags.err_begin(), Diags.err_end(),
+ "Errors expected but not seen:",
+ "Errors seen but not expected:");
+
+ // See if there are warning mismatches.
+ HadProblem |= CompareDiagLists(SourceMgr,
+ ExpectedWarnings.begin(),
+ ExpectedWarnings.end(),
+ Diags.warn_begin(), Diags.warn_end(),
+ "Warnings expected but not seen:",
+ "Warnings seen but not expected:");
+
+ // See if there are note mismatches.
+ HadProblem |= CompareDiagLists(SourceMgr,
+ ExpectedNotes.begin(),
+ ExpectedNotes.end(),
+ Diags.note_begin(), Diags.note_end(),
+ "Notes expected but not seen:",
+ "Notes seen but not expected:");
+
+ return HadProblem;
+}
+
+
+/// CheckDiagnostics - Gather the expected diagnostics and check them.
+bool clang::CheckDiagnostics(Preprocessor &PP) {
+ // Gather the set of expected diagnostics.
+ DiagList ExpectedErrors, ExpectedWarnings, ExpectedNotes;
+ FindExpectedDiags(PP, ExpectedErrors, ExpectedWarnings, ExpectedNotes);
+
+ // Check that the expected diagnostics occurred.
+ return CheckResults(PP, ExpectedErrors, ExpectedWarnings, ExpectedNotes);
+}
diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp
new file mode 100644
index 0000000..e9aece9
--- /dev/null
+++ b/lib/Frontend/PrintParserCallbacks.cpp
@@ -0,0 +1,829 @@
+//===--- PrintParserActions.cpp - Implement -parse-print-callbacks mode ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This code simply runs the preprocessor on the input file and prints out the
+// result. This is the traditional behavior of the -E option.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Parse/Action.h"
+#include "clang/Parse/DeclSpec.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+namespace {
+ class ParserPrintActions : public MinimalAction {
+ llvm::raw_ostream& Out;
+
+ public:
+ ParserPrintActions(Preprocessor &PP, llvm::raw_ostream& OS)
+ : MinimalAction(PP), Out(OS) {}
+
+ // Printing Functions which also must call MinimalAction
+
+ /// ActOnDeclarator - This callback is invoked when a declarator is parsed
+ /// and 'Init' specifies the initializer if any. This is for things like:
+ /// "int X = 4" or "typedef int foo".
+ virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) {
+ Out << __FUNCTION__ << " ";
+ if (IdentifierInfo *II = D.getIdentifier()) {
+ Out << "'" << II->getName() << "'";
+ } else {
+ Out << "<anon>";
+ }
+ Out << "\n";
+
+ // Pass up to EmptyActions so that the symbol table is maintained right.
+ return MinimalAction::ActOnDeclarator(S, D);
+ }
+ /// ActOnPopScope - This callback is called immediately before the specified
+ /// scope is popped and deleted.
+ virtual void ActOnPopScope(SourceLocation Loc, Scope *S) {
+ Out << __FUNCTION__ << "\n";
+ return MinimalAction::ActOnPopScope(Loc, S);
+ }
+
+ /// ActOnTranslationUnitScope - This callback is called once, immediately
+ /// after creating the translation unit scope (in Parser::Initialize).
+ virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
+ Out << __FUNCTION__ << "\n";
+ MinimalAction::ActOnTranslationUnitScope(Loc, S);
+ }
+
+
+ Action::DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassLoc,
+ IdentifierInfo *SuperName,
+ SourceLocation SuperLoc,
+ const DeclPtrTy *ProtoRefs,
+ unsigned NumProtocols,
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList) {
+ Out << __FUNCTION__ << "\n";
+ return MinimalAction::ActOnStartClassInterface(AtInterfaceLoc,
+ ClassName, ClassLoc,
+ SuperName, SuperLoc,
+ ProtoRefs, NumProtocols,
+ EndProtoLoc, AttrList);
+ }
+
+ /// ActOnForwardClassDeclaration -
+ /// Scope will always be top level file scope.
+ Action::DeclPtrTy ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
+ IdentifierInfo **IdentList,
+ unsigned NumElts) {
+ Out << __FUNCTION__ << "\n";
+ return MinimalAction::ActOnForwardClassDeclaration(AtClassLoc, IdentList,
+ NumElts);
+ }
+
+ // Pure Printing
+
+ /// ActOnParamDeclarator - This callback is invoked when a parameter
+ /// declarator is parsed. This callback only occurs for functions
+ /// with prototypes. S is the function prototype scope for the
+ /// parameters (C++ [basic.scope.proto]).
+ virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D) {
+ Out << __FUNCTION__ << " ";
+ if (IdentifierInfo *II = D.getIdentifier()) {
+ Out << "'" << II->getName() << "'";
+ } else {
+ Out << "<anon>";
+ }
+ Out << "\n";
+ return DeclPtrTy();
+ }
+
+ /// AddInitializerToDecl - This action is called immediately after
+ /// ParseDeclarator (when an initializer is present). The code is factored
+ /// this way to make sure we are able to handle the following:
+ /// void func() { int xx = xx; }
+ /// This allows ActOnDeclarator to register "xx" prior to parsing the
+ /// initializer. The declaration above should still result in a warning,
+ /// since the reference to "xx" is uninitialized.
+ virtual void AddInitializerToDecl(DeclPtrTy Dcl, ExprArg Init) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ /// FinalizeDeclaratorGroup - After a sequence of declarators are parsed,
+ /// this gives the actions implementation a chance to process the group as
+ /// a whole.
+ virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, DeclPtrTy *Group,
+ unsigned NumDecls) {
+ Out << __FUNCTION__ << "\n";
+ return DeclGroupPtrTy();
+ }
+
+ /// ActOnStartOfFunctionDef - This is called at the start of a function
+ /// definition, instead of calling ActOnDeclarator. The Declarator includes
+ /// information about formal arguments that are part of this function.
+ virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *FnBodyScope,
+ Declarator &D){
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ /// ActOnStartOfFunctionDef - This is called at the start of a function
+ /// definition, after the FunctionDecl has already been created.
+ virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual void ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ /// ActOnFunctionDefBody - This is called when a function body has completed
+ /// parsing. Decl is the DeclTy returned by ParseStartOfFunctionDef.
+ virtual DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual DeclPtrTy ActOnFileScopeAsmDecl(SourceLocation Loc,
+ ExprArg AsmString) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
+ /// no declarator (e.g. "struct foo;") is parsed.
+ virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ /// ActOnLinkageSpec - Parsed a C++ linkage-specification that
+ /// contained braces. Lang/StrSize contains the language string that
+ /// was parsed at location Loc. Decls/NumDecls provides the
+ /// declarations parsed inside the linkage specification.
+ virtual DeclPtrTy ActOnLinkageSpec(SourceLocation Loc,
+ SourceLocation LBrace,
+ SourceLocation RBrace, const char *Lang,
+ unsigned StrSize,
+ DeclPtrTy *Decls, unsigned NumDecls) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ /// ActOnLinkageSpec - Parsed a C++ linkage-specification without
+ /// braces. Lang/StrSize contains the language string that was
+ /// parsed at location Loc. D is the declaration parsed.
+ virtual DeclPtrTy ActOnLinkageSpec(SourceLocation Loc, const char *Lang,
+ unsigned StrSize, DeclPtrTy D) {
+ return DeclPtrTy();
+ }
+
+ //===------------------------------------------------------------------===//
+ // Type Parsing Callbacks.
+ //===------------------------------------------------------------------===//
+
+ virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) {
+ Out << __FUNCTION__ << "\n";
+ return TypeResult();
+ }
+
+ virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagType, TagKind TK,
+ SourceLocation KWLoc, const CXXScopeSpec &SS,
+ IdentifierInfo *Name, SourceLocation NameLoc,
+ AttributeList *Attr, AccessSpecifier AS) {
+ // TagType is an instance of DeclSpec::TST, indicating what kind of tag this
+ // is (struct/union/enum/class).
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ /// Act on @defs() element found when parsing a structure. ClassName is the
+ /// name of the referenced class.
+ virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
+ IdentifierInfo *ClassName,
+ llvm::SmallVectorImpl<DeclPtrTy> &Decls) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual DeclPtrTy ActOnField(Scope *S, DeclPtrTy TagD,
+ SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth,
+ tok::ObjCKeywordKind visibility) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual void ActOnFields(Scope* S, SourceLocation RecLoc, DeclPtrTy TagDecl,
+ DeclPtrTy *Fields, unsigned NumFields,
+ SourceLocation LBrac, SourceLocation RBrac,
+ AttributeList *AttrList) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual DeclPtrTy ActOnEnumConstant(Scope *S, DeclPtrTy EnumDecl,
+ DeclPtrTy LastEnumConstant,
+ SourceLocation IdLoc,IdentifierInfo *Id,
+ SourceLocation EqualLoc, ExprTy *Val) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
+ SourceLocation RBraceLoc, DeclPtrTy EnumDecl,
+ DeclPtrTy *Elements, unsigned NumElements) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ //===------------------------------------------------------------------===//
+ // Statement Parsing Callbacks.
+ //===------------------------------------------------------------------===//
+
+ virtual OwningStmtResult ActOnNullStmt(SourceLocation SemiLoc) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnCompoundStmt(SourceLocation L,
+ SourceLocation R,
+ MultiStmtArg Elts,
+ bool isStmtExpr) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnDeclStmt(DeclGroupPtrTy Decl,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnExprStmt(FullExprArg Expr) {
+ Out << __FUNCTION__ << "\n";
+ return OwningStmtResult(*this, Expr->release());
+ }
+
+ /// ActOnCaseStmt - Note that this handles the GNU 'case 1 ... 4' extension,
+ /// which can specify an RHS value.
+ virtual OwningStmtResult ActOnCaseStmt(SourceLocation CaseLoc,
+ ExprArg LHSVal,
+ SourceLocation DotDotDotLoc,
+ ExprArg RHSVal,
+ SourceLocation ColonLoc) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnDefaultStmt(SourceLocation DefaultLoc,
+ SourceLocation ColonLoc,
+ StmtArg SubStmt, Scope *CurScope){
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnLabelStmt(SourceLocation IdentLoc,
+ IdentifierInfo *II,
+ SourceLocation ColonLoc,
+ StmtArg SubStmt) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc,
+ FullExprArg CondVal, StmtArg ThenVal,
+ SourceLocation ElseLoc,
+ StmtArg ElseVal) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnStartOfSwitchStmt(ExprArg Cond) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
+ StmtArg Switch,
+ StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
+ FullExprArg Cond, StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
+ SourceLocation WhileLoc, ExprArg Cond){
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc,
+ SourceLocation LParenLoc,
+ StmtArg First, ExprArg Second,
+ ExprArg Third, SourceLocation RParenLoc,
+ StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnObjCForCollectionStmt(
+ SourceLocation ForColLoc,
+ SourceLocation LParenLoc,
+ StmtArg First, ExprArg Second,
+ SourceLocation RParenLoc, StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnGotoStmt(SourceLocation GotoLoc,
+ SourceLocation LabelLoc,
+ IdentifierInfo *LabelII) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc,
+ SourceLocation StarLoc,
+ ExprArg DestExp) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnContinueStmt(SourceLocation ContinueLoc,
+ Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnBreakStmt(SourceLocation GotoLoc,
+ Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc,
+ ExprArg RetValExp) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnAsmStmt(SourceLocation AsmLoc,
+ bool IsSimple,
+ bool IsVolatile,
+ unsigned NumOutputs,
+ unsigned NumInputs,
+ std::string *Names,
+ MultiExprArg Constraints,
+ MultiExprArg Exprs,
+ ExprArg AsmString,
+ MultiExprArg Clobbers,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ // Objective-c statements
+ virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
+ SourceLocation RParen,
+ DeclPtrTy Parm, StmtArg Body,
+ StmtArg CatchList) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc,
+ StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc,
+ StmtArg Try, StmtArg Catch,
+ StmtArg Finally) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
+ ExprArg Throw,
+ Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc,
+ ExprArg SynchExpr,
+ StmtArg SynchBody) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ // C++ Statements
+ virtual DeclPtrTy ActOnExceptionDeclarator(Scope *S, Declarator &D) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc,
+ DeclPtrTy ExceptionDecl,
+ StmtArg HandlerBlock) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc,
+ StmtArg TryBlock,
+ MultiStmtArg Handlers) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ //===------------------------------------------------------------------===//
+ // Expression Parsing Callbacks.
+ //===------------------------------------------------------------------===//
+
+ // Primary Expressions.
+
+ /// ActOnIdentifierExpr - Parse an identifier in expression context.
+ /// 'HasTrailingLParen' indicates whether or not the identifier has a '('
+ /// token immediately after it.
+ virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
+ IdentifierInfo &II,
+ bool HasTrailingLParen,
+ const CXXScopeSpec *SS,
+ bool isAddressOfOperand) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr(
+ Scope *S, SourceLocation OperatorLoc,
+ OverloadedOperatorKind Op,
+ bool HasTrailingLParen, const CXXScopeSpec &SS,
+ bool isAddressOfOperand) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXConversionFunctionExpr(
+ Scope *S, SourceLocation OperatorLoc,
+ TypeTy *Type, bool HasTrailingLParen,
+ const CXXScopeSpec &SS,bool isAddressOfOperand) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc,
+ tok::TokenKind Kind) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCharacterConstant(const Token &) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnNumericConstant(const Token &) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ /// ActOnStringLiteral - The specified tokens were lexed as pasted string
+ /// fragments (e.g. "foo" "bar" L"baz").
+ virtual OwningExprResult ActOnStringLiteral(const Token *Toks,
+ unsigned NumToks) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnParenExpr(SourceLocation L, SourceLocation R,
+ ExprArg Val) {
+ Out << __FUNCTION__ << "\n";
+ return move(Val); // Default impl returns operand.
+ }
+
+ // Postfix Expressions.
+ virtual OwningExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
+ tok::TokenKind Kind,
+ ExprArg Input) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnArraySubscriptExpr(Scope *S, ExprArg Base,
+ SourceLocation LLoc,
+ ExprArg Idx,
+ SourceLocation RLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation MemberLoc,
+ IdentifierInfo &Member,
+ DeclPtrTy ImplDecl) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCallExpr(Scope *S, ExprArg Fn,
+ SourceLocation LParenLoc,
+ MultiExprArg Args,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ // Unary Operators. 'Tok' is the token for the operator.
+ virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
+ tok::TokenKind Op, ExprArg Input) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult
+ ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
+ void *TyOrEx, const SourceRange &ArgRange) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParen,
+ TypeTy *Ty,
+ SourceLocation RParen,
+ ExprArg Op) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnInitList(SourceLocation LParenLoc,
+ MultiExprArg InitList,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
+ SourceLocation RParenLoc,ExprArg Op){
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc,
+ tok::TokenKind Kind,
+ ExprArg LHS, ExprArg RHS) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
+ /// in the case of a the GNU conditional expr extension.
+ virtual OwningExprResult ActOnConditionalOp(SourceLocation QuestionLoc,
+ SourceLocation ColonLoc,
+ ExprArg Cond, ExprArg LHS,
+ ExprArg RHS) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ //===--------------------- GNU Extension Expressions ------------------===//
+
+ virtual OwningExprResult ActOnAddrLabel(SourceLocation OpLoc,
+ SourceLocation LabLoc,
+ IdentifierInfo *LabelII) {// "&&foo"
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnStmtExpr(SourceLocation LPLoc,
+ StmtArg SubStmt,
+ SourceLocation RPLoc) { // "({..})"
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnBuiltinOffsetOf(Scope *S,
+ SourceLocation BuiltinLoc,
+ SourceLocation TypeLoc,
+ TypeTy *Arg1,
+ OffsetOfComponent *CompPtr,
+ unsigned NumComponents,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ // __builtin_types_compatible_p(type1, type2)
+ virtual OwningExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc,
+ TypeTy *arg1,TypeTy *arg2,
+ SourceLocation RPLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ // __builtin_choose_expr(constExpr, expr1, expr2)
+ virtual OwningExprResult ActOnChooseExpr(SourceLocation BuiltinLoc,
+ ExprArg cond, ExprArg expr1,
+ ExprArg expr2,
+ SourceLocation RPLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ // __builtin_va_arg(expr, type)
+ virtual OwningExprResult ActOnVAArg(SourceLocation BuiltinLoc,
+ ExprArg expr, TypeTy *type,
+ SourceLocation RPLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnGNUNullExpr(SourceLocation TokenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual OwningExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc,
+ StmtArg Body,
+ Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc,
+ IdentifierInfo *Ident,
+ SourceLocation LBrace) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual void ActOnFinishNamespaceDef(DeclPtrTy Dcl, SourceLocation RBrace) {
+ Out << __FUNCTION__ << "\n";
+ return;
+ }
+
+#if 0
+ // FIXME: AttrList should be deleted by this function, but the definition
+ // would have to be available.
+ virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope,
+ SourceLocation UsingLoc,
+ SourceLocation NamespcLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *NamespcName,
+ AttributeList *AttrList) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+#endif
+
+ virtual void ActOnParamDefaultArgument(DeclPtrTy param,
+ SourceLocation EqualLoc,
+ ExprArg defarg) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
+ SourceLocation EqualLoc) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnParamDefaultArgumentError(DeclPtrTy param) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
+ SourceLocation LParenLoc,
+ MultiExprArg Exprs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return;
+ }
+
+ virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S,
+ DeclPtrTy Method)
+ {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy Param) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S,
+ DeclPtrTy Method) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
+ ExprArg AssertExpr,
+ ExprArg AssertMessageExpr) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc,
+ tok::TokenKind Kind,
+ SourceLocation LAngleBracketLoc,
+ TypeTy *Ty,
+ SourceLocation RAngleBracketLoc,
+ SourceLocation LParenLoc,
+ ExprArg Op,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc,
+ SourceLocation LParenLoc,
+ bool isType, void *TyOrExpr,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXThis(SourceLocation ThisLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc,
+ tok::TokenKind Kind) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXThrow(SourceLocation OpLoc, ExprArg Op) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXTypeConstructExpr(SourceRange TypeRange,
+ TypeTy *TypeRep,
+ SourceLocation LParenLoc,
+ MultiExprArg Exprs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXConditionDeclarationExpr(Scope *S,
+ SourceLocation StartLoc,
+ Declarator &D,
+ SourceLocation EqualLoc,
+ ExprArg AssignExprVal) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXNew(SourceLocation StartLoc,
+ bool UseGlobal,
+ SourceLocation PlacementLParen,
+ MultiExprArg PlacementArgs,
+ SourceLocation PlacementRParen,
+ bool ParenTypeId, Declarator &D,
+ SourceLocation ConstructorLParen,
+ MultiExprArg ConstructorArgs,
+ SourceLocation ConstructorRParen) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXDelete(SourceLocation StartLoc,
+ bool UseGlobal, bool ArrayForm,
+ ExprArg Operand) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
+ SourceLocation KWLoc,
+ SourceLocation LParen,
+ TypeTy *Ty,
+ SourceLocation RParen) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ };
+}
+
+MinimalAction *clang::CreatePrintParserActionsAction(Preprocessor &PP,
+ llvm::raw_ostream* OS) {
+ return new ParserPrintActions(PP, *OS);
+}
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
new file mode 100644
index 0000000..6a7ad31
--- /dev/null
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -0,0 +1,467 @@
+//===--- PrintPreprocessedOutput.cpp - Implement the -E mode --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This code simply runs the preprocessor on the input file and prints out the
+// result. This is the traditional behavior of the -E option.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/Pragma.h"
+#include "clang/Lex/TokenConcatenation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/System/Path.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdio>
+using namespace clang;
+
+/// PrintMacroDefinition - Print a macro definition in a form that will be
+/// properly accepted back as a definition.
+static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI,
+ Preprocessor &PP, llvm::raw_ostream &OS) {
+ OS << "#define " << II.getName();
+
+ if (MI.isFunctionLike()) {
+ OS << '(';
+ if (MI.arg_empty())
+ ;
+ else if (MI.getNumArgs() == 1)
+ OS << (*MI.arg_begin())->getName();
+ else {
+ MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end();
+ OS << (*AI++)->getName();
+ while (AI != E)
+ OS << ',' << (*AI++)->getName();
+ }
+
+ if (MI.isVariadic()) {
+ if (!MI.arg_empty())
+ OS << ',';
+ OS << "...";
+ }
+ OS << ')';
+ }
+
+ // GCC always emits a space, even if the macro body is empty. However, do not
+ // want to emit two spaces if the first token has a leading space.
+ if (MI.tokens_empty() || !MI.tokens_begin()->hasLeadingSpace())
+ OS << ' ';
+
+ llvm::SmallVector<char, 128> SpellingBuffer;
+ for (MacroInfo::tokens_iterator I = MI.tokens_begin(), E = MI.tokens_end();
+ I != E; ++I) {
+ if (I->hasLeadingSpace())
+ OS << ' ';
+
+ // Make sure we have enough space in the spelling buffer.
+ if (I->getLength() < SpellingBuffer.size())
+ SpellingBuffer.resize(I->getLength());
+ const char *Buffer = &SpellingBuffer[0];
+ unsigned SpellingLen = PP.getSpelling(*I, Buffer);
+ OS.write(Buffer, SpellingLen);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Preprocessed token printer
+//===----------------------------------------------------------------------===//
+
+namespace {
+class PrintPPOutputPPCallbacks : public PPCallbacks {
+ Preprocessor &PP;
+ TokenConcatenation ConcatInfo;
+public:
+ llvm::raw_ostream &OS;
+private:
+ unsigned CurLine;
+ bool EmittedTokensOnThisLine;
+ SrcMgr::CharacteristicKind FileType;
+ llvm::SmallString<512> CurFilename;
+ bool Initialized;
+ bool DisableLineMarkers;
+ bool DumpDefines;
+public:
+ PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os,
+ bool lineMarkers, bool defines)
+ : PP(pp), ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers),
+ DumpDefines(defines) {
+ CurLine = 0;
+ CurFilename += "<uninit>";
+ EmittedTokensOnThisLine = false;
+ FileType = SrcMgr::C_User;
+ Initialized = false;
+ }
+
+ void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }
+ bool hasEmittedTokensOnThisLine() const { return EmittedTokensOnThisLine; }
+
+ virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType);
+ virtual void Ident(SourceLocation Loc, const std::string &str);
+ virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
+ const std::string &Str);
+
+
+ bool HandleFirstTokOnLine(Token &Tok);
+ bool MoveToLine(SourceLocation Loc);
+ bool AvoidConcat(const Token &PrevTok, const Token &Tok) {
+ return ConcatInfo.AvoidConcat(PrevTok, Tok);
+ }
+ void WriteLineInfo(unsigned LineNo, const char *Extra=0, unsigned ExtraLen=0);
+
+ /// MacroDefined - This hook is called whenever a macro definition is seen.
+ void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI);
+
+};
+} // end anonymous namespace
+
+void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo,
+ const char *Extra,
+ unsigned ExtraLen) {
+ if (EmittedTokensOnThisLine) {
+ OS << '\n';
+ EmittedTokensOnThisLine = false;
+ }
+
+ OS << '#' << ' ' << LineNo << ' ' << '"';
+ OS.write(&CurFilename[0], CurFilename.size());
+ OS << '"';
+
+ if (ExtraLen)
+ OS.write(Extra, ExtraLen);
+
+ if (FileType == SrcMgr::C_System)
+ OS.write(" 3", 2);
+ else if (FileType == SrcMgr::C_ExternCSystem)
+ OS.write(" 3 4", 4);
+ OS << '\n';
+}
+
+/// MoveToLine - Move the output to the source line specified by the location
+/// object. We can do this by emitting some number of \n's, or be emitting a
+/// #line directive. This returns false if already at the specified line, true
+/// if some newlines were emitted.
+bool PrintPPOutputPPCallbacks::MoveToLine(SourceLocation Loc) {
+ unsigned LineNo = PP.getSourceManager().getInstantiationLineNumber(Loc);
+
+ if (DisableLineMarkers) {
+ if (LineNo == CurLine) return false;
+
+ CurLine = LineNo;
+
+ if (!EmittedTokensOnThisLine)
+ return true;
+
+ OS << '\n';
+ EmittedTokensOnThisLine = false;
+ return true;
+ }
+
+ // If this line is "close enough" to the original line, just print newlines,
+ // otherwise print a #line directive.
+ if (LineNo-CurLine <= 8) {
+ if (LineNo-CurLine == 1)
+ OS << '\n';
+ else if (LineNo == CurLine)
+ return false; // Spelling line moved, but instantiation line didn't.
+ else {
+ const char *NewLines = "\n\n\n\n\n\n\n\n";
+ OS.write(NewLines, LineNo-CurLine);
+ }
+ } else {
+ WriteLineInfo(LineNo, 0, 0);
+ }
+
+ CurLine = LineNo;
+ return true;
+}
+
+
+/// FileChanged - Whenever the preprocessor enters or exits a #include file
+/// it invokes this handler. Update our conception of the current source
+/// position.
+void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
+ FileChangeReason Reason,
+ SrcMgr::CharacteristicKind NewFileType) {
+ // Unless we are exiting a #include, make sure to skip ahead to the line the
+ // #include directive was at.
+ SourceManager &SourceMgr = PP.getSourceManager();
+ if (Reason == PPCallbacks::EnterFile) {
+ SourceLocation IncludeLoc = SourceMgr.getPresumedLoc(Loc).getIncludeLoc();
+ if (IncludeLoc.isValid())
+ MoveToLine(IncludeLoc);
+ } else if (Reason == PPCallbacks::SystemHeaderPragma) {
+ MoveToLine(Loc);
+
+ // TODO GCC emits the # directive for this directive on the line AFTER the
+ // directive and emits a bunch of spaces that aren't needed. Emulate this
+ // strange behavior.
+ }
+
+ Loc = SourceMgr.getInstantiationLoc(Loc);
+ // FIXME: Should use presumed line #!
+ CurLine = SourceMgr.getInstantiationLineNumber(Loc);
+
+ if (DisableLineMarkers) return;
+
+ CurFilename.clear();
+ CurFilename += SourceMgr.getPresumedLoc(Loc).getFilename();
+ Lexer::Stringify(CurFilename);
+ FileType = NewFileType;
+
+ if (!Initialized) {
+ WriteLineInfo(CurLine);
+ Initialized = true;
+ }
+
+ switch (Reason) {
+ case PPCallbacks::EnterFile:
+ WriteLineInfo(CurLine, " 1", 2);
+ break;
+ case PPCallbacks::ExitFile:
+ WriteLineInfo(CurLine, " 2", 2);
+ break;
+ case PPCallbacks::SystemHeaderPragma:
+ case PPCallbacks::RenameFile:
+ WriteLineInfo(CurLine);
+ break;
+ }
+}
+
+/// Ident - Handle #ident directives when read by the preprocessor.
+///
+void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) {
+ MoveToLine(Loc);
+
+ OS.write("#ident ", strlen("#ident "));
+ OS.write(&S[0], S.size());
+ EmittedTokensOnThisLine = true;
+}
+
+/// MacroDefined - This hook is called whenever a macro definition is seen.
+void PrintPPOutputPPCallbacks::MacroDefined(const IdentifierInfo *II,
+ const MacroInfo *MI) {
+ // Only print out macro definitions in -dD mode.
+ if (!DumpDefines ||
+ // Ignore __FILE__ etc.
+ MI->isBuiltinMacro()) return;
+
+ MoveToLine(MI->getDefinitionLoc());
+ PrintMacroDefinition(*II, *MI, PP, OS);
+}
+
+
+void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
+ const IdentifierInfo *Kind,
+ const std::string &Str) {
+ MoveToLine(Loc);
+ OS << "#pragma comment(" << Kind->getName();
+
+ if (!Str.empty()) {
+ OS << ", \"";
+
+ for (unsigned i = 0, e = Str.size(); i != e; ++i) {
+ unsigned char Char = Str[i];
+ if (isprint(Char) && Char != '\\' && Char != '"')
+ OS << (char)Char;
+ else // Output anything hard as an octal escape.
+ OS << '\\'
+ << (char)('0'+ ((Char >> 6) & 7))
+ << (char)('0'+ ((Char >> 3) & 7))
+ << (char)('0'+ ((Char >> 0) & 7));
+ }
+ OS << '"';
+ }
+
+ OS << ')';
+ EmittedTokensOnThisLine = true;
+}
+
+
+/// HandleFirstTokOnLine - When emitting a preprocessed file in -E mode, this
+/// is called for the first token on each new line. If this really is the start
+/// of a new logical line, handle it and return true, otherwise return false.
+/// This may not be the start of a logical line because the "start of line"
+/// marker is set for spelling lines, not instantiation ones.
+bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) {
+ // Figure out what line we went to and insert the appropriate number of
+ // newline characters.
+ if (!MoveToLine(Tok.getLocation()))
+ return false;
+
+ // Print out space characters so that the first token on a line is
+ // indented for easy reading.
+ const SourceManager &SourceMgr = PP.getSourceManager();
+ unsigned ColNo = SourceMgr.getInstantiationColumnNumber(Tok.getLocation());
+
+ // This hack prevents stuff like:
+ // #define HASH #
+ // HASH define foo bar
+ // From having the # character end up at column 1, which makes it so it
+ // is not handled as a #define next time through the preprocessor if in
+ // -fpreprocessed mode.
+ if (ColNo <= 1 && Tok.is(tok::hash))
+ OS << ' ';
+
+ // Otherwise, indent the appropriate number of spaces.
+ for (; ColNo > 1; --ColNo)
+ OS << ' ';
+
+ return true;
+}
+
+namespace {
+struct UnknownPragmaHandler : public PragmaHandler {
+ const char *Prefix;
+ PrintPPOutputPPCallbacks *Callbacks;
+
+ UnknownPragmaHandler(const char *prefix, PrintPPOutputPPCallbacks *callbacks)
+ : PragmaHandler(0), Prefix(prefix), Callbacks(callbacks) {}
+ virtual void HandlePragma(Preprocessor &PP, Token &PragmaTok) {
+ // Figure out what line we went to and insert the appropriate number of
+ // newline characters.
+ Callbacks->MoveToLine(PragmaTok.getLocation());
+ Callbacks->OS.write(Prefix, strlen(Prefix));
+
+ // Read and print all of the pragma tokens.
+ while (PragmaTok.isNot(tok::eom)) {
+ if (PragmaTok.hasLeadingSpace())
+ Callbacks->OS << ' ';
+ std::string TokSpell = PP.getSpelling(PragmaTok);
+ Callbacks->OS.write(&TokSpell[0], TokSpell.size());
+ PP.LexUnexpandedToken(PragmaTok);
+ }
+ Callbacks->OS << '\n';
+ }
+};
+} // end anonymous namespace
+
+
+static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
+ PrintPPOutputPPCallbacks *Callbacks,
+ llvm::raw_ostream &OS) {
+ char Buffer[256];
+ Token PrevTok;
+ while (1) {
+
+ // If this token is at the start of a line, emit newlines if needed.
+ if (Tok.isAtStartOfLine() && Callbacks->HandleFirstTokOnLine(Tok)) {
+ // done.
+ } else if (Tok.hasLeadingSpace() ||
+ // If we haven't emitted a token on this line yet, PrevTok isn't
+ // useful to look at and no concatenation could happen anyway.
+ (Callbacks->hasEmittedTokensOnThisLine() &&
+ // Don't print "-" next to "-", it would form "--".
+ Callbacks->AvoidConcat(PrevTok, Tok))) {
+ OS << ' ';
+ }
+
+ if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
+ OS.write(II->getName(), II->getLength());
+ } else if (Tok.isLiteral() && !Tok.needsCleaning() &&
+ Tok.getLiteralData()) {
+ OS.write(Tok.getLiteralData(), Tok.getLength());
+ } else if (Tok.getLength() < 256) {
+ const char *TokPtr = Buffer;
+ unsigned Len = PP.getSpelling(Tok, TokPtr);
+ OS.write(TokPtr, Len);
+ } else {
+ std::string S = PP.getSpelling(Tok);
+ OS.write(&S[0], S.size());
+ }
+ Callbacks->SetEmittedTokensOnThisLine();
+
+ if (Tok.is(tok::eof)) break;
+
+ PrevTok = Tok;
+ PP.Lex(Tok);
+ }
+}
+
+namespace {
+ struct SortMacrosByID {
+ typedef std::pair<IdentifierInfo*, MacroInfo*> id_macro_pair;
+ bool operator()(const id_macro_pair &LHS, const id_macro_pair &RHS) const {
+ return strcmp(LHS.first->getName(), RHS.first->getName()) < 0;
+ }
+ };
+}
+
+void clang::DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
+ // -dM mode just scans and ignores all tokens in the files, then dumps out
+ // the macro table at the end.
+ PP.EnterMainSourceFile();
+
+ Token Tok;
+ do PP.Lex(Tok);
+ while (Tok.isNot(tok::eof));
+
+ std::vector<std::pair<IdentifierInfo*, MacroInfo*> > MacrosByID;
+ for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
+ I != E; ++I)
+ MacrosByID.push_back(*I);
+ std::sort(MacrosByID.begin(), MacrosByID.end(), SortMacrosByID());
+
+ for (unsigned i = 0, e = MacrosByID.size(); i != e; ++i) {
+ MacroInfo &MI = *MacrosByID[i].second;
+ // Ignore computed macros like __LINE__ and friends.
+ if (MI.isBuiltinMacro()) continue;
+
+ PrintMacroDefinition(*MacrosByID[i].first, MI, PP, *OS);
+ *OS << "\n";
+ }
+}
+
+/// DoPrintPreprocessedInput - This implements -E mode.
+///
+void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS,
+ bool EnableCommentOutput,
+ bool EnableMacroCommentOutput,
+ bool DisableLineMarkers,
+ bool DumpDefines) {
+ // Inform the preprocessor whether we want it to retain comments or not, due
+ // to -C or -CC.
+ PP.SetCommentRetentionState(EnableCommentOutput, EnableMacroCommentOutput);
+
+ OS->SetBufferSize(64*1024);
+
+ PrintPPOutputPPCallbacks *Callbacks =
+ new PrintPPOutputPPCallbacks(PP, *OS, DisableLineMarkers, DumpDefines);
+ PP.AddPragmaHandler(0, new UnknownPragmaHandler("#pragma", Callbacks));
+ PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC",
+ Callbacks));
+
+ PP.setPPCallbacks(Callbacks);
+
+ // After we have configured the preprocessor, enter the main file.
+ PP.EnterMainSourceFile();
+
+ // Consume all of the tokens that come from the predefines buffer. Those
+ // should not be emitted into the output and are guaranteed to be at the
+ // start.
+ const SourceManager &SourceMgr = PP.getSourceManager();
+ Token Tok;
+ do PP.Lex(Tok);
+ while (Tok.isNot(tok::eof) && Tok.getLocation().isFileID() &&
+ !strcmp(SourceMgr.getPresumedLoc(Tok.getLocation()).getFilename(),
+ "<built-in>"));
+
+ // Read all the preprocessed tokens, printing them out to the stream.
+ PrintPreprocessedTokens(PP, Tok, Callbacks, *OS);
+ *OS << '\n';
+}
+
diff --git a/lib/Frontend/RewriteMacros.cpp b/lib/Frontend/RewriteMacros.cpp
new file mode 100644
index 0000000..5ef4892
--- /dev/null
+++ b/lib/Frontend/RewriteMacros.cpp
@@ -0,0 +1,215 @@
+//===--- RewriteMacros.cpp - Rewrite macros into their expansions ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This code rewrites macro invocations into their expansions. This gives you
+// a macro expanded file that retains comments and #includes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+#include "llvm/ADT/OwningPtr.h"
+using namespace clang;
+
+/// isSameToken - Return true if the two specified tokens start have the same
+/// content.
+static bool isSameToken(Token &RawTok, Token &PPTok) {
+ // If two tokens have the same kind and the same identifier info, they are
+ // obviously the same.
+ if (PPTok.getKind() == RawTok.getKind() &&
+ PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo())
+ return true;
+
+ // Otherwise, if they are different but have the same identifier info, they
+ // are also considered to be the same. This allows keywords and raw lexed
+ // identifiers with the same name to be treated the same.
+ if (PPTok.getIdentifierInfo() &&
+ PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo())
+ return true;
+
+ return false;
+}
+
+
+/// GetNextRawTok - Return the next raw token in the stream, skipping over
+/// comments if ReturnComment is false.
+static const Token &GetNextRawTok(const std::vector<Token> &RawTokens,
+ unsigned &CurTok, bool ReturnComment) {
+ assert(CurTok < RawTokens.size() && "Overran eof!");
+
+ // If the client doesn't want comments and we have one, skip it.
+ if (!ReturnComment && RawTokens[CurTok].is(tok::comment))
+ ++CurTok;
+
+ return RawTokens[CurTok++];
+}
+
+
+/// LexRawTokensFromMainFile - Lets all the raw tokens from the main file into
+/// the specified vector.
+static void LexRawTokensFromMainFile(Preprocessor &PP,
+ std::vector<Token> &RawTokens) {
+ SourceManager &SM = PP.getSourceManager();
+
+ // Create a lexer to lex all the tokens of the main file in raw mode. Even
+ // though it is in raw mode, it will not return comments.
+ Lexer RawLex(SM.getMainFileID(), SM, PP.getLangOptions());
+
+ // Switch on comment lexing because we really do want them.
+ RawLex.SetCommentRetentionState(true);
+
+ Token RawTok;
+ do {
+ RawLex.LexFromRawLexer(RawTok);
+
+ // If we have an identifier with no identifier info for our raw token, look
+ // up the indentifier info. This is important for equality comparison of
+ // identifier tokens.
+ if (RawTok.is(tok::identifier) && !RawTok.getIdentifierInfo())
+ RawTok.setIdentifierInfo(PP.LookUpIdentifierInfo(RawTok));
+
+ RawTokens.push_back(RawTok);
+ } while (RawTok.isNot(tok::eof));
+}
+
+
+/// RewriteMacrosInInput - Implement -rewrite-macros mode.
+void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) {
+ SourceManager &SM = PP.getSourceManager();
+
+ Rewriter Rewrite;
+ Rewrite.setSourceMgr(SM, PP.getLangOptions());
+ RewriteBuffer &RB = Rewrite.getEditBuffer(SM.getMainFileID());
+
+ std::vector<Token> RawTokens;
+ LexRawTokensFromMainFile(PP, RawTokens);
+ unsigned CurRawTok = 0;
+ Token RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
+
+
+ // Get the first preprocessing token.
+ PP.EnterMainSourceFile();
+ Token PPTok;
+ PP.Lex(PPTok);
+
+ // Preprocess the input file in parallel with raw lexing the main file. Ignore
+ // all tokens that are preprocessed from a file other than the main file (e.g.
+ // a header). If we see tokens that are in the preprocessed file but not the
+ // lexed file, we have a macro expansion. If we see tokens in the lexed file
+ // that aren't in the preprocessed view, we have macros that expand to no
+ // tokens, or macro arguments etc.
+ while (RawTok.isNot(tok::eof) || PPTok.isNot(tok::eof)) {
+ SourceLocation PPLoc = SM.getInstantiationLoc(PPTok.getLocation());
+
+ // If PPTok is from a different source file, ignore it.
+ if (!SM.isFromMainFile(PPLoc)) {
+ PP.Lex(PPTok);
+ continue;
+ }
+
+ // If the raw file hits a preprocessor directive, they will be extra tokens
+ // in the raw file that don't exist in the preprocsesed file. However, we
+ // choose to preserve them in the output file and otherwise handle them
+ // specially.
+ if (RawTok.is(tok::hash) && RawTok.isAtStartOfLine()) {
+ // If this is a #warning directive or #pragma mark (GNU extensions),
+ // comment the line out.
+ if (RawTokens[CurRawTok].is(tok::identifier)) {
+ const IdentifierInfo *II = RawTokens[CurRawTok].getIdentifierInfo();
+ if (!strcmp(II->getName(), "warning")) {
+ // Comment out #warning.
+ RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//", 2);
+ } else if (!strcmp(II->getName(), "pragma") &&
+ RawTokens[CurRawTok+1].is(tok::identifier) &&
+ !strcmp(RawTokens[CurRawTok+1].getIdentifierInfo()->getName(),
+ "mark")){
+ // Comment out #pragma mark.
+ RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//", 2);
+ }
+ }
+
+ // Otherwise, if this is a #include or some other directive, just leave it
+ // in the file by skipping over the line.
+ RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
+ while (!RawTok.isAtStartOfLine() && RawTok.isNot(tok::eof))
+ RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
+ continue;
+ }
+
+ // Okay, both tokens are from the same file. Get their offsets from the
+ // start of the file.
+ unsigned PPOffs = SM.getFileOffset(PPLoc);
+ unsigned RawOffs = SM.getFileOffset(RawTok.getLocation());
+
+ // If the offsets are the same and the token kind is the same, ignore them.
+ if (PPOffs == RawOffs && isSameToken(RawTok, PPTok)) {
+ RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
+ PP.Lex(PPTok);
+ continue;
+ }
+
+ // If the PP token is farther along than the raw token, something was
+ // deleted. Comment out the raw token.
+ if (RawOffs <= PPOffs) {
+ // Comment out a whole run of tokens instead of bracketing each one with
+ // comments. Add a leading space if RawTok didn't have one.
+ bool HasSpace = RawTok.hasLeadingSpace();
+ RB.InsertTextAfter(RawOffs, " /*"+HasSpace, 2+!HasSpace);
+ unsigned EndPos;
+
+ do {
+ EndPos = RawOffs+RawTok.getLength();
+
+ RawTok = GetNextRawTok(RawTokens, CurRawTok, true);
+ RawOffs = SM.getFileOffset(RawTok.getLocation());
+
+ if (RawTok.is(tok::comment)) {
+ // Skip past the comment.
+ RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
+ break;
+ }
+
+ } while (RawOffs <= PPOffs && !RawTok.isAtStartOfLine() &&
+ (PPOffs != RawOffs || !isSameToken(RawTok, PPTok)));
+
+ RB.InsertTextBefore(EndPos, "*/", 2);
+ continue;
+ }
+
+ // Otherwise, there was a replacement an expansion. Insert the new token
+ // in the output buffer. Insert the whole run of new tokens at once to get
+ // them in the right order.
+ unsigned InsertPos = PPOffs;
+ std::string Expansion;
+ while (PPOffs < RawOffs) {
+ Expansion += ' ' + PP.getSpelling(PPTok);
+ PP.Lex(PPTok);
+ PPLoc = SM.getInstantiationLoc(PPTok.getLocation());
+ PPOffs = SM.getFileOffset(PPLoc);
+ }
+ Expansion += ' ';
+ RB.InsertTextBefore(InsertPos, &Expansion[0], Expansion.size());
+ }
+
+ // Get the buffer corresponding to MainFileID. If we haven't changed it, then
+ // we are done.
+ if (const RewriteBuffer *RewriteBuf =
+ Rewrite.getRewriteBufferFor(SM.getMainFileID())) {
+ //printf("Changed:\n");
+ *OS << std::string(RewriteBuf->begin(), RewriteBuf->end());
+ } else {
+ fprintf(stderr, "No changes\n");
+ }
+ OS->flush();
+}
diff --git a/lib/Frontend/RewriteTest.cpp b/lib/Frontend/RewriteTest.cpp
new file mode 100644
index 0000000..f9eb58f
--- /dev/null
+++ b/lib/Frontend/RewriteTest.cpp
@@ -0,0 +1,39 @@
+//===--- RewriteTest.cpp - Rewriter playground ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a testbed.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Rewrite/TokenRewriter.h"
+#include "llvm/Support/raw_ostream.h"
+
+void clang::DoRewriteTest(Preprocessor &PP, llvm::raw_ostream* OS) {
+ SourceManager &SM = PP.getSourceManager();
+ const LangOptions &LangOpts = PP.getLangOptions();
+
+ TokenRewriter Rewriter(SM.getMainFileID(), SM, LangOpts);
+
+ // Throw <i> </i> tags around comments.
+ for (TokenRewriter::token_iterator I = Rewriter.token_begin(),
+ E = Rewriter.token_end(); I != E; ++I) {
+ if (I->isNot(tok::comment)) continue;
+
+ Rewriter.AddTokenBefore(I, "<i>");
+ Rewriter.AddTokenAfter(I, "</i>");
+ }
+
+
+ // Print out the output.
+ for (TokenRewriter::token_iterator I = Rewriter.token_begin(),
+ E = Rewriter.token_end(); I != E; ++I)
+ *OS << PP.getSpelling(*I);
+}
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
new file mode 100644
index 0000000..8d6ca68
--- /dev/null
+++ b/lib/Frontend/Warnings.cpp
@@ -0,0 +1,106 @@
+//===--- Warnings.cpp - C-Language Front-end ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Command line warning options handler.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is responsible for handling all warning options. This includes
+// a number of -Wfoo options and their variants, which are driven by TableGen-
+// generated data, and the special cases -pedantic, -pedantic-errors, -w and
+// -Werror.
+//
+// Each warning option controls any number of actual warnings.
+// Given a warning option 'foo', the following are valid:
+// -Wfoo, -Wno-foo, -Werror=foo
+//
+#include "clang/Frontend/Utils.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "llvm/Support/CommandLine.h"
+#include <cstdio>
+#include <utility>
+#include <algorithm>
+using namespace clang;
+
+bool clang::ProcessWarningOptions(Diagnostic &Diags,
+ std::vector<std::string> &Warnings,
+ bool Pedantic, bool PedanticErrors,
+ bool NoWarnings) {
+ Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers
+ Diags.setIgnoreAllWarnings(NoWarnings);
+
+ // If -pedantic or -pedantic-errors was specified, then we want to map all
+ // extension diagnostics onto WARNING or ERROR unless the user has futz'd
+ // around with them explicitly.
+ if (PedanticErrors)
+ Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Error);
+ else if (Pedantic)
+ Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Warn);
+ else
+ Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Ignore);
+
+ // FIXME: -Wfatal-errors / -Wfatal-errors=foo
+
+ for (unsigned i = 0, e = Warnings.size(); i != e; ++i) {
+ const std::string &Opt = Warnings[i];
+ const char *OptStart = &Opt[0];
+ const char *OptEnd = OptStart+Opt.size();
+ assert(*OptEnd == 0 && "Expect null termination for lower-bound search");
+
+ // Check to see if this warning starts with "no-", if so, this is a negative
+ // form of the option.
+ bool isPositive = true;
+ if (OptEnd-OptStart > 3 && memcmp(OptStart, "no-", 3) == 0) {
+ isPositive = false;
+ OptStart += 3;
+ }
+
+ // Figure out how this option affects the warning. If -Wfoo, map the
+ // diagnostic to a warning, if -Wno-foo, map it to ignore.
+ diag::Mapping Mapping = isPositive ? diag::MAP_WARNING : diag::MAP_IGNORE;
+
+ // -Wsystem-headers is a special case, not driven by the option table. It
+ // cannot be controlled with -Werror.
+ if (OptEnd-OptStart == 14 && memcmp(OptStart, "system-headers", 14) == 0) {
+ Diags.setSuppressSystemWarnings(!isPositive);
+ continue;
+ }
+
+ // -Werror/-Wno-error is a special case, not controlled by the option table.
+ // It also has the "specifier" form of -Werror=foo and -Werror-foo.
+ if (OptEnd-OptStart >= 5 && memcmp(OptStart, "error", 5) == 0) {
+ const char *Specifier = 0;
+ if (OptEnd-OptStart != 5) { // Specifier must be present.
+ if ((OptStart[5] != '=' && OptStart[5] != '-') ||
+ OptEnd-OptStart == 6) {
+ fprintf(stderr, "warning: unknown -Werror warning specifier: -W%s\n",
+ Opt.c_str());
+ continue;
+ }
+ Specifier = OptStart+6;
+ }
+
+ if (Specifier == 0) {
+ Diags.setWarningsAsErrors(true);
+ continue;
+ }
+
+ // -Werror=foo maps foo to Error, -Wno-error=foo maps it to Warning.
+ Mapping = isPositive ? diag::MAP_ERROR : diag::MAP_WARNING_NO_WERROR;
+ OptStart = Specifier;
+ }
+
+ if (Diags.setDiagnosticGroupMapping(OptStart, Mapping))
+ fprintf(stderr, "warning: unknown warning option: -W%s\n", Opt.c_str());
+ }
+
+ return false;
+}