mfgnik

Untitled

May 6th, 2020
1,336
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 18.06 KB | None | 0 0
  1. #include <fstream>
  2. #include <unordered_set>
  3.  
  4. #include "clang/AST/ASTConsumer.h"
  5. #include "clang/AST/RecursiveASTVisitor.h"
  6. #include "clang/Frontend/CompilerInstance.h"
  7. #include "clang/Frontend/FrontendAction.h"
  8. #include "clang/Tooling/Tooling.h"
  9. #include "print.h"
  10.  
  11. using namespace clang;
  12. using namespace llvm;
  13.  
  14. struct Node {
  15.     std::string word;
  16.  
  17.     std::array<int, 40> next;
  18.  
  19.     explicit Node(const std::string &word = "") : word(word) {
  20.         next.fill(0);
  21.     }
  22. };
  23.  
  24. int Min(int a, int b) {
  25.     if (a < b) {
  26.         return a;
  27.     }
  28.     return b;
  29. }
  30.  
  31. inline int Min(int first, int second, int third) {
  32.     return Min(first, Min(second, third));
  33. }
  34.  
  35. int LevenshteinDistance(const std::string &first_string, const std::string &second_string) {
  36.     std::vector<std::vector<int>> dynamic(first_string.size() + 1,
  37.                                           std::vector<int>(second_string.size() + 1));
  38.     for (int index = 0; index <= static_cast<int>(first_string.size()); ++index) {
  39.         dynamic[index][0] = index;
  40.     }
  41.     for (int index = 0; index <= static_cast<int>(second_string.size()); ++index) {
  42.         dynamic[0][index] = index;
  43.     }
  44.     for (size_t index_first = 1; index_first <= first_string.size(); ++index_first) {
  45.         for (size_t index_second = 1; index_second <= second_string.size(); ++index_second) {
  46.             if (first_string[index_first - 1] != second_string[index_second - 1]) {
  47.                 dynamic[index_first][index_second] =
  48.                     Min(1 + dynamic[index_first - 1][index_second],
  49.                         1 + dynamic[index_first][index_second - 1],
  50.                         1 + dynamic[index_first - 1][index_second - 1]);
  51.             } else {
  52.                 dynamic[index_first][index_second] = dynamic[index_first - 1][index_second - 1];
  53.             }
  54.         }
  55.     }
  56.     return dynamic.back().back();
  57. }
  58.  
  59. class BkTree {
  60. public:
  61.     BkTree() = default;
  62.  
  63.     explicit BkTree(int size) : current_element_(0), tree_(size) {
  64.     }
  65.  
  66.     void SetSize(int size) {
  67.         current_element_ = 0;
  68.         tree_.resize(size);
  69.     }
  70.  
  71.     void Add(Node &root, Node &node) {
  72.         if (root.word == "") {
  73.             root = node;
  74.             return;
  75.         }
  76.         int dist = LevenshteinDistance(node.word, root.word);
  77.  
  78.         if (tree_[root.next[dist]].word.empty()) {
  79.             ++current_element_;
  80.             tree_[current_element_] = node;
  81.             root.next[dist] = current_element_;
  82.         } else {
  83.             Add(tree_[root.next[dist]], node);
  84.         }
  85.     }
  86.  
  87.     std::pair<int, std::string> GetSimilarWords(Node &root, std::string &string) {
  88.         std::pair<int, std::string> current_candidate{4, ""};
  89.         if (root.word.empty()) {
  90.             return current_candidate;
  91.         }
  92.         auto distance = LevenshteinDistance(root.word, string);
  93.         if (distance < current_candidate.first) {
  94.             current_candidate = {distance, root.word};
  95.         }
  96.         if (distance == 0) {
  97.             return current_candidate;
  98.         }
  99.         auto index = (distance <= 3) ? 1 : distance - 3;
  100.  
  101.         while (index <= distance + 3) {
  102.             auto new_candidate = GetSimilarWords(tree_[root.next[index]], string);
  103.             if (new_candidate.first < current_candidate.first || new_candidate.first ==
  104.                 current_candidate.first && new_candidate.second <
  105.                 current_candidate.second) {
  106.                 current_candidate = new_candidate;
  107.             }
  108.             if (current_candidate.first == 0) {
  109.                 return current_candidate;
  110.             }
  111.             ++index;
  112.         }
  113.         return current_candidate;
  114.     }
  115.  
  116.     Node &GetRoot() {
  117.         return root_;
  118.     }
  119.  
  120.     bool IsEmpty() {
  121.         return tree_.empty();
  122.     }
  123.  
  124. private:
  125.     Node root_;
  126.     int current_element_;
  127.     std::vector<Node> tree_;
  128. };
  129.  
  130. std::unordered_set<std::string> words_set;
  131. BkTree bk_tree;
  132.  
  133. enum class ToPrint { Mistake = 0, BadName = 1 };
  134.  
  135. struct BadNameStruct {
  136.     Entity entity;
  137.     std::string name;
  138.     int line;
  139.     std::string bad_name;
  140.     std::string good_name;
  141.     ToPrint to_print;
  142.  
  143.     BadNameStruct(Entity entity, std::string name, int line, std::string bad_name = "",
  144.                   std::string good_name = "", ToPrint to_print = ToPrint::BadName)
  145.         : entity(entity),
  146.           name(name),
  147.           line(line),
  148.           bad_name(bad_name),
  149.           good_name(good_name),
  150.           to_print(to_print) {
  151.     }
  152.  
  153.     void Print(const std::string &filename) {
  154.         if (to_print == ToPrint::BadName) {
  155.             BadName(entity, name, filename, line);
  156.         } else {
  157.             Mistake(name, bad_name, good_name, filename, line);
  158.         }
  159.     }
  160. };
  161.  
  162. std::vector<BadNameStruct> bad_names;
  163.  
  164. // void PrintVector(const std::vector<std::string> &some_vector) {
  165. //    for (size_t i = 0; i < some_vector.size(); ++i) {
  166. //        llvm::outs() << some_vector[i] << " ";
  167. //    }
  168. //    llvm::outs() << "\n";
  169. //}
  170.  
  171. std::pair<bool, std::vector<std::string>> ParseVariable(const std::string &name,
  172.                                                         char delimiter = '_') {
  173.     std::vector<std::string> split;
  174.     std::string current_word;
  175.     if (name.empty()) {
  176.         return {true, {}};
  177.     }
  178.     if (name[0] == delimiter) {
  179.         return {false, {}};
  180.     }
  181.     for (auto letter : name) {
  182.         if (letter == delimiter) {
  183.             if (!current_word.empty()) {
  184.                 split.push_back(current_word);
  185.             } else {
  186.                 return {false, {}};
  187.             }
  188.             current_word = "";
  189.             continue;
  190.         } else if (!std::islower(letter)) {
  191.             return {false, {}};
  192.         }
  193.         current_word.push_back(letter);
  194.     }
  195.     if (!current_word.empty()) {
  196.         split.push_back(current_word);
  197.     } else {
  198.         return {false, {}};
  199.     }
  200.     return {true, split};
  201. }
  202.  
  203. std::pair<bool, std::vector<std::string>> ParseFunctionOrType(const std::string &name) {
  204.     std::vector<std::string> split;
  205.     std::vector<std::string> words;
  206.     if (name == "main" || name.empty()) {
  207.         return {true, {name}};
  208.     }
  209.     if (!std::isupper(name[0])) {
  210.         return {false, {}};
  211.     }
  212.     std::string current_word;
  213.     bool lowercase = false;
  214.     for (auto letter : name) {
  215.         if (std::isupper(letter)) {
  216.             if (!current_word.empty()) {
  217.                 split.push_back(current_word);
  218.             }
  219.             current_word = "";
  220.         } else if (std::islower(letter)) {
  221.             lowercase = true;
  222.         } else {
  223.             return {false, {}};
  224.         }
  225.         current_word.push_back(letter);
  226.     }
  227.     if (!lowercase) {
  228.         return {false, words};
  229.     }
  230.     if (!current_word.empty()) {
  231.         split.push_back(current_word);
  232.     }
  233.     for (size_t index = 0; index < split.size(); ++index) {
  234.         if (split[index].size() > 1) {
  235.             words.push_back(split[index]);
  236.         } else {
  237.             current_word = "";
  238.             while (index < split.size() && split[index].size() == 1) {
  239.                 current_word.push_back(split[index][0]);
  240.                 ++index;
  241.             }
  242.             if (current_word.size() < 3) {
  243.                 return {false, {}};
  244.             }
  245.             words.push_back(current_word);
  246.             if (index < split.size()) {
  247.                 words.push_back(split[index]);
  248.             }
  249.         }
  250.     }
  251.     return {true, words};
  252. }
  253.  
  254. void CheckWords(const std::vector<std::string> &words, const std::string& name, int line) {
  255.     if (bk_tree.IsEmpty()) {
  256.         return;
  257.     }
  258.     for (auto word : words) {
  259.         if (word.size() <= 3) {
  260.             continue;
  261.         }
  262.         std::string lower_word;
  263.         lower_word.resize(word.size());
  264.         std::transform(word.begin(), word.end(), lower_word.begin(), ::tolower);
  265.         if (words_set.count(word) == 1) {
  266.             continue;
  267.         }
  268.         auto search_result = bk_tree.GetSimilarWords(bk_tree.GetRoot(), lower_word);
  269.         if (search_result.first < 4 && search_result.second != lower_word) {
  270.             bad_names.emplace_back(Entity::kVariable, name, line, word, search_result.second,
  271.                                    ToPrint::Mistake);
  272.         }
  273.     }
  274. }
  275.  
  276. class FindNamedClassVisitor : public RecursiveASTVisitor<FindNamedClassVisitor> {
  277. public:
  278.     explicit FindNamedClassVisitor(ASTContext *context) : context_(context) {
  279.     }
  280.  
  281.     bool VisitVarDecl(VarDecl *declaration) {
  282.         if (!context_->getSourceManager().isInMainFile(declaration->getBeginLoc())) {
  283.             return true;
  284.         }
  285.         auto name = declaration->getDeclName().getAsString();
  286.         if (name == "firstValue" || name == "secondValue") {
  287.             return true;
  288.         }
  289.         std::string short_name = name;
  290.         auto line = context_->getSourceManager().getSpellingLineNumber(declaration->getBeginLoc());
  291.         if (declaration->getType().isConstQualified()) {
  292.             if (short_name[0] != 'k') {
  293.                 bad_names.emplace_back(Entity::kConst, name, line);
  294.                 return true;
  295.             }
  296.             short_name.erase(0, 1);
  297.             auto [result, words] = ParseFunctionOrType(short_name);
  298.             if (!result) {
  299.                 bad_names.emplace_back(Entity::kConst, name, line);
  300.             }
  301.             CheckWords(words, name, line);
  302.         } else if (declaration->isStaticDataMember()) {
  303.             Entity entity;
  304.             if (declaration->getAccess() == AS_public) {
  305.                 entity = Entity::kVariable;
  306.                 if (name.back() == '_') {
  307.                     bad_names.emplace_back(entity, name, line);
  308.                     return true;
  309.                 }
  310.             } else {
  311.                 entity = Entity::kField;
  312.                 if (name.back() != '_') {
  313.                     bad_names.emplace_back(entity, name, line);
  314.                     return true;
  315.                 }
  316.                 short_name.resize(short_name.size() - 1);
  317.             }
  318.             auto [result, words] = ParseVariable(short_name);
  319.             if (!result) {
  320.                 bad_names.emplace_back(entity, name, line);
  321.             }
  322.             CheckWords(words, name, line);
  323.         } else {
  324.             auto [result, words] = ParseVariable(short_name);
  325.             if (!result) {
  326.                 bad_names.emplace_back(Entity::kVariable, name, line);
  327.             }
  328.             CheckWords(words, name, line);
  329.         }
  330.         return true;
  331.     }
  332.  
  333.     bool VisitTypeAliasDecl(TypeAliasDecl *declaration) {
  334.         if (!context_->getSourceManager().isInMainFile(declaration->getBeginLoc())) {
  335.             return true;
  336.         }
  337.         auto name = declaration->getDeclName().getAsString();
  338.         auto line = context_->getSourceManager().getSpellingLineNumber(declaration->getBeginLoc());
  339.         auto [result, words] = ParseFunctionOrType(name);
  340.         if (!result) {
  341.             bad_names.emplace_back(Entity::kType, name, line);
  342.         }
  343.         CheckWords(words, name, line);
  344.         return true;
  345.     }
  346.  
  347.     bool VisitTypedefDecl(TypedefDecl *declaration) {
  348.         if (!context_->getSourceManager().isInMainFile(declaration->getBeginLoc())) {
  349.             return true;
  350.         }
  351.         auto name = declaration->getDeclName().getAsString();
  352.         auto line = context_->getSourceManager().getSpellingLineNumber(declaration->getBeginLoc());
  353.         auto [result, words] = ParseFunctionOrType(name);
  354.         if (!result) {
  355.             bad_names.emplace_back(Entity::kType, name, line);
  356.         }
  357.         CheckWords(words, name, line);
  358.         return true;
  359.     }
  360.  
  361.     bool VisitFieldDecl(FieldDecl *declaration) {
  362.         if (!context_->getSourceManager().isInMainFile(declaration->getBeginLoc())) {
  363.             return true;
  364.         }
  365.         auto name = declaration->getDeclName().getAsString();
  366.         std::string short_name = name;
  367.         auto line = context_->getSourceManager().getSpellingLineNumber(declaration->getBeginLoc());
  368.         if (declaration->getType().isConstQualified()) {
  369.             if (short_name[0] != 'k') {
  370.                 bad_names.emplace_back(Entity::kConst, name, line);
  371.                 return true;
  372.             }
  373.             short_name.erase(0, 1);
  374.             auto [result, words] = ParseFunctionOrType(short_name);
  375.             if (!result) {
  376.                 bad_names.emplace_back(Entity::kConst, name, line);
  377.             }
  378.             CheckWords(words, name, line);
  379.         } else if (declaration->getParent()->isClass()) {
  380.             if (declaration->getAccess() == AS_public) {
  381.                 if (name.back() == '_') {
  382.                     bad_names.emplace_back(Entity::kField, name, line);
  383.                     return true;
  384.                 }
  385.             } else {
  386.                 if (name.back() != '_') {
  387.                     bad_names.emplace_back(Entity::kField, name, line);
  388.                     return true;
  389.                 }
  390.                 short_name.resize(short_name.size() - 1);
  391.             }
  392.  
  393.             auto [result, words] = ParseVariable(short_name);
  394.             if (!result) {
  395.                 bad_names.emplace_back(Entity::kField, name, line);
  396.             }
  397.             CheckWords(words, name, line);
  398.         } else {
  399.             if (name.back() == '_') {
  400.                 bad_names.emplace_back(Entity::kVariable, name, line);
  401.                 return true;
  402.             }
  403.             auto [result, words] = ParseVariable(short_name);
  404.             if (!result) {
  405.                 bad_names.emplace_back(Entity::kVariable, name, line);
  406.             }
  407.             CheckWords(words, name, line);
  408.         }
  409.         return true;
  410.     }
  411.  
  412.     bool VisitFunctionDecl(FunctionDecl *declaration) {
  413.         if (!context_->getSourceManager().isInMainFile(declaration->getBeginLoc())) {
  414.             return true;
  415.         }
  416.         auto name = declaration->getDeclName().getAsString();
  417.         auto line = context_->getSourceManager().getSpellingLineNumber(declaration->getBeginLoc());
  418.         if (name.rfind("operator", 0) == 0) {
  419.             return true;
  420.         }
  421.         if (name.rfind("<") != std::string::npos && name.rfind(">") != std::string::npos) {
  422.             name.resize(name.rfind("<"));
  423.         }
  424.         auto [result, words] = ParseFunctionOrType(name);
  425.         if (!result) {
  426.             bad_names.emplace_back(Entity::kFunction, name, line);
  427.         }
  428.         CheckWords(words, name, line);
  429.         return true;
  430.     }
  431.  
  432.     bool VisitRecordDecl(RecordDecl *declaration) {
  433.         if (!context_->getSourceManager().isInMainFile(declaration->getBeginLoc())) {
  434.             return true;
  435.         }
  436.         auto name = declaration->getDeclName().getAsString();
  437.         auto [result, words] = ParseFunctionOrType(name);
  438.         auto line = context_->getSourceManager().getSpellingLineNumber(declaration->getBeginLoc());
  439.         if (!result) {
  440.             bad_names.emplace_back(
  441.                 Entity::kType, name, line);
  442.         }
  443.         CheckWords(words, name, line);
  444.         return true;
  445.     }
  446.  
  447.     bool VisitEnumDecl(EnumDecl *declaration) {
  448.         if (!context_->getSourceManager().isInMainFile(declaration->getBeginLoc())) {
  449.             return true;
  450.         }
  451.         auto name = declaration->getDeclName().getAsString();
  452.         auto line = context_->getSourceManager().getSpellingLineNumber(declaration->getBeginLoc());
  453.         auto [result, words] = ParseFunctionOrType(name);
  454.         if (!result) {
  455.             bad_names.emplace_back(
  456.                 Entity::kType, name, line);
  457.         }
  458.         CheckWords(words, name, line);
  459.         return true;
  460.     }
  461.  
  462. private:
  463.     ASTContext *context_;
  464. };
  465.  
  466. class FindNamedClassConsumer : public clang::ASTConsumer {
  467. public:
  468.     explicit FindNamedClassConsumer(ASTContext *context) : visitor_(context) {
  469.     }
  470.  
  471.     virtual void HandleTranslationUnit(clang::ASTContext &context) {
  472.         visitor_.TraverseDecl(context.getTranslationUnitDecl());
  473.     }
  474.  
  475. private:
  476.     FindNamedClassVisitor visitor_;
  477. };
  478.  
  479. class FindNamedClassAction : public clang::ASTFrontendAction {
  480. public:
  481.     virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance &compiler,
  482.                                                                   llvm::StringRef in_file) {
  483.         return std::unique_ptr<clang::ASTConsumer>(
  484.             new FindNamedClassConsumer(&compiler.getASTContext()));
  485.     }
  486. };
  487.  
  488. void ProceedFile(const std::string &filename) {
  489.     std::ifstream t(filename);
  490.     std::string code((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
  491.     bad_names.clear();
  492.     clang::tooling::runToolOnCode(std::make_unique<FindNamedClassAction>(), code);
  493.     int mistakes_count = 0;
  494.     int bad_names_count = 0;
  495.     for (auto bad_name : bad_names) {
  496.         if (bad_name.to_print == ToPrint::Mistake) {
  497.             ++mistakes_count;
  498.         } else {
  499.             ++bad_names_count;
  500.         }
  501.     }
  502.     PrintStatistics(filename, bad_names_count, mistakes_count);
  503.     for (auto bad_name : bad_names) {
  504.         bad_name.Print(filename);
  505.     }
  506. }
  507.  
  508. int main(int argc, const char **argv) {
  509.     if (argc > 1) {
  510.         std::vector<std::string> files_to_check;
  511.         std::string dict;
  512.         for (int index = 1; index < argc; ++index) {
  513.             if (argv[index][0] != '-') {
  514.                 files_to_check.emplace_back(argv[index]);
  515.             } else {
  516.                 std::string arg_name(argv[index]);
  517.                 ++index;
  518.                 if (arg_name == "-dict") {
  519.                     dict = argv[index];
  520.                 }
  521.             }
  522.         }
  523.         if (!dict.empty()) {
  524.             std::vector<std::string> words;
  525.             std::ifstream dict_file(dict);
  526.             std::string word;
  527.             while (dict_file >> word) {
  528.                 words_set.insert(word);
  529.                 words.push_back(word);
  530.             }
  531.             bk_tree.SetSize(words.size());
  532.             for (auto word : words) {
  533.                 auto new_node = Node(word);
  534.                 bk_tree.Add(bk_tree.GetRoot(), new_node);
  535.             }
  536.         }
  537.         for (auto filename : files_to_check) {
  538.             ProceedFile(filename);
  539.         }
  540.     }
  541. }
Advertisement
Add Comment
Please, Sign In to add comment