Index: llvm/tools/clang/include/clang/Tooling/Core/Diagnostic.h =================================================================== --- llvm/tools/clang/include/clang/Tooling/Core/Diagnostic.h +++ llvm/tools/clang/include/clang/Tooling/Core/Diagnostic.h @@ -0,0 +1,78 @@ +//===--- Diagnostic.h - Framework for clang diagnostics tools --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// \file +// Structures supporting diagnostics and refactorings that span multiple +// translation units. Indicate diagnostics reports and replacements +// suggestions for the analyzed sources. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_CORE_DIAGNOSTIC_H +#define LLVM_CLANG_TOOLING_CORE_DIAGNOSTIC_H + +#include "Replacement.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include + +namespace clang { +namespace tooling { + +/// \brief Represents the diagnostic message with the error message associated +/// and theinformation on the location of the problem. +struct DiagnosticMessage { + DiagnosticMessage(llvm::StringRef Message = ""); + DiagnosticMessage(llvm::StringRef Message, const SourceManager &Sources, + SourceLocation Loc); + std::string Message; + std::string FilePath; + unsigned FileOffset; +}; + +/// \brief Represents the diagnostic with the level of severity and possible +/// fixes to be applied. +struct Diagnostic { + enum Level { + Warning = DiagnosticsEngine::Warning, + Error = DiagnosticsEngine::Error + }; + + Diagnostic() = default; + + Diagnostic(llvm::StringRef CheckName, Level DiagLevel); + + Diagnostic(llvm::StringRef CheckName, DiagnosticMessage &Message, + llvm::StringMap &Fix, + SmallVector &Notes, Level DiagLevel); + + std::string CheckName; + DiagnosticMessage Message; + // Fixes grouped by file path. + llvm::StringMap Fix; + SmallVector Notes; + Level DiagLevel; +}; + +/// \brief Collection of Diagnostics generated from a single translation unit. +struct TranslationUnitDiagnostics { + std::string MainSourceFile; + /// A freeform chunk of text to describe the context of the replacements. + /// Will be printed, for example, when detecting conflicts during replacement + /// deduplication. + std::string Context; + + std::vector Diagnostics; +}; + +} // end namespace tooling +} // end namespace clang +#endif // LLVM_CLANG_TOOLING_CORE_DIAGNOSTIC_H Index: llvm/tools/clang/include/clang/Tooling/DiagnosticsYaml.h =================================================================== --- llvm/tools/clang/include/clang/Tooling/DiagnosticsYaml.h +++ llvm/tools/clang/include/clang/Tooling/DiagnosticsYaml.h @@ -0,0 +1,81 @@ +//===-- DiagnosticsYaml.h -- Serialiazation for Diagnosticss ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file defines the structure of a YAML document for serializing +/// diagnostics. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_DIAGNOSTICSYAML_H +#define LLVM_CLANG_TOOLING_DIAGNOSTICSYAML_H + +#include "clang/Tooling/Core/Diagnostic.h" +#include "clang/Tooling/ReplacementsYaml.h" +#include "llvm/Support/YAMLTraits.h" +#include + +LLVM_YAML_IS_SEQUENCE_VECTOR(clang::tooling::Diagnostic) + +namespace llvm { +namespace yaml { + +/// \brief Specialized MappingTraits to describe how a Diagnostic is +/// (de)serialized. +template <> struct MappingTraits { + /// \brief Helper to (de)serialize a Diagnostic since we don't have direct + /// access to its data members. + class NormalizedDiagnostic { + public: + NormalizedDiagnostic(const IO &) + : CheckName(""), Message(), Fix(), Notes(), DiagLevel() {} + + NormalizedDiagnostic(const IO &, const clang::tooling::Diagnostic &D) + : CheckName(D.CheckName), Message(Message), Fix(D.Fix), Notes(D.Notes), + DiagLevel(D.DiagLevel) {} + + clang::tooling::Diagnostic denormalize(const IO &) { + return clang::tooling::Diagnostic(CheckName, Message, Fix, Notes, + DiagLevel); + } + + std::string CheckName; + clang::tooling::DiagnosticMessage Message; + llvm::StringMap Fix; + SmallVector Notes; + clang::tooling::Diagnostic::Level DiagLevel; + }; + + static void mapping(IO &Io, clang::tooling::Diagnostic &D) { + MappingNormalization Keys( + Io, D); + Io.mapRequired("CheckName", Keys->CheckName); + for (auto &Fixes : Keys->Fix) { + if (Fixes.second.size() > 0) { + std::vector Fix(Fixes.second.begin(), + Fixes.second.end()); + Io.mapRequired("Replacements", Fix); + } + } + } +}; + +/// \brief Specialized MappingTraits to describe how a +/// TranslationUnitDiagnostics is (de)serialized. +template <> struct MappingTraits { + static void mapping(IO &Io, clang::tooling::TranslationUnitDiagnostics &Doc) { + Io.mapRequired("MainSourceFile", Doc.MainSourceFile); + Io.mapOptional("Context", Doc.Context, std::string()); + Io.mapRequired("Diagnostics", Doc.Diagnostics); + } +}; +} // end namespace yaml +} // end namespace llvm + +#endif // LLVM_CLANG_TOOLING_DIAGNOSTICSYAML_H Index: llvm/tools/clang/lib/Tooling/Core/CMakeLists.txt =================================================================== --- llvm/tools/clang/lib/Tooling/Core/CMakeLists.txt +++ llvm/tools/clang/lib/Tooling/Core/CMakeLists.txt @@ -4,7 +4,8 @@ Lookup.cpp Replacement.cpp QualTypeNames.cpp + Diagnostic.cpp LINK_LIBS clangAST clangBasic Index: llvm/tools/clang/lib/Tooling/Core/Diagnostic.cpp =================================================================== --- llvm/tools/clang/lib/Tooling/Core/Diagnostic.cpp +++ llvm/tools/clang/lib/Tooling/Core/Diagnostic.cpp @@ -0,0 +1,43 @@ +//===--- Diagnostic.cpp - Framework for clang diagnostics tools ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implements classes to support/store diagnostics refactoring. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Core/Diagnostic.h" +#include "clang/Basic/SourceManager.h" + +namespace clang { +namespace tooling { + +DiagnosticMessage::DiagnosticMessage(llvm::StringRef Message) + : Message(Message), FileOffset(0) {} + +DiagnosticMessage::DiagnosticMessage(llvm::StringRef Message, + const SourceManager &Sources, + SourceLocation Loc) + : Message(Message) { + assert(Loc.isValid() && Loc.isFileID()); + FilePath = Sources.getFilename(Loc); + FileOffset = Sources.getFileOffset(Loc); +} + +Diagnostic::Diagnostic(llvm::StringRef CheckName, Diagnostic::Level DiagLevel) + : CheckName(CheckName), DiagLevel(DiagLevel) {} + +Diagnostic::Diagnostic(llvm::StringRef CheckName, DiagnosticMessage &Message, + llvm::StringMap &Fix, + SmallVector &Notes, + Level DiagLevel) + : CheckName(CheckName), Message(Message), Fix(Fix), Notes(Notes), + DiagLevel(DiagLevel) {} + +} // end namespace tooling +} // end namespace clang Index: llvm/tools/clang/tools/extra/clang-apply-replacements/include/clang-apply-replacements/Tooling/ApplyReplacements.h =================================================================== --- llvm/tools/clang/tools/extra/clang-apply-replacements/include/clang-apply-replacements/Tooling/ApplyReplacements.h +++ llvm/tools/clang/tools/extra/clang-apply-replacements/include/clang-apply-replacements/Tooling/ApplyReplacements.h @@ -16,6 +16,7 @@ #ifndef LLVM_CLANG_APPLYREPLACEMENTS_H #define LLVM_CLANG_APPLYREPLACEMENTS_H +#include "clang/Tooling/Core/Diagnostic.h" #include "clang/Tooling/Refactoring.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" @@ -38,8 +39,8 @@ typedef std::vector RangeVector; /// \brief Collection of TranslationUnitReplacements. -typedef std::vector -TUReplacements; +typedef std::vector +TUDiagnostics; /// \brief Collection of TranslationUnitReplacement files. typedef std::vector TUReplacementFiles; @@ -68,7 +69,7 @@ /// directory structure. std::error_code collectReplacementsFromDirectory(const llvm::StringRef Directory, - TUReplacements &TUs, + TUDiagnostics &TUs, TUReplacementFiles &TURFiles, clang::DiagnosticsEngine &Diagnostics); @@ -87,7 +88,7 @@ /// \returns \parblock /// \li true If all changes were applied successfully. /// \li false If there were conflicts. -bool mergeAndDeduplicate(const TUReplacements &TUs, +bool mergeAndDeduplicate(const TUDiagnostics &TUs, FileToReplacementsMap &GroupedReplacements, clang::SourceManager &SM); Index: llvm/tools/clang/tools/extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp =================================================================== --- llvm/tools/clang/tools/extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp +++ llvm/tools/clang/tools/extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp @@ -20,6 +20,7 @@ #include "clang/Format/Format.h" #include "clang/Lex/Lexer.h" #include "clang/Rewrite/Core/Rewriter.h" +#include "clang/Tooling/DiagnosticsYaml.h" #include "clang/Tooling/ReplacementsYaml.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/FileSystem.h" @@ -38,7 +39,7 @@ std::error_code collectReplacementsFromDirectory(const llvm::StringRef Directory, - TUReplacements &TUs, + TUDiagnostics &TUs, TUReplacementFiles & TURFiles, clang::DiagnosticsEngine &Diagnostics) { using namespace llvm::sys::fs; @@ -68,7 +69,7 @@ } yaml::Input YIn(Out.get()->getBuffer(), nullptr, &eatDiagnostics); - tooling::TranslationUnitReplacements TU; + tooling::TranslationUnitDiagnostics TU; YIn >> TU; if (YIn.error()) { // File doesn't appear to be a header change description. Ignore it. @@ -238,23 +239,27 @@ return conflictsFound; } -bool mergeAndDeduplicate(const TUReplacements &TUs, +bool mergeAndDeduplicate(const TUDiagnostics &TUs, FileToReplacementsMap &GroupedReplacements, clang::SourceManager &SM) { // Group all replacements by target file. std::set Warned; for (const auto &TU : TUs) { - for (const tooling::Replacement &R : TU.Replacements) { - // Use the file manager to deduplicate paths. FileEntries are - // automatically canonicalized. - const FileEntry *Entry = SM.getFileManager().getFile(R.getFilePath()); - if (!Entry && Warned.insert(R.getFilePath()).second) { - errs() << "Described file '" << R.getFilePath() - << "' doesn't exist. Ignoring...\n"; - continue; + for (const auto &D : TU.Diagnostics) { + for (const auto &Fix : D.Fix) { + for (const tooling::Replacement &R : Fix.second) { + // Use the file manager to deduplicate paths. FileEntries are + // automatically canonicalized. + const FileEntry *Entry = SM.getFileManager().getFile(R.getFilePath()); + if (!Entry && Warned.insert(R.getFilePath()).second) { + errs() << "Described file '" << R.getFilePath() + << "' doesn't exist. Ignoring...\n"; + continue; + } + GroupedReplacements[Entry].push_back(R); + } } - GroupedReplacements[Entry].push_back(R); } } Index: llvm/tools/clang/tools/extra/clang-tidy/ClangTidy.cpp =================================================================== --- llvm/tools/clang/tools/extra/clang-tidy/ClangTidy.cpp +++ llvm/tools/clang/tools/extra/clang-tidy/ClangTidy.cpp @@ -35,6 +35,7 @@ #include "clang/Rewrite/Frontend/FrontendActions.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" +#include "clang/Tooling/DiagnosticsYaml.h" #include "clang/Tooling/Refactoring.h" #include "clang/Tooling/ReplacementsYaml.h" #include "clang/Tooling/Tooling.h" @@ -574,16 +575,10 @@ void exportReplacements(const std::vector &Errors, raw_ostream &OS) { - TranslationUnitReplacements TUR; - for (const ClangTidyError &Error : Errors) { - for (const auto &FileAndFixes : Error.Fix) - TUR.Replacements.insert(TUR.Replacements.end(), - FileAndFixes.second.begin(), - FileAndFixes.second.end()); - } - + TranslationUnitDiagnostics TUD; + TUD.Diagnostics.insert(TUD.Diagnostics.end(), Errors.begin(), Errors.end()); yaml::Output YAML(OS); - YAML << TUR; + YAML << TUD; } } // namespace tidy Index: llvm/tools/clang/tools/extra/clang-tidy/ClangTidyDiagnosticConsumer.h =================================================================== --- llvm/tools/clang/tools/extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ llvm/tools/clang/tools/extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -13,6 +13,7 @@ #include "ClangTidyOptions.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" +#include "clang/Tooling/Core/Diagnostic.h" #include "clang/Tooling/Refactoring.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" @@ -32,17 +33,7 @@ namespace tidy { -/// \brief A message from a clang-tidy check. -/// -/// Note that this is independent of a \c SourceManager. -struct ClangTidyMessage { - ClangTidyMessage(StringRef Message = ""); - ClangTidyMessage(StringRef Message, const SourceManager &Sources, - SourceLocation Loc); - std::string Message; - std::string FilePath; - unsigned FileOffset; -}; +typedef clang::tooling::DiagnosticMessage ClangTidyMessage; /// \brief A detected error complete with information to display diagnostic and /// automatic fix. @@ -51,21 +42,10 @@ /// dependency on a SourceManager. /// /// FIXME: Make Diagnostics flexible enough to support this directly. -struct ClangTidyError { - enum Level { - Warning = DiagnosticsEngine::Warning, - Error = DiagnosticsEngine::Error - }; - +struct ClangTidyError : clang::tooling::Diagnostic { ClangTidyError(StringRef CheckName, Level DiagLevel, bool IsWarningAsError, StringRef BuildDirectory); - std::string CheckName; - ClangTidyMessage Message; - // Fixes grouped by file path. - llvm::StringMap Fix; - SmallVector Notes; - // A build directory of the diagnostic source file. // // It's an absolute path which is `directory` field of the source file in @@ -75,7 +55,6 @@ // Note: it is empty in unittest. std::string BuildDirectory; - Level DiagLevel; bool IsWarningAsError; }; Index: llvm/tools/clang/tools/extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp =================================================================== --- llvm/tools/clang/tools/extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ llvm/tools/clang/tools/extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -110,24 +110,11 @@ }; } // end anonymous namespace -ClangTidyMessage::ClangTidyMessage(StringRef Message) - : Message(Message), FileOffset(0) {} - -ClangTidyMessage::ClangTidyMessage(StringRef Message, - const SourceManager &Sources, - SourceLocation Loc) - : Message(Message) { - assert(Loc.isValid() && Loc.isFileID()); - FilePath = Sources.getFilename(Loc); - FileOffset = Sources.getFileOffset(Loc); -} - ClangTidyError::ClangTidyError(StringRef CheckName, ClangTidyError::Level DiagLevel, - bool IsWarningAsError, - StringRef BuildDirectory) - : CheckName(CheckName), BuildDirectory(BuildDirectory), DiagLevel(DiagLevel), - IsWarningAsError(IsWarningAsError) {} + bool IsWarningAsError, StringRef BuildDirectory) + : clang::tooling::Diagnostic(CheckName, DiagLevel), + BuildDirectory(BuildDirectory), IsWarningAsError(IsWarningAsError) {} // Returns true if GlobList starts with the negative indicator ('-'), removes it // from the GlobList.