Make changes to SDiagsWriter to make it work in combination with the ARC migrator:

-Allow it to be used with multiple BeginSourceFile/EndSourceFile calls; for this introduce
 a "finish" callback method in the DiagnosticConsumer. SDiagsWriter finishes up the serialization
 file inside this method.
-Make it independent of any particular DiagnosticsEngine; make it use the SourceManager of the
 Diagnostic object.
-Ignore null source ranges.

llvm-svn: 146020
This commit is contained in:
Argyrios Kyrtzidis 2011-12-07 05:52:12 +00:00
parent 2b0b43cf56
commit 7910d7b72a
7 changed files with 109 additions and 33 deletions

View File

@ -1078,6 +1078,10 @@ public:
/// objects made available via \see BeginSourceFile() are inaccessible.
virtual void EndSourceFile() {}
/// \brief Callback to inform the diagnostic client that processing of all
/// source files has ended.
virtual void finish() {}
/// IncludeInDiagnosticCounts - This method (whose default implementation
/// returns true) indicates whether the diagnostics handled by this
/// DiagnosticConsumer should be included in the number of diagnostics

View File

@ -42,6 +42,11 @@ public:
Primary->EndSourceFile();
}
virtual void finish() {
Secondary->finish();
Primary->finish();
}
virtual bool IncludeInDiagnosticCounts() const {
return Primary->IncludeInDiagnosticCounts();
}

View File

@ -52,8 +52,7 @@ enum RecordIDs {
/// This allows wrapper tools for Clang to get diagnostics from Clang
/// (via libclang) without needing to parse Clang's command line output.
///
DiagnosticConsumer *create(llvm::raw_ostream *OS,
DiagnosticsEngine &Diags);
DiagnosticConsumer *create(llvm::raw_ostream *OS);
} // end serialized_diags namespace
} // end clang namespace

View File

@ -170,7 +170,7 @@ static void SetupSerializedDiagnostics(const DiagnosticOptions &DiagOpts,
}
DiagnosticConsumer *SerializedConsumer =
clang::serialized_diags::create(OS.take(), Diags);
clang::serialized_diags::create(OS.take());
Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(),
@ -660,6 +660,9 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
}
}
// Notify the diagnostic client that all files were processed.
getDiagnostics().getClient()->finish();
if (getDiagnosticOpts().ShowCarets) {
// We can have multiple diagnostics sharing one diagnostic client.
// Get the total number of warnings/errors from the client.

View File

@ -47,9 +47,8 @@ typedef llvm::SmallVectorImpl<uint64_t> RecordDataImpl;
class SDiagsWriter : public DiagnosticConsumer {
public:
SDiagsWriter(DiagnosticsEngine &diags, llvm::raw_ostream *os)
: LangOpts(0), Stream(Buffer), OS(os), Diags(diags),
inNonNoteDiagnostic(false)
explicit SDiagsWriter(llvm::raw_ostream *os)
: LangOpts(0), Stream(Buffer), OS(os), inNonNoteDiagnostic(false)
{
EmitPreamble();
}
@ -59,13 +58,13 @@ public:
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info);
void EndSourceFile();
void BeginSourceFile(const LangOptions &LO,
const Preprocessor *PP) {
LangOpts = &LO;
}
virtual void finish();
DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
// It makes no sense to clone this.
return 0;
@ -82,7 +81,7 @@ private:
void EmitMetaBlock();
/// \brief Emit a record for a CharSourceRange.
void EmitCharSourceRange(CharSourceRange R);
void EmitCharSourceRange(CharSourceRange R, SourceManager &SM);
/// \brief Emit the string information for the category for a diagnostic.
unsigned getEmitCategory(unsigned DiagID);
@ -92,14 +91,16 @@ private:
const Diagnostic &Info);
/// \brief Emit (lazily) the file string and retrieved the file identifier.
unsigned getEmitFile(SourceLocation Loc);
unsigned getEmitFile(SourceLocation Loc, SourceManager &SM);
/// \brief Add SourceLocation information the specified record.
void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record,
SourceManager &SM,
unsigned TokSize = 0);
/// \brief Add CharSourceRange information the specified record.
void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record);
void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record,
SourceManager &SM);
/// \brief The version of the diagnostics file.
enum { Version = 1 };
@ -115,9 +116,6 @@ private:
/// \brief The name of the diagnostics file.
llvm::OwningPtr<llvm::raw_ostream> OS;
/// \brief The DiagnosticsEngine tied to all diagnostic locations.
DiagnosticsEngine &Diags;
/// \brief The set of constructed record abbreviations.
AbbreviationMap Abbrevs;
@ -147,8 +145,8 @@ private:
namespace clang {
namespace serialized_diags {
DiagnosticConsumer *create(llvm::raw_ostream *OS, DiagnosticsEngine &Diags) {
return new SDiagsWriter(Diags, OS);
DiagnosticConsumer *create(llvm::raw_ostream *OS) {
return new SDiagsWriter(OS);
}
} // end namespace serialized_diags
} // end namespace clang
@ -192,6 +190,7 @@ static void EmitRecordID(unsigned ID, const char *Name,
void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
RecordDataImpl &Record,
SourceManager &SM,
unsigned TokSize) {
if (Loc.isInvalid()) {
// Emit a "sentinel" location.
@ -202,28 +201,26 @@ void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
return;
}
SourceManager &SM = Diags.getSourceManager();
Loc = SM.getSpellingLoc(Loc);
Record.push_back(getEmitFile(Loc));
Record.push_back(getEmitFile(Loc, SM));
Record.push_back(SM.getSpellingLineNumber(Loc));
Record.push_back(SM.getSpellingColumnNumber(Loc)+TokSize);
Record.push_back(SM.getFileOffset(Loc));
}
void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
RecordDataImpl &Record) {
AddLocToRecord(Range.getBegin(), Record);
RecordDataImpl &Record,
SourceManager &SM) {
AddLocToRecord(Range.getBegin(), Record, SM);
unsigned TokSize = 0;
if (Range.isTokenRange())
TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
Diags.getSourceManager(),
*LangOpts);
SM, *LangOpts);
AddLocToRecord(Range.getEnd(), Record, TokSize);
AddLocToRecord(Range.getEnd(), Record, SM, TokSize);
}
unsigned SDiagsWriter::getEmitFile(SourceLocation Loc) {
SourceManager &SM = Diags.getSourceManager();
unsigned SDiagsWriter::getEmitFile(SourceLocation Loc, SourceManager &SM) {
assert(Loc.isValid());
const std::pair<FileID, unsigned> &LocInfo = SM.getDecomposedLoc(Loc);
const FileEntry *FE = SM.getFileEntryForID(LocInfo.first);
@ -248,10 +245,11 @@ unsigned SDiagsWriter::getEmitFile(SourceLocation Loc) {
return entry;
}
void SDiagsWriter::EmitCharSourceRange(CharSourceRange R) {
void SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
SourceManager &SM) {
Record.clear();
Record.push_back(RECORD_SOURCE_RANGE);
AddCharSourceRangeToRecord(R, Record);
AddCharSourceRangeToRecord(R, Record, SM);
Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_SOURCE_RANGE), Record);
}
@ -426,6 +424,7 @@ unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) {
SourceManager &SM = Info.getSourceManager();
if (DiagLevel != DiagnosticsEngine::Note) {
if (inNonNoteDiagnostic) {
@ -442,7 +441,7 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
Record.clear();
Record.push_back(RECORD_DIAG);
Record.push_back(DiagLevel);
AddLocToRecord(Info.getLocation(), Record);
AddLocToRecord(Info.getLocation(), Record, SM);
// Emit the category string lazily and get the category ID.
Record.push_back(getEmitCategory(Info.getID()));
// Emit the diagnostic flag string lazily and get the mapped ID.
@ -457,7 +456,8 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
ArrayRef<CharSourceRange> Ranges = Info.getRanges();
for (ArrayRef<CharSourceRange>::iterator it=Ranges.begin(), ei=Ranges.end();
it != ei; ++it) {
EmitCharSourceRange(*it);
if (it->isValid())
EmitCharSourceRange(*it, SM);
}
// Emit FixIts.
@ -467,7 +467,7 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
continue;
Record.clear();
Record.push_back(RECORD_FIXIT);
AddCharSourceRangeToRecord(fix.RemoveRange, Record);
AddCharSourceRangeToRecord(fix.RemoveRange, Record, SM);
Record.push_back(fix.CodeToInsert.size());
Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FIXIT), Record,
fix.CodeToInsert);
@ -480,7 +480,7 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
}
}
void SDiagsWriter::EndSourceFile() {
void SDiagsWriter::finish() {
if (inNonNoteDiagnostic) {
// Finish off any diagnostics we were in the process of emitting.
Stream.ExitBlock();

View File

@ -0,0 +1,48 @@
@protocol NSObject
- (id)retain;
- (unsigned)retainCount;
- (oneway void)release;
- (id)autorelease;
@end
@interface NSObject <NSObject> {}
- (id)init;
+ (id)new;
+ (id)alloc;
- (void)dealloc;
- (void)finalize;
- (id)copy;
- (id)mutableCopy;
@end
@interface A : NSObject
@end
struct UnsafeS {
A *__unsafe_unretained unsafeObj;
};
id global_foo;
void test1(A *a, struct UnsafeS *unsafeS) {
[unsafeS->unsafeObj retain];
id foo = [unsafeS->unsafeObj retain]; // no warning.
[global_foo retain];
[a retainCount];
}
// RUN: not %clang_cc1 -arcmt-check -triple x86_64-apple-darwin10 %s -serialize-diagnostic-file %t.diag
// RUN: c-index-test -read-diagnostics %t.diag 2>&1 | FileCheck %s
// CHECK: {{.*}}check-with-serialized-diag.m:32:4: error: [rewriter] it is not safe to remove 'retain' message on an __unsafe_unretained type
// CHECK-NEXT: {{.*}}check-with-serialized-diag.m:34:4: error: [rewriter] it is not safe to remove 'retain' message on a global variable
// CHECK-NEXT: {{.*}}check-with-serialized-diag.m:32:4: error: ARC forbids explicit message send of 'retain'
// CHECK-NEXT: Range: {{.*}}check-with-serialized-diag.m:32:23 {{.*}}check-with-serialized-diag.m:32:29
// CHECK-NEXT: {{.*}}check-with-serialized-diag.m:34:4: error: ARC forbids explicit message send of 'retain'
// CHECK-NEXT: Range: {{.*}}check-with-serialized-diag.m:34:15 {{.*}}check-with-serialized-diag.m:34:21
// CHECK-NEXT: {{.*}}check-with-serialized-diag.m:35:4: error: ARC forbids explicit message send of 'retainCount'
// CHECK-NEXT: Range: {{.*}}check-with-serialized-diag.m:35:6 {{.*}}check-with-serialized-diag.m:35:17

View File

@ -13,4 +13,21 @@ void foo() {
// CHECK: {{.*}}serialized-diags-single-issue.c:3:12: warning: variable 'voodoo' is uninitialized when used here [-Wuninitialized]
// CHECK: Range: {{.*}}serialized-diags-single-issue.c:3:12 {{.*}}serialized-diags-single-issue.c:3:18
// CHECK: +-{{.*}}serialized-diags-single-issue.c:2:13: note: initialize the variable 'voodoo' to silence this warning []
// CHECK: +-FIXIT: {{.*}}serialized-diags-single-issue.c:2:13 - {{.*}}serialized-diags-single-issue.c:2:13): " = 0"
// CHECK: +-FIXIT: {{.*}}serialized-diags-single-issue.c:2:13 - {{.*}}serialized-diags-single-issue.c:2:13): " = 0"
// Test that we handle serializing diagnostics for multiple source files
// RUN: %clang_cc1 -Wall -fsyntax-only %s %s -serialize-diagnostic-file %t
// RUN: c-index-test -read-diagnostics %t 2>&1 | FileCheck -check-prefix=CHECK-MULT %s
// RUN: rm -f %t
// CHECK-MULT: {{.*}}serialized-diags-single-issue.c:3:12: warning: variable 'voodoo' is uninitialized when used here [-Wuninitialized]
// CHECK-MULT: Range: {{.*}}serialized-diags-single-issue.c:3:12 {{.*}}serialized-diags-single-issue.c:3:18
// CHECK-MULT: +-{{.*}}serialized-diags-single-issue.c:2:13: note: initialize the variable 'voodoo' to silence this warning []
// CHECK-MULT: +-FIXIT: {{.*}}serialized-diags-single-issue.c:2:13 - {{.*}}serialized-diags-single-issue.c:2:13): " = 0"
// CHECK-MULT: {{.*}}serialized-diags-single-issue.c:3:12: warning: variable 'voodoo' is uninitialized when used here [-Wuninitialized]
// CHECK-MULT: Range: {{.*}}serialized-diags-single-issue.c:3:12 {{.*}}serialized-diags-single-issue.c:3:18
// CHECK-MULT: +-{{.*}}serialized-diags-single-issue.c:2:13: note: initialize the variable 'voodoo' to silence this warning []
// CHECK-MULT: +-FIXIT: {{.*}}serialized-diags-single-issue.c:2:13 - {{.*}}serialized-diags-single-issue.c:2:13): " = 0"
// CHECK-MULT: Number of diagnostics: 2