forked from OSchip/llvm-project
TextDiagnosticPrinter.cpp: Show diagnostics as far as possible even with invalid PresomedLoc, instead of just silencing it.
FileManager.cpp: Allow virtual files in nonexistent directories. FileManager.cpp: Close FileDescriptor for virtual files that correspond to actual files. FileManager.cpp: Enable virtual files to be created even for files that were flagged as NON_EXISTENT_FILE, e.g. by a prior (unsuccessful) addFile(). ASTReader.cpp: Read a PCH even if the original source files cannot be found. Add a test for reading a PCH of a file that has been removed and diagnostics referencing that file. llvm-svn: 124374
This commit is contained in:
parent
284c48fff6
commit
63fbaeda29
|
@ -350,18 +350,17 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
|
|||
FileEntries.GetOrCreateValue(Filename);
|
||||
|
||||
// See if there is already an entry in the map.
|
||||
if (NamedFileEnt.getValue())
|
||||
return NamedFileEnt.getValue() == NON_EXISTENT_FILE
|
||||
? 0 : NamedFileEnt.getValue();
|
||||
if (NamedFileEnt.getValue() && NamedFileEnt.getValue() != NON_EXISTENT_FILE)
|
||||
return NamedFileEnt.getValue();
|
||||
|
||||
++NumFileCacheMisses;
|
||||
|
||||
// By default, initialize it to invalid.
|
||||
NamedFileEnt.setValue(NON_EXISTENT_FILE);
|
||||
|
||||
// We allow the directory to not exist. If it does exist we store it.
|
||||
//
|
||||
const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename);
|
||||
if (DirInfo == 0) // Directory doesn't exist, file can't exist.
|
||||
return 0;
|
||||
|
||||
FileEntry *UFE = new FileEntry();
|
||||
VirtualFileEntries.push_back(UFE);
|
||||
|
@ -381,8 +380,13 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
|
|||
// newly-created file entry.
|
||||
int FileDescriptor = -1;
|
||||
struct stat StatBuf;
|
||||
if (getStatValue(InterndFileName, StatBuf, &FileDescriptor))
|
||||
if (getStatValue(InterndFileName, StatBuf, &FileDescriptor)) {
|
||||
// If the stat process opened the file, close it to avoid a FD leak.
|
||||
if (FileDescriptor != -1)
|
||||
close(FileDescriptor);
|
||||
|
||||
return UFE;
|
||||
}
|
||||
|
||||
UFE->FD = FileDescriptor;
|
||||
llvm::SmallString<128> FilePath(UFE->Name);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Frontend/DiagnosticOptions.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
|
@ -139,8 +140,9 @@ void TextDiagnosticPrinter::HighlightRange(const CharSourceRange &R,
|
|||
(SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
|
||||
--EndColNo;
|
||||
|
||||
// If the start/end passed each other, then we are trying to highlight a range
|
||||
// that just exists in whitespace, which must be some sort of other bug.
|
||||
// If the start/end passed each other, then we are trying to highlight a
|
||||
// range that just exists in whitespace, which must be some sort of other
|
||||
// bug.
|
||||
assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
|
||||
}
|
||||
|
||||
|
@ -781,78 +783,94 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
|
|||
if (Info.getLocation().isValid()) {
|
||||
const SourceManager &SM = Info.getSourceManager();
|
||||
PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());
|
||||
if (PLoc.isInvalid())
|
||||
return;
|
||||
|
||||
unsigned LineNo = PLoc.getLine();
|
||||
|
||||
// First, if this diagnostic is not in the main file, print out the
|
||||
// "included from" lines.
|
||||
if (LastWarningLoc != PLoc.getIncludeLoc()) {
|
||||
LastWarningLoc = PLoc.getIncludeLoc();
|
||||
PrintIncludeStack(LastWarningLoc, SM);
|
||||
StartOfLocationInfo = OS.tell();
|
||||
}
|
||||
|
||||
// Compute the column number.
|
||||
if (DiagOpts->ShowLocation && PLoc.isValid()) {
|
||||
if (DiagOpts->ShowColors)
|
||||
OS.changeColor(savedColor, true);
|
||||
|
||||
// Emit a Visual Studio compatible line number syntax.
|
||||
if (LangOpts && LangOpts->Microsoft) {
|
||||
OS << PLoc.getFilename() << '(' << LineNo << ')';
|
||||
OS << " : ";
|
||||
} else {
|
||||
OS << PLoc.getFilename() << ':' << LineNo << ':';
|
||||
if (DiagOpts->ShowColumn)
|
||||
if (unsigned ColNo = PLoc.getColumn())
|
||||
OS << ColNo << ':';
|
||||
}
|
||||
if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) {
|
||||
FileID CaretFileID =
|
||||
SM.getFileID(SM.getInstantiationLoc(Info.getLocation()));
|
||||
bool PrintedRange = false;
|
||||
|
||||
for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) {
|
||||
// Ignore invalid ranges.
|
||||
if (!Info.getRange(i).isValid()) continue;
|
||||
|
||||
SourceLocation B = Info.getRange(i).getBegin();
|
||||
SourceLocation E = Info.getRange(i).getEnd();
|
||||
B = SM.getInstantiationLoc(B);
|
||||
E = SM.getInstantiationLoc(E);
|
||||
|
||||
// If the End location and the start location are the same and are a
|
||||
// macro location, then the range was something that came from a macro
|
||||
// expansion or _Pragma. If this is an object-like macro, the best we
|
||||
// can do is to highlight the range. If this is a function-like
|
||||
// macro, we'd also like to highlight the arguments.
|
||||
if (B == E && Info.getRange(i).getEnd().isMacroID())
|
||||
E = SM.getInstantiationRange(Info.getRange(i).getEnd()).second;
|
||||
|
||||
std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
|
||||
std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
|
||||
|
||||
// If the start or end of the range is in another file, just discard
|
||||
// it.
|
||||
if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
|
||||
continue;
|
||||
|
||||
// Add in the length of the token, so that we cover multi-char tokens.
|
||||
unsigned TokSize = 0;
|
||||
if (Info.getRange(i).isTokenRange())
|
||||
TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts);
|
||||
|
||||
OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
|
||||
<< SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
|
||||
<< SM.getLineNumber(EInfo.first, EInfo.second) << ':'
|
||||
<< (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) << '}';
|
||||
PrintedRange = true;
|
||||
if (PLoc.isInvalid()) {
|
||||
// At least print the file name if available:
|
||||
FileID FID = SM.getFileID(Info.getLocation());
|
||||
if (!FID.isInvalid()) {
|
||||
const FileEntry* FE = SM.getFileEntryForID(FID);
|
||||
if (FE && FE->getName()) {
|
||||
OS << FE->getName();
|
||||
if (FE->getDevice() == 0 && FE->getInode() == 0
|
||||
&& FE->getFileMode() == 0) {
|
||||
// in PCH is a guess, but a good one:
|
||||
OS << " (in PCH)";
|
||||
}
|
||||
OS << ": ";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unsigned LineNo = PLoc.getLine();
|
||||
|
||||
if (PrintedRange)
|
||||
OS << ':';
|
||||
// First, if this diagnostic is not in the main file, print out the
|
||||
// "included from" lines.
|
||||
if (LastWarningLoc != PLoc.getIncludeLoc()) {
|
||||
LastWarningLoc = PLoc.getIncludeLoc();
|
||||
PrintIncludeStack(LastWarningLoc, SM);
|
||||
StartOfLocationInfo = OS.tell();
|
||||
}
|
||||
|
||||
// Compute the column number.
|
||||
if (DiagOpts->ShowLocation && PLoc.isValid()) {
|
||||
if (DiagOpts->ShowColors)
|
||||
OS.changeColor(savedColor, true);
|
||||
|
||||
// Emit a Visual Studio compatible line number syntax.
|
||||
if (LangOpts && LangOpts->Microsoft) {
|
||||
OS << PLoc.getFilename() << '(' << LineNo << ')';
|
||||
OS << " : ";
|
||||
} else {
|
||||
OS << PLoc.getFilename() << ':' << LineNo << ':';
|
||||
if (DiagOpts->ShowColumn)
|
||||
if (unsigned ColNo = PLoc.getColumn())
|
||||
OS << ColNo << ':';
|
||||
}
|
||||
if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) {
|
||||
FileID CaretFileID =
|
||||
SM.getFileID(SM.getInstantiationLoc(Info.getLocation()));
|
||||
bool PrintedRange = false;
|
||||
|
||||
for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) {
|
||||
// Ignore invalid ranges.
|
||||
if (!Info.getRange(i).isValid()) continue;
|
||||
|
||||
SourceLocation B = Info.getRange(i).getBegin();
|
||||
SourceLocation E = Info.getRange(i).getEnd();
|
||||
B = SM.getInstantiationLoc(B);
|
||||
E = SM.getInstantiationLoc(E);
|
||||
|
||||
// If the End location and the start location are the same and are a
|
||||
// macro location, then the range was something that came from a
|
||||
// macro expansion or _Pragma. If this is an object-like macro, the
|
||||
// best we can do is to highlight the range. If this is a
|
||||
// function-like macro, we'd also like to highlight the arguments.
|
||||
if (B == E && Info.getRange(i).getEnd().isMacroID())
|
||||
E = SM.getInstantiationRange(Info.getRange(i).getEnd()).second;
|
||||
|
||||
std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
|
||||
std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
|
||||
|
||||
// If the start or end of the range is in another file, just discard
|
||||
// it.
|
||||
if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
|
||||
continue;
|
||||
|
||||
// Add in the length of the token, so that we cover multi-char
|
||||
// tokens.
|
||||
unsigned TokSize = 0;
|
||||
if (Info.getRange(i).isTokenRange())
|
||||
TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts);
|
||||
|
||||
OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
|
||||
<< SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
|
||||
<< SM.getLineNumber(EInfo.first, EInfo.second) << ':'
|
||||
<< (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize)
|
||||
<< '}';
|
||||
PrintedRange = true;
|
||||
}
|
||||
|
||||
if (PrintedRange)
|
||||
OS << ':';
|
||||
}
|
||||
}
|
||||
OS << ' ';
|
||||
if (DiagOpts->ShowColors)
|
||||
|
|
|
@ -1232,6 +1232,9 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(unsigned ID) {
|
|||
std::string Filename(BlobStart, BlobStart + BlobLen);
|
||||
MaybeAddSystemRootToFilename(Filename);
|
||||
const FileEntry *File = FileMgr.getFile(Filename);
|
||||
if (File == 0)
|
||||
File = FileMgr.getVirtualFile(Filename, (off_t)Record[4],
|
||||
(time_t)Record[5]);
|
||||
if (File == 0) {
|
||||
std::string ErrorStr = "could not find file '";
|
||||
ErrorStr += Filename;
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
// Test reading of PCH without original input files.
|
||||
|
||||
// Generate the PCH, removing the original file:
|
||||
// RUN: echo 'struct S{char c; int i; }; void foo() {}' > %t.h
|
||||
// RUN: echo 'template <typename T> void tf() { T::foo(); }' >> %t.h
|
||||
// RUN: echo '#define RETURN return &i' >> %t.h
|
||||
// RUN: %clang_cc1 -x c++ -emit-pch -o %t.h.pch %t.h
|
||||
// RUN: rm %t.h
|
||||
|
||||
// Check diagnostic with location in original source:
|
||||
// RUN: %clang_cc1 -include-pch %t.h.pch -Wpadded -emit-obj %s 2> %t.stderr
|
||||
// RUN: grep 'bytes to align' %t.stderr
|
||||
|
||||
// Check diagnostic with 2nd location in original source:
|
||||
// RUN: not %clang_cc1 -DREDECL -include-pch %t.h.pch -emit-obj %s 2> %t.stderr
|
||||
// RUN: grep 'previous definition is here' %t.stderr
|
||||
|
||||
// Check diagnostic with instantiation location in original source:
|
||||
// RUN: not %clang_cc1 -DINSTANTIATION -include-pch %t.h.pch -emit-obj %s 2> %t.stderr
|
||||
// RUN: grep 'cannot be used prior to' %t.stderr
|
||||
|
||||
void qq(S*) {}
|
||||
|
||||
#ifdef REDECL
|
||||
float foo() {return 0f;}
|
||||
#endif
|
||||
|
||||
#ifdef INSTANTIATION
|
||||
void f() {
|
||||
tf<int>();
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue