diff clang-tools-extra/clang-tidy/ClangTidyCheck.cpp @ 173:0572611fdcc8 llvm10 llvm12

reorgnization done
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 11:55:54 +0900
parents 1d019706d866
children 2e18cbf3894f
line wrap: on
line diff
--- a/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp	Mon May 25 11:50:15 2020 +0900
+++ b/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp	Mon May 25 11:55:54 2020 +0900
@@ -7,10 +7,44 @@
 //===----------------------------------------------------------------------===//
 
 #include "ClangTidyCheck.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
 
 namespace clang {
 namespace tidy {
 
+char MissingOptionError::ID;
+char UnparseableEnumOptionError::ID;
+char UnparseableIntegerOptionError::ID;
+
+std::string MissingOptionError::message() const {
+  llvm::SmallString<128> Buffer;
+  llvm::raw_svector_ostream Output(Buffer);
+  Output << "option not found '" << OptionName << '\'';
+  return std::string(Buffer);
+}
+
+std::string UnparseableEnumOptionError::message() const {
+  llvm::SmallString<128> Buffer;
+  llvm::raw_svector_ostream Output(Buffer);
+  Output << "invalid configuration value '" << LookupValue << "' for option '"
+         << LookupName << '\'';
+  if (SuggestedValue)
+    Output << "; did you mean '" << *SuggestedValue << "'?";
+  return std::string(Buffer);
+}
+
+std::string UnparseableIntegerOptionError::message() const {
+  llvm::SmallString<128> Buffer;
+  llvm::raw_svector_ostream Output(Buffer);
+  Output << "invalid configuration value '" << LookupValue << "' for option '"
+         << LookupName << "'; expected "
+         << (IsBoolean ? "a bool" : "an integer value");
+  return std::string(Buffer);
+}
+
 ClangTidyCheck::ClangTidyCheck(StringRef CheckName, ClangTidyContext *Context)
     : CheckName(CheckName), Context(Context),
       Options(CheckName, Context->getOptions().CheckOptions) {
@@ -34,31 +68,87 @@
                          const ClangTidyOptions::OptionMap &CheckOptions)
     : NamePrefix(CheckName.str() + "."), CheckOptions(CheckOptions) {}
 
-std::string ClangTidyCheck::OptionsView::get(StringRef LocalName,
-                                             StringRef Default) const {
+llvm::Expected<std::string>
+ClangTidyCheck::OptionsView::get(StringRef LocalName) const {
   const auto &Iter = CheckOptions.find(NamePrefix + LocalName.str());
   if (Iter != CheckOptions.end())
-    return Iter->second;
-  return std::string(Default);
+    return Iter->second.Value;
+  return llvm::make_error<MissingOptionError>((NamePrefix + LocalName).str());
+}
+
+llvm::Expected<std::string>
+ClangTidyCheck::OptionsView::getLocalOrGlobal(StringRef LocalName) const {
+  auto IterLocal = CheckOptions.find(NamePrefix + LocalName.str());
+  auto IterGlobal = CheckOptions.find(LocalName.str());
+  if (IterLocal != CheckOptions.end() &&
+      (IterGlobal == CheckOptions.end() ||
+       IterLocal->second.Priority >= IterGlobal->second.Priority))
+    return IterLocal->second.Value;
+  if (IterGlobal != CheckOptions.end())
+    return IterGlobal->second.Value;
+  return llvm::make_error<MissingOptionError>((NamePrefix + LocalName).str());
+}
+
+static llvm::Expected<bool> getAsBool(StringRef Value,
+                                      const llvm::Twine &LookupName) {
+  if (Value == "true")
+    return true;
+  if (Value == "false")
+    return false;
+  bool Result;
+  if (!Value.getAsInteger(10, Result))
+    return Result;
+  return llvm::make_error<UnparseableIntegerOptionError>(LookupName.str(),
+                                                         Value.str(), true);
 }
 
-std::string
-ClangTidyCheck::OptionsView::getLocalOrGlobal(StringRef LocalName,
-                                              StringRef Default) const {
-  auto Iter = CheckOptions.find(NamePrefix + LocalName.str());
-  if (Iter != CheckOptions.end())
-    return Iter->second;
-  // Fallback to global setting, if present.
-  Iter = CheckOptions.find(LocalName.str());
-  if (Iter != CheckOptions.end())
-    return Iter->second;
-  return std::string(Default);
+template <>
+llvm::Expected<bool>
+ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName) const {
+  llvm::Expected<std::string> ValueOr = get(LocalName);
+  if (ValueOr)
+    return getAsBool(*ValueOr, NamePrefix + LocalName);
+  return ValueOr.takeError();
+}
+
+template <>
+bool ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName,
+                                            bool Default) const {
+  llvm::Expected<bool> ValueOr = get<bool>(LocalName);
+  if (ValueOr)
+    return *ValueOr;
+  logErrToStdErr(ValueOr.takeError());
+  return Default;
+}
+
+template <>
+llvm::Expected<bool>
+ClangTidyCheck::OptionsView::getLocalOrGlobal<bool>(StringRef LocalName) const {
+  auto IterLocal = CheckOptions.find(NamePrefix + LocalName.str());
+  auto IterGlobal = CheckOptions.find(LocalName.str());
+  if (IterLocal != CheckOptions.end() &&
+      (IterGlobal == CheckOptions.end() ||
+       IterLocal->second.Priority >= IterGlobal->second.Priority))
+    return getAsBool(IterLocal->second.Value, NamePrefix + LocalName);
+  if (IterGlobal != CheckOptions.end())
+    return getAsBool(IterGlobal->second.Value, llvm::Twine(LocalName));
+  return llvm::make_error<MissingOptionError>((NamePrefix + LocalName).str());
+}
+
+template <>
+bool ClangTidyCheck::OptionsView::getLocalOrGlobal<bool>(StringRef LocalName,
+                                                         bool Default) const {
+  llvm::Expected<bool> ValueOr = getLocalOrGlobal<bool>(LocalName);
+  if (ValueOr)
+    return *ValueOr;
+  logErrToStdErr(ValueOr.takeError());
+  return Default;
 }
 
 void ClangTidyCheck::OptionsView::store(ClangTidyOptions::OptionMap &Options,
                                         StringRef LocalName,
                                         StringRef Value) const {
-  Options[NamePrefix + LocalName.str()] = std::string(Value);
+  Options[NamePrefix + LocalName.str()] = Value;
 }
 
 void ClangTidyCheck::OptionsView::store(ClangTidyOptions::OptionMap &Options,
@@ -67,5 +157,49 @@
   store(Options, LocalName, llvm::itostr(Value));
 }
 
+llvm::Expected<int64_t> ClangTidyCheck::OptionsView::getEnumInt(
+    StringRef LocalName, ArrayRef<std::pair<StringRef, int64_t>> Mapping,
+    bool CheckGlobal, bool IgnoreCase) {
+  auto Iter = CheckOptions.find((NamePrefix + LocalName).str());
+  if (CheckGlobal && Iter == CheckOptions.end())
+    Iter = CheckOptions.find(LocalName.str());
+  if (Iter == CheckOptions.end())
+    return llvm::make_error<MissingOptionError>((NamePrefix + LocalName).str());
+
+  StringRef Value = Iter->second.Value;
+  StringRef Closest;
+  unsigned EditDistance = -1;
+  for (const auto &NameAndEnum : Mapping) {
+    if (IgnoreCase) {
+      if (Value.equals_lower(NameAndEnum.first))
+        return NameAndEnum.second;
+    } else if (Value.equals(NameAndEnum.first)) {
+      return NameAndEnum.second;
+    } else if (Value.equals_lower(NameAndEnum.first)) {
+      Closest = NameAndEnum.first;
+      EditDistance = 0;
+      continue;
+    }
+    unsigned Distance = Value.edit_distance(NameAndEnum.first);
+    if (Distance < EditDistance) {
+      EditDistance = Distance;
+      Closest = NameAndEnum.first;
+    }
+  }
+  if (EditDistance < 3)
+    return llvm::make_error<UnparseableEnumOptionError>(
+        Iter->first, Iter->second.Value, std::string(Closest));
+  return llvm::make_error<UnparseableEnumOptionError>(Iter->first,
+                                                      Iter->second.Value);
+}
+
+void ClangTidyCheck::OptionsView::logErrToStdErr(llvm::Error &&Err) {
+  llvm::logAllUnhandledErrors(
+      llvm::handleErrors(std::move(Err),
+                         [](const MissingOptionError &) -> llvm::Error {
+                           return llvm::Error::success();
+                         }),
+      llvm::errs(), "warning: ");
+}
 } // namespace tidy
 } // namespace clang