//===--- tools/extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp ----------=== // // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file This file implements ClangTidyDiagnosticConsumer, ClangTidyMessage, /// ClangTidyContext and ClangTidyError classes. /// /// This tool uses the Clang Tooling infrastructure, see /// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html /// for details on setting it up with LLVM source tree. /// //===----------------------------------------------------------------------===// #include "ClangTidyDiagnosticConsumer.h" #include "llvm/ADT/SmallString.h" namespace clang { namespace tidy { ClangTidyMessage::ClangTidyMessage(StringRef Message) : Message(Message) {} ClangTidyMessage::ClangTidyMessage(StringRef Message, const SourceManager &Sources, SourceLocation Loc) : Message(Message) { FilePath = Sources.getFilename(Loc); FileOffset = Sources.getFileOffset(Loc); } ClangTidyError::ClangTidyError(StringRef CheckName, const ClangTidyMessage &Message) : CheckName(CheckName), Message(Message) {} DiagnosticBuilder ClangTidyContext::diag( StringRef CheckName, SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level /* = DiagnosticsEngine::Warning*/) { unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID( Level, (Description + " [" + CheckName + "]").str()); if (CheckNamesByDiagnosticID.count(ID) == 0) CheckNamesByDiagnosticID.insert(std::make_pair(ID, CheckName.str())); return DiagEngine->Report(Loc, ID); } void ClangTidyContext::setDiagnosticsEngine(DiagnosticsEngine *Engine) { DiagEngine = Engine; } void ClangTidyContext::setSourceManager(SourceManager *SourceMgr) { DiagEngine->setSourceManager(SourceMgr); } /// \brief Store a \c ClangTidyError. void ClangTidyContext::storeError(const ClangTidyError &Error) { Errors->push_back(Error); } StringRef ClangTidyContext::getCheckName(unsigned DiagnosticID) const { llvm::DenseMap::const_iterator I = CheckNamesByDiagnosticID.find(DiagnosticID); if (I != CheckNamesByDiagnosticID.end()) return I->second; return ""; } ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx) : Context(Ctx), LastErrorRelatesToUserCode(false) { IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); Diags.reset(new DiagnosticsEngine( IntrusiveRefCntPtr(new DiagnosticIDs), &*DiagOpts, this, /*ShouldOwnClient=*/false)); Context.setDiagnosticsEngine(Diags.get()); } void ClangTidyDiagnosticConsumer::finalizeLastError() { if (!LastErrorRelatesToUserCode && !Errors.empty()) Errors.pop_back(); LastErrorRelatesToUserCode = false; } void ClangTidyDiagnosticConsumer::HandleDiagnostic( DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { // FIXME: Deduplicate diagnostics. if (DiagLevel == DiagnosticsEngine::Note) { assert(!Errors.empty() && "A diagnostic note can only be appended to a message."); Errors.back().Notes.push_back(getMessage(Info)); } else { finalizeLastError(); Errors.push_back( ClangTidyError(Context.getCheckName(Info.getID()), getMessage(Info))); } addFixes(Info, Errors.back()); // Let argument parsing-related warnings through. if (!Diags->hasSourceManager() || !Diags->getSourceManager().isInSystemHeader(Info.getLocation())) { LastErrorRelatesToUserCode = true; } } // Flushes the internal diagnostics buffer to the ClangTidyContext. void ClangTidyDiagnosticConsumer::finish() { finalizeLastError(); for (unsigned i = 0, e = Errors.size(); i != e; ++i) Context.storeError(Errors[i]); Errors.clear(); } void ClangTidyDiagnosticConsumer::addFixes(const Diagnostic &Info, ClangTidyError &Error) { if (!Info.hasSourceManager()) return; SourceManager &SourceMgr = Info.getSourceManager(); tooling::Replacements Replacements; for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i) { Error.Fix.insert(tooling::Replacement( SourceMgr, Info.getFixItHint(i).RemoveRange.getBegin(), 0, Info.getFixItHint(i).CodeToInsert)); } } ClangTidyMessage ClangTidyDiagnosticConsumer::getMessage(const Diagnostic &Info) const { SmallString<100> Buf; Info.FormatDiagnostic(Buf); if (!Info.hasSourceManager()) { return ClangTidyMessage(Buf.str()); } return ClangTidyMessage(Buf.str(), Info.getSourceManager(), Info.getLocation()); } } // namespace tidy } // namespace clang