* 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

llvm-svn: 54620
This commit is contained in:
Nico Weber 2008-08-10 19:59:06 +00:00
parent cb1e06e8fd
commit 4c3116437c
17 changed files with 111 additions and 165 deletions

View File

@ -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<const TextDiagnosticBuffer&>(PP.getDiagnostics().getClient());
static_cast<const TextDiagnosticBuffer&>(*DiagClient);
SourceManager &SourceMgr = PP.getSourceManager();
// We want to capture the delta between what was expected and what was

View File

@ -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();

View File

@ -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,

View File

@ -247,6 +247,8 @@ public:
const char* getSourceName() const;
const FileEntry* getFileEntryForLoc() const;
bool isInSystemHeader() const;
bool isFileID() const { return Loc.isFileID(); }
unsigned getCanonicalFileID() const;

View File

@ -112,7 +112,10 @@ 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;
@ -120,17 +123,19 @@ namespace SrcMgr {
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
@ -422,6 +430,12 @@ public:
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.
///
void PrintStats() const;
@ -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.

View File

@ -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 <vector>
namespace clang {
@ -22,7 +22,7 @@ namespace clang {
class Preprocessor;
class SourceManager;
class TextDiagnosticBuffer : public TextDiagnostics {
class TextDiagnosticBuffer : public DiagnosticClient {
public:
typedef std::vector<std::pair<SourceLocation, std::string> > 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(); }

View File

@ -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;

View File

@ -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

View File

@ -470,6 +470,9 @@ private:
/// #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.
void DiscardUntilEndOfDirective();

View File

@ -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) {
@ -47,16 +44,7 @@ void PathDiagnosticClient::HandleDiagnostic(Diagnostic &Diags,
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] : "<<<INTERNAL ERROR>>>") +
std::string(Msg.begin() + i + 2, Msg.end());
}
}
std::string Msg = FormatDiagnostic(Diags, DiagLevel, ID, Strs, NumStrs);
os << Msg;

View File

@ -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) {
@ -221,29 +220,51 @@ void Diagnostic::Report(DiagnosticClient* C,
// 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,
if (C != 0)
C->HandleDiagnostic(*this, DiagLevel, Loc, (diag::kind)DiagID,
Strs, NumStrs, Ranges, NumRanges);
if (C == Client)
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] : "<<<INTERNAL ERROR>>>") +
std::string(Msg.begin() + i + 2, Msg.end());
}
}
return Msg;
}

View File

@ -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);

View File

@ -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);

View File

@ -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 <string>

View File

@ -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] : "<<<INTERNAL ERROR>>>") +
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;
}

View File

@ -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));

View File

@ -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.