From: Nico Weber Date: Sun, 10 Aug 2008 19:59:06 +0000 (+0000) Subject: * Remove isInSystemHeader() from DiagClient, move it to SourceManager X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7bfaaaecb3113f955db31e8d8a51acffd1bc0c27;p=clang * Remove isInSystemHeader() from DiagClient, move it to SourceManager * Move FormatError() from TextDiagnostic up to DiagClient, remove now empty class TextDiagnostic * Make DiagClient optional for Diagnostic This fixes the following problems: * -html-diags (and probably others) does now output the same set of warnings as console clang does * nothing crashes if one forgets to call setHeaderSearch() on TextDiagnostic * some code duplication is removed git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@54620 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Driver/DiagChecker.cpp b/Driver/DiagChecker.cpp index e11d2f0c6a..660d17add2 100644 --- a/Driver/DiagChecker.cpp +++ b/Driver/DiagChecker.cpp @@ -183,8 +183,11 @@ static bool CompareDiagLists(SourceManager &SourceMgr, static bool CheckResults(Preprocessor &PP, const DiagList &ExpectedErrors, const DiagList &ExpectedWarnings) { + const DiagnosticClient *DiagClient = PP.getDiagnostics().getClient(); + assert(DiagClient != 0 && + "DiagChecker requires a valid TextDiagnosticBuffer"); const TextDiagnosticBuffer &Diags = - static_cast(PP.getDiagnostics().getClient()); + static_cast(*DiagClient); SourceManager &SourceMgr = PP.getSourceManager(); // We want to capture the delta between what was expected and what was diff --git a/Driver/clang.cpp b/Driver/clang.cpp index 8bafbd5078..f35e318933 100644 --- a/Driver/clang.cpp +++ b/Driver/clang.cpp @@ -1344,14 +1344,14 @@ static void ProcessSerializedFile(const std::string& InFile, Diagnostic& Diag, llvm::OwningPtr Consumer(CreateASTConsumer(InFile, Diag, FileMgr, TU->getLangOptions(), 0, 0)); - + if (!Consumer) { fprintf(stderr, "Unsupported program action with serialized ASTs!\n"); exit (1); } - + Consumer->Initialize(TU->getContext()); - + // FIXME: We need to inform Consumer about completed TagDecls as well. for (TranslationUnit::iterator I=TU->begin(), E=TU->end(); I!=E; ++I) Consumer->HandleTopLevelDecl(*I); @@ -1387,7 +1387,7 @@ int main(int argc, char **argv) { // Create the diagnostic client for reporting errors or for // implementing -verify. - TextDiagnostics* TextDiagClient = 0; + DiagnosticClient* TextDiagClient = 0; if (!VerifyDiagnostics) { // Print diagnostics to stderr by default. @@ -1460,7 +1460,6 @@ int main(int argc, char **argv) { // Process the -I options and set them in the HeaderInfo. HeaderSearch HeaderInfo(FileMgr); - if (TextDiagClient) TextDiagClient->setHeaderSearch(HeaderInfo); // FIXME: Sink IncludeGroup into this loop. IncludeGroup[0].clear(); diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index f214091272..c23abdcd0f 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -76,16 +76,17 @@ private: /// CustomDiagInfo - Information for uniquing and looking up custom diags. diag::CustomDiagInfo *CustomDiagInfo; + public: - explicit Diagnostic(DiagnosticClient *client); + explicit Diagnostic(DiagnosticClient *client = 0); ~Diagnostic(); //===--------------------------------------------------------------------===// // Diagnostic characterization methods, used by a client to customize how // - DiagnosticClient &getClient() { return *Client; }; - const DiagnosticClient &getClient() const { return *Client; }; + DiagnosticClient *getClient() { return Client; }; + const DiagnosticClient *getClient() const { return Client; }; void setClient(DiagnosticClient* client) { Client = client; } @@ -181,13 +182,14 @@ public: /// DiagnosticClient - This is an abstract interface implemented by clients of /// the front-end, which formats and prints fully processed diagnostics. class DiagnosticClient { +protected: + std::string FormatDiagnostic(Diagnostic &Diags, Diagnostic::Level Level, + diag::kind ID, + const std::string *Strs, + unsigned NumStrs); public: virtual ~DiagnosticClient(); - /// isInSystemHeader - If the client can tell that this is a system header, - /// return true. - virtual bool isInSystemHeader(FullSourceLoc Pos) const { return false; } - /// HandleDiagnostic - Handle this diagnostic, reporting it to the user or /// capturing it to a log as needed. virtual void HandleDiagnostic(Diagnostic &Diags, diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h index 6bc45057d5..145e1c8487 100644 --- a/include/clang/Basic/SourceLocation.h +++ b/include/clang/Basic/SourceLocation.h @@ -246,6 +246,8 @@ public: const char* getSourceName() const; const FileEntry* getFileEntryForLoc() const; + + bool isInSystemHeader() const; bool isFileID() const { return Loc.isFileID(); } diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index 7cb1f4c4ba..7cc4087db8 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -112,25 +112,30 @@ namespace SrcMgr { /// ChunkNo - Really large buffers are broken up into chunks that are /// each (1 << SourceLocation::FilePosBits) in size. This specifies the /// chunk number of this FileID. - unsigned ChunkNo; + unsigned ChunkNo:30; + + /// isSystemHeader - Set for system header files. + bool isSysHeader:1; /// Content - Information about the source buffer itself. const ContentCache* Content; - + public: /// get - Return a FileIDInfo object. static FileIDInfo get(SourceLocation IL, unsigned CN, - const ContentCache *Con) { + const ContentCache *Con, bool SysHeader) { FileIDInfo X; X.IncludeLoc = IL; X.ChunkNo = CN; X.Content = Con; + X.isSysHeader = SysHeader; return X; } SourceLocation getIncludeLoc() const { return IncludeLoc; } unsigned getChunkNo() const { return ChunkNo; } const ContentCache* getContentCache() const { return Content; } + bool isSystemHeader() const { return isSysHeader; } /// Emit - Emit this FileIDInfo to Bitcode. void Emit(llvm::Serializer& S) const; @@ -244,10 +249,11 @@ public: /// createFileID - Create a new FileID that represents the specified file /// being #included from the specified IncludePosition. This returns 0 on /// error and translates NULL into standard input. - unsigned createFileID(const FileEntry *SourceFile, SourceLocation IncludePos){ + unsigned createFileID(const FileEntry *SourceFile, SourceLocation IncludePos, + bool isSysHeader = false) { const SrcMgr::ContentCache *IR = getContentCache(SourceFile); if (IR == 0) return 0; // Error opening file? - return createFileID(IR, IncludePos); + return createFileID(IR, IncludePos, isSysHeader); } /// createMainFileID - Create the FileID for the main source file. @@ -262,8 +268,10 @@ public: /// createFileIDForMemBuffer - Create a new FileID that represents the /// specified memory buffer. This does no caching of the buffer and takes /// ownership of the MemoryBuffer, so only pass a MemoryBuffer to this once. - unsigned createFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer) { - return createFileID(createMemBufferContentCache(Buffer), SourceLocation()); + unsigned createFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer, + bool isSysHeader = false) { + return createFileID(createMemBufferContentCache(Buffer), SourceLocation(), + isSysHeader); } /// createMainFileIDForMembuffer - Create the FileID for a memory buffer @@ -421,6 +429,12 @@ public: bool isFromMainFile(SourceLocation Loc) const { return getCanonicalFileID(Loc) == getMainFileID(); } + + /// isInSystemHeader - Returns if a SourceLocation is in a system header. + bool isInSystemHeader(SourceLocation Loc) const { + assert (Loc.isFileID() && "method only valid for file ids"); + return getFIDInfo(Loc.getFileID())->isSystemHeader(); + } /// PrintStats - Print statistics to stderr. /// @@ -440,7 +454,7 @@ private: /// include position. This works regardless of whether the ContentCache /// corresponds to a file or some other input source. unsigned createFileID(const SrcMgr::ContentCache* File, - SourceLocation IncludePos); + SourceLocation IncludePos, bool isSysHeader = false); /// getContentCache - Create or return a cached ContentCache for the specified /// file. This returns null on failure. diff --git a/include/clang/Driver/TextDiagnosticBuffer.h b/include/clang/Driver/TextDiagnosticBuffer.h index 99df075fb4..76dfeaf305 100644 --- a/include/clang/Driver/TextDiagnosticBuffer.h +++ b/include/clang/Driver/TextDiagnosticBuffer.h @@ -14,7 +14,7 @@ #ifndef DRIVER_TEXT_DIAGNOSTIC_BUFFER_H_ #define DRIVER_TEXT_DIAGNOSTIC_BUFFER_H_ -#include "clang/Driver/TextDiagnostics.h" +#include "clang/Basic/Diagnostic.h" #include namespace clang { @@ -22,7 +22,7 @@ namespace clang { class Preprocessor; class SourceManager; -class TextDiagnosticBuffer : public TextDiagnostics { +class TextDiagnosticBuffer : public DiagnosticClient { public: typedef std::vector > DiagList; typedef DiagList::iterator iterator; @@ -30,8 +30,6 @@ public: private: DiagList Errors, Warnings; public: - TextDiagnosticBuffer() {} - const_iterator err_begin() const { return Errors.begin(); } const_iterator err_end() const { return Errors.end(); } diff --git a/include/clang/Driver/TextDiagnosticPrinter.h b/include/clang/Driver/TextDiagnosticPrinter.h index 03ac65a247..1d609ced4d 100644 --- a/include/clang/Driver/TextDiagnosticPrinter.h +++ b/include/clang/Driver/TextDiagnosticPrinter.h @@ -15,14 +15,14 @@ #ifndef TEXT_DIAGNOSTIC_PRINTER_H_ #define TEXT_DIAGNOSTIC_PRINTER_H_ -#include "clang/Driver/TextDiagnostics.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceLocation.h" #include "llvm/Support/Streams.h" namespace clang { class SourceManager; -class TextDiagnosticPrinter : public TextDiagnostics { +class TextDiagnosticPrinter : public DiagnosticClient { FullSourceLoc LastWarningLoc; FullSourceLoc LastLoc; llvm::OStream OS; diff --git a/include/clang/Driver/TextDiagnostics.h b/include/clang/Driver/TextDiagnostics.h deleted file mode 100644 index 9b8d9fb27d..0000000000 --- a/include/clang/Driver/TextDiagnostics.h +++ /dev/null @@ -1,50 +0,0 @@ -//===--- TextDiagnostics.h - Text Diagnostics Checkers ----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is the parent class for all text diagnostics. -// -//===----------------------------------------------------------------------===// - -#ifndef TEXT_DIAGNOSTICS_H_ -#define TEXT_DIAGNOSTICS_H_ - -#include "clang/Basic/Diagnostic.h" - -namespace clang { -class SourceManager; -class HeaderSearch; -class Preprocessor; - -class TextDiagnostics : public DiagnosticClient { - HeaderSearch *TheHeaderSearch; -protected: - std::string FormatDiagnostic(Diagnostic &Diags, Diagnostic::Level Level, - diag::kind ID, - const std::string *Strs, - unsigned NumStrs); -public: - TextDiagnostics() {} - virtual ~TextDiagnostics(); - - void setHeaderSearch(HeaderSearch &HS) { TheHeaderSearch = &HS; } - - virtual bool isInSystemHeader(FullSourceLoc Pos) const; - - virtual void HandleDiagnostic(Diagnostic &Diags, Diagnostic::Level DiagLevel, - FullSourceLoc Pos, - diag::kind ID, - const std::string *Strs, - unsigned NumStrs, - const SourceRange *Ranges, - unsigned NumRanges) = 0; -}; - -} // end namspace clang - -#endif diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 772ce228a4..786af69938 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -469,6 +469,9 @@ private: /// isInPrimaryFile - Return true if we're in the top-level file, not in a /// #include. bool isInPrimaryFile() const; + + /// isSystemHeader - Return true if F is a system header. + bool isSystemHeader(const FileEntry* F) const; /// DiscardUntilEndOfDirective - Read and discard all tokens remaining on the /// current line until the tok::eom token is found. diff --git a/lib/Analysis/PathDiagnostic.cpp b/lib/Analysis/PathDiagnostic.cpp index 28b76b38f1..4c34953b17 100644 --- a/lib/Analysis/PathDiagnostic.cpp +++ b/lib/Analysis/PathDiagnostic.cpp @@ -33,9 +33,6 @@ void PathDiagnosticClient::HandleDiagnostic(Diagnostic &Diags, PathDiagnostic* D = new PathDiagnostic(); - // Ripped from TextDiagnostics::FormatDiagnostic. Perhaps we should - // centralize it somewhere? - std::ostringstream os; switch (DiagLevel) { @@ -46,17 +43,8 @@ void PathDiagnosticClient::HandleDiagnostic(Diagnostic &Diags, case Diagnostic::Fatal: os << "fatal error: "; break; break; } - - std::string Msg = Diags.getDescription(ID); - for (unsigned i = 0; i < Msg.size() - 1; ++i) { - if (Msg[i] == '%' && isdigit(Msg[i + 1])) { - unsigned StrNo = Msg[i + 1] - '0'; - Msg = std::string(Msg.begin(), Msg.begin() + i) + - (StrNo < NumStrs ? Strs[StrNo] : "<<>>") + - std::string(Msg.begin() + i + 2, Msg.end()); - } - } + std::string Msg = FormatDiagnostic(Diags, DiagLevel, ID, Strs, NumStrs); os << Msg; diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 16bdd4a6c2..f9e1d2bda3 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -203,11 +203,10 @@ Diagnostic::Level Diagnostic::getDiagnosticLevel(unsigned DiagID) const { } } -/// Report - Issue the message to the client. If the client wants us to stop -/// compilation, return true, otherwise return false. DiagID is a member of -/// the diag::kind enum. +/// Report - Issue the message to the client. +/// DiagID is a member of the diag::kind enum. void Diagnostic::Report(DiagnosticClient* C, - FullSourceLoc Pos, unsigned DiagID, + FullSourceLoc Loc, unsigned DiagID, const std::string *Strs, unsigned NumStrs, const SourceRange *Ranges, unsigned NumRanges) { @@ -217,33 +216,55 @@ void Diagnostic::Report(DiagnosticClient* C, // If the client doesn't care about this message, don't issue it. if (DiagLevel == Diagnostic::Ignored) return; - + // Set the diagnostic client if it isn't set already. if (!C) C = Client; - // If this is not an error and we are in a system header, ignore it. We have - // to check on the original class here, because we also want to ignore - // extensions and warnings in -Werror and -pedantic-errors modes, which *map* - // warnings/extensions to errors. + // If this is not an error and we are in a system header, ignore it. We + // have to check on the original DiagID here, because we also want to + // ignore extensions and warnings in -Werror and -pedantic-errors modes, + // which *map* warnings/extensions to errors. if (DiagID < diag::NUM_BUILTIN_DIAGNOSTICS && getBuiltinDiagClass(DiagID) != ERROR && - Client->isInSystemHeader(Pos)) + Loc.isValid() && Loc.isFileID() && Loc.isInSystemHeader()) return; if (DiagLevel >= Diagnostic::Error) { ErrorOccurred = true; - - if (C == Client) + + if (C != 0 && C == Client) ++NumErrors; } // Finally, report it. - - C->HandleDiagnostic(*this, DiagLevel, Pos, (diag::kind)DiagID, - Strs, NumStrs, Ranges, NumRanges); - - if (C == Client) + + if (C != 0) + C->HandleDiagnostic(*this, DiagLevel, Loc, (diag::kind)DiagID, + Strs, NumStrs, Ranges, NumRanges); + + if (C != 0 && C == Client) ++NumDiagnostics; } + DiagnosticClient::~DiagnosticClient() {} + +std::string DiagnosticClient::FormatDiagnostic(Diagnostic &Diags, + Diagnostic::Level Level, + diag::kind ID, + const std::string *Strs, + unsigned NumStrs) { + std::string Msg = Diags.getDescription(ID); + + // Replace all instances of %0 in Msg with 'Extra'. + for (unsigned i = 0; i < Msg.size() - 1; ++i) { + if (Msg[i] == '%' && isdigit(Msg[i + 1])) { + unsigned StrNo = Msg[i + 1] - '0'; + Msg = std::string(Msg.begin(), Msg.begin() + i) + + (StrNo < NumStrs ? Strs[StrNo] : "<<>>") + + std::string(Msg.begin() + i + 2, Msg.end()); + } + } + + return Msg; +} diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp index 83c264ad0b..12a49623c6 100644 --- a/lib/Basic/SourceLocation.cpp +++ b/lib/Basic/SourceLocation.cpp @@ -79,6 +79,12 @@ const FileEntry* FullSourceLoc::getFileEntryForLoc() const { return SrcMgr->getFileEntryForLoc(Loc); } +bool FullSourceLoc::isInSystemHeader() const { + assert (isValid()); + return SrcMgr->isInSystemHeader(Loc); +} + + const char * FullSourceLoc::getCharacterData() const { assert (isValid()); return SrcMgr->getCharacterData(Loc); diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index d7d2c84a4c..7534ac4f26 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -75,14 +75,15 @@ SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) { /// include position. This works regardless of whether the ContentCache /// corresponds to a file or some other input source. unsigned SourceManager::createFileID(const ContentCache *File, - SourceLocation IncludePos) { + SourceLocation IncludePos, + bool isSysHeader) { // If FileEnt is really large (e.g. it's a large .i file), we may not be able // to fit an arbitrary position in the file in the FilePos field. To handle // this, we create one FileID for each chunk of the file that fits in a // FilePos field. unsigned FileSize = File->Buffer->getBufferSize(); if (FileSize+1 < (1 << SourceLocation::FilePosBits)) { - FileIDs.push_back(FileIDInfo::get(IncludePos, 0, File)); + FileIDs.push_back(FileIDInfo::get(IncludePos, 0, File, isSysHeader)); assert(FileIDs.size() < (1 << SourceLocation::FileIDBits) && "Ran out of file ID's!"); return FileIDs.size(); @@ -93,7 +94,8 @@ unsigned SourceManager::createFileID(const ContentCache *File, unsigned ChunkNo = 0; while (1) { - FileIDs.push_back(FileIDInfo::get(IncludePos, ChunkNo++, File)); + FileIDs.push_back(FileIDInfo::get(IncludePos, ChunkNo++, File, + isSysHeader)); if (FileSize+1 < (1 << SourceLocation::FilePosBits)) break; FileSize -= (1 << SourceLocation::FilePosBits); diff --git a/lib/Driver/TextDiagnosticPrinter.cpp b/lib/Driver/TextDiagnosticPrinter.cpp index f8f6b3599b..5b99f70205 100644 --- a/lib/Driver/TextDiagnosticPrinter.cpp +++ b/lib/Driver/TextDiagnosticPrinter.cpp @@ -14,7 +14,6 @@ #include "clang/Driver/TextDiagnosticPrinter.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" -#include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Lexer.h" #include "llvm/Support/MemoryBuffer.h" #include diff --git a/lib/Driver/TextDiagnostics.cpp b/lib/Driver/TextDiagnostics.cpp deleted file mode 100644 index ae7b57dc2c..0000000000 --- a/lib/Driver/TextDiagnostics.cpp +++ /dev/null @@ -1,53 +0,0 @@ -//===--- TextDiagnostics.cpp - Text Diagnostics Parent Class --------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is the parent class for all text diagnostics. -// -//===----------------------------------------------------------------------===// - -#include "clang/Driver/TextDiagnostics.h" -#include "clang/Basic/SourceLocation.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Lex/HeaderSearch.h" -using namespace clang; - -TextDiagnostics:: ~TextDiagnostics() {} - -std::string TextDiagnostics::FormatDiagnostic(Diagnostic &Diags, - Diagnostic::Level Level, - diag::kind ID, - const std::string *Strs, - unsigned NumStrs) { - std::string Msg = Diags.getDescription(ID); - - // Replace all instances of %0 in Msg with 'Extra'. - for (unsigned i = 0; i < Msg.size() - 1; ++i) { - if (Msg[i] == '%' && isdigit(Msg[i + 1])) { - unsigned StrNo = Msg[i + 1] - '0'; - Msg = std::string(Msg.begin(), Msg.begin() + i) + - (StrNo < NumStrs ? Strs[StrNo] : "<<>>") + - std::string(Msg.begin() + i + 2, Msg.end()); - } - } - - return Msg; -} - -bool TextDiagnostics::isInSystemHeader(FullSourceLoc Pos) const { - if (!Pos.isValid()) return false; - - if (const FileEntry *F = Pos.getFileEntryForLoc()) { - DirectoryLookup::DirType DirInfo = TheHeaderSearch->getFileDirFlavor(F); - if (DirInfo == DirectoryLookup::SystemHeaderDir || - DirInfo == DirectoryLookup::ExternCSystemHeaderDir) - return true; - } - - return false; -} diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 11afa84f3b..2aa8eaedd4 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -674,7 +674,8 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, } // Look up the file, create a File ID for it. - unsigned FileID = SourceMgr.createFileID(File, FilenameTok.getLocation()); + unsigned FileID = SourceMgr.createFileID(File, FilenameTok.getLocation(), + isSystemHeader(File)); if (FileID == 0) return Diag(FilenameTok, diag::err_pp_file_not_found, std::string(FilenameStart, FilenameEnd)); diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 33c94b6e8a..bc28442784 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -115,6 +115,17 @@ Preprocessor::~Preprocessor() { delete Callbacks; } +bool Preprocessor::isSystemHeader(const FileEntry* F) const { + if (F) { + DirectoryLookup::DirType DirInfo = HeaderInfo.getFileDirFlavor(F); + if (DirInfo == DirectoryLookup::SystemHeaderDir || + DirInfo == DirectoryLookup::ExternCSystemHeaderDir) + return true; + } + return false; +} + + /// Diag - Forwarding function for diagnostics. This emits a diagnostic at /// the specified Token's location, translating the token's start /// position in the current buffer into a SourcePosition object for rendering.