From b09f6e15c59b89d5820db8ef40598eb1d1323c1f Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Tue, 19 May 2009 04:14:29 +0000 Subject: 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 --- lib/Frontend/CacheTokens.cpp | 658 ++++++++++++++++++++++++ lib/Frontend/DependencyFile.cpp | 171 +++++++ lib/Frontend/DiagChecker.cpp | 301 +++++++++++ lib/Frontend/PrintParserCallbacks.cpp | 829 +++++++++++++++++++++++++++++++ lib/Frontend/PrintPreprocessedOutput.cpp | 467 +++++++++++++++++ lib/Frontend/RewriteMacros.cpp | 215 ++++++++ lib/Frontend/RewriteTest.cpp | 39 ++ lib/Frontend/Warnings.cpp | 106 ++++ 8 files changed, 2786 insertions(+) create mode 100644 lib/Frontend/CacheTokens.cpp create mode 100644 lib/Frontend/DependencyFile.cpp create mode 100644 lib/Frontend/DiagChecker.cpp create mode 100644 lib/Frontend/PrintParserCallbacks.cpp create mode 100644 lib/Frontend/PrintPreprocessedOutput.cpp create mode 100644 lib/Frontend/RewriteMacros.cpp create mode 100644 lib/Frontend/RewriteTest.cpp create mode 100644 lib/Frontend/Warnings.cpp (limited to 'lib') diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp new file mode 100644 index 0000000000..0065828c6d --- /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 + 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 PTHMap; +typedef llvm::DenseMap IDMap; +typedef llvm::StringMap 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*> 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 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 *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 > PPCondTable; + PPCondTable PPCond; + std::vector 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*>::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 &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 + 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 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 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 0000000000..4cee280ebf --- /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 + +using namespace clang; + +namespace { +class VISIBILITY_HIDDEN DependencyFileCallback : public PPCallbacks { + std::vector Files; + llvm::StringSet<> FilesSet; + const Preprocessor *PP; + std::vector 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 &_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 &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("", 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::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::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::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 0000000000..2eaf2fe62f --- /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- {{diag text}}", where is one of "error", +// "warning" or "note", and 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(*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 0000000000..e9aece968f --- /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 << ""; + } + 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 << ""; + } + 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 &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 O