From: Alexander Kornienko Date: Tue, 3 Jan 2017 14:35:47 +0000 (+0000) Subject: [clang-tidy] Add check name to YAML export X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fb9bfeea738853fc73d0f74fec0f30909beaeb73;p=clang [clang-tidy] Add check name to YAML export Add a field indicating the associated check for every replacement to the YAML report generated with the '-export-fixes' option. Update clang-apply-replacements to handle the new format. Patch by Alpha Abdoulaye! Differential revision: https://reviews.llvm.org/D26137 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@290892 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Tooling/Core/Diagnostic.h b/include/clang/Tooling/Core/Diagnostic.h new file mode 100644 index 0000000000..d657f16df1 --- /dev/null +++ b/include/clang/Tooling/Core/Diagnostic.h @@ -0,0 +1,100 @@ +//===--- 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 the information on the location of the problem. +struct DiagnosticMessage { + DiagnosticMessage(llvm::StringRef Message = ""); + + /// \brief Constructs a diagnostic message with anoffset to the diagnostic + /// within the file where the problem occured. + /// + /// \param Loc Should be a file location, it is not meaningful for a macro + /// location. + /// + 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 DiagnosticName, Level DiagLevel, + StringRef BuildDirectory); + + Diagnostic(llvm::StringRef DiagnosticName, DiagnosticMessage &Message, + llvm::StringMap &Fix, + SmallVector &Notes, Level DiagLevel, + llvm::StringRef BuildDirectory); + + /// \brief Name identifying the Diagnostic. + std::string DiagnosticName; + + /// \brief Message associated to the diagnostic. + DiagnosticMessage Message; + + /// \brief Fixes to apply, grouped by file path. + llvm::StringMap Fix; + + /// \brief Potential notes about the diagnostic. + SmallVector Notes; + + /// \brief Diagnostic level. Can indicate either an error or a warning. + Level DiagLevel; + + /// \brief A build directory of the diagnostic source file. + /// + /// It's an absolute path which is `directory` field of the source file in + /// compilation database. If users don't specify the compilation database + /// directory, it is the current directory where clang-tidy runs. + /// + /// Note: it is empty in unittest. + std::string BuildDirectory; +}; + +/// \brief Collection of Diagnostics generated from a single translation unit. +struct TranslationUnitDiagnostics { + /// Name of the main source for the translation unit. + std::string MainSourceFile; + std::vector Diagnostics; +}; + +} // end namespace tooling +} // end namespace clang +#endif // LLVM_CLANG_TOOLING_CORE_DIAGNOSTIC_H diff --git a/include/clang/Tooling/Core/Replacement.h b/include/clang/Tooling/Core/Replacement.h index 95dc3cd6e7..8d4a22adf3 100644 --- a/include/clang/Tooling/Core/Replacement.h +++ b/include/clang/Tooling/Core/Replacement.h @@ -329,12 +329,6 @@ llvm::Expected applyAllReplacements(StringRef Code, struct TranslationUnitReplacements { /// Name of the main source for the translation unit. 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 Replacements; }; diff --git a/include/clang/Tooling/DiagnosticsYaml.h b/include/clang/Tooling/DiagnosticsYaml.h new file mode 100644 index 0000000000..f32b9fa9c9 --- /dev/null +++ b/include/clang/Tooling/DiagnosticsYaml.h @@ -0,0 +1,101 @@ +//===-- 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 { + +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 &) + : DiagLevel(clang::tooling::Diagnostic::Level::Warning) {} + + NormalizedDiagnostic(const IO &, const clang::tooling::Diagnostic &D) + : DiagnosticName(D.DiagnosticName), Message(D.Message), Fix(D.Fix), + Notes(D.Notes), DiagLevel(D.DiagLevel), + BuildDirectory(D.BuildDirectory) {} + + clang::tooling::Diagnostic denormalize(const IO &) { + return clang::tooling::Diagnostic(DiagnosticName, Message, Fix, Notes, + DiagLevel, BuildDirectory); + } + + std::string DiagnosticName; + clang::tooling::DiagnosticMessage Message; + llvm::StringMap Fix; + SmallVector Notes; + clang::tooling::Diagnostic::Level DiagLevel; + std::string BuildDirectory; + }; + + static void mapping(IO &Io, clang::tooling::Diagnostic &D) { + MappingNormalization Keys( + Io, D); + Io.mapRequired("DiagnosticName", Keys->DiagnosticName); + + // FIXME: Export properly all the different fields. + + std::vector Fixes; + for (auto &Replacements : Keys->Fix) { + for (auto &Replacement : Replacements.second) { + Fixes.push_back(Replacement); + } + } + Io.mapRequired("Replacements", Fixes); + for (auto &Fix : Fixes) { + llvm::Error Err = Keys->Fix[Fix.getFilePath()].add(Fix); + if (Err) { + // FIXME: Implement better conflict handling. + llvm::errs() << "Fix conflicts with existing fix: " + << llvm::toString(std::move(Err)) << "\n"; + } + } + } +}; + +/// \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); + + std::vector Diagnostics; + for (auto &Diagnostic : Doc.Diagnostics) { + // FIXME: Export all diagnostics, not just the ones with fixes. + // Update MappingTraits::mapping. + if (Diagnostic.Fix.size() > 0) { + Diagnostics.push_back(Diagnostic); + } + } + Io.mapRequired("Diagnostics", Diagnostics); + Doc.Diagnostics = Diagnostics; + } +}; +} // end namespace yaml +} // end namespace llvm + +#endif // LLVM_CLANG_TOOLING_DIAGNOSTICSYAML_H diff --git a/include/clang/Tooling/ReplacementsYaml.h b/include/clang/Tooling/ReplacementsYaml.h index 47b7f3f9a5..0b1dc4c774 100644 --- a/include/clang/Tooling/ReplacementsYaml.h +++ b/include/clang/Tooling/ReplacementsYaml.h @@ -65,7 +65,6 @@ template <> struct MappingTraits { static void mapping(IO &Io, clang::tooling::TranslationUnitReplacements &Doc) { Io.mapRequired("MainSourceFile", Doc.MainSourceFile); - Io.mapOptional("Context", Doc.Context, std::string()); Io.mapRequired("Replacements", Doc.Replacements); } }; diff --git a/lib/Tooling/Core/CMakeLists.txt b/lib/Tooling/Core/CMakeLists.txt index f6348cbf80..e2b0dd424d 100644 --- a/lib/Tooling/Core/CMakeLists.txt +++ b/lib/Tooling/Core/CMakeLists.txt @@ -4,6 +4,7 @@ add_clang_library(clangToolingCore Lookup.cpp Replacement.cpp QualTypeNames.cpp + Diagnostic.cpp LINK_LIBS clangAST diff --git a/lib/Tooling/Core/Diagnostic.cpp b/lib/Tooling/Core/Diagnostic.cpp new file mode 100644 index 0000000000..3bbc2b901e --- /dev/null +++ b/lib/Tooling/Core/Diagnostic.cpp @@ -0,0 +1,46 @@ +//===--- 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 DiagnosticName, + Diagnostic::Level DiagLevel, StringRef BuildDirectory) + : DiagnosticName(DiagnosticName), DiagLevel(DiagLevel), + BuildDirectory(BuildDirectory) {} + +Diagnostic::Diagnostic(llvm::StringRef DiagnosticName, + DiagnosticMessage &Message, + llvm::StringMap &Fix, + SmallVector &Notes, + Level DiagLevel, llvm::StringRef BuildDirectory) + : DiagnosticName(DiagnosticName), Message(Message), Fix(Fix), Notes(Notes), + DiagLevel(DiagLevel), BuildDirectory(BuildDirectory) {} + +} // end namespace tooling +} // end namespace clang diff --git a/unittests/Tooling/ReplacementsYamlTest.cpp b/unittests/Tooling/ReplacementsYamlTest.cpp index a20dde7614..3e4193d2ad 100644 --- a/unittests/Tooling/ReplacementsYamlTest.cpp +++ b/unittests/Tooling/ReplacementsYamlTest.cpp @@ -22,11 +22,8 @@ TEST(ReplacementsYamlTest, serializesReplacements) { TranslationUnitReplacements Doc; Doc.MainSourceFile = "/path/to/source.cpp"; - Doc.Context = "some context"; - Doc.Replacements - .push_back(Replacement("/path/to/file1.h", 232, 56, "replacement #1")); - Doc.Replacements - .push_back(Replacement("/path/to/file2.h", 301, 2, "replacement #2")); + Doc.Replacements.emplace_back("/path/to/file1.h", 232, 56, "replacement #1"); + Doc.Replacements.emplace_back("/path/to/file2.h", 301, 2, "replacement #2"); std::string YamlContent; llvm::raw_string_ostream YamlContentStream(YamlContent); @@ -37,7 +34,6 @@ TEST(ReplacementsYamlTest, serializesReplacements) { // NOTE: If this test starts to fail for no obvious reason, check whitespace. ASSERT_STREQ("---\n" "MainSourceFile: /path/to/source.cpp\n" - "Context: some context\n" "Replacements: \n" // Extra whitespace here! " - FilePath: /path/to/file1.h\n" " Offset: 232\n" @@ -54,7 +50,6 @@ TEST(ReplacementsYamlTest, serializesReplacements) { TEST(ReplacementsYamlTest, deserializesReplacements) { std::string YamlContent = "---\n" "MainSourceFile: /path/to/source.cpp\n" - "Context: some context\n" "Replacements:\n" " - FilePath: /path/to/file1.h\n" " Offset: 232\n" @@ -71,7 +66,6 @@ TEST(ReplacementsYamlTest, deserializesReplacements) { ASSERT_FALSE(YAML.error()); ASSERT_EQ(2u, DocActual.Replacements.size()); ASSERT_EQ("/path/to/source.cpp", DocActual.MainSourceFile); - ASSERT_EQ("some context", DocActual.Context); ASSERT_EQ("/path/to/file1.h", DocActual.Replacements[0].getFilePath()); ASSERT_EQ(232u, DocActual.Replacements[0].getOffset()); ASSERT_EQ(56u, DocActual.Replacements[0].getLength()); @@ -98,7 +92,6 @@ TEST(ReplacementsYamlTest, deserializesWithoutContext) { ASSERT_FALSE(YAML.error()); ASSERT_EQ("/path/to/source.cpp", DocActual.MainSourceFile); ASSERT_EQ(1u, DocActual.Replacements.size()); - ASSERT_EQ(std::string(), DocActual.Context); ASSERT_EQ("target_file.h", DocActual.Replacements[0].getFilePath()); ASSERT_EQ(1u, DocActual.Replacements[0].getOffset()); ASSERT_EQ(10u, DocActual.Replacements[0].getLength());