Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <fstream>
- #include <unordered_set>
- #include "clang/AST/ASTConsumer.h"
- #include "clang/AST/RecursiveASTVisitor.h"
- #include "clang/Frontend/CompilerInstance.h"
- #include "clang/Frontend/FrontendAction.h"
- #include "clang/Tooling/Tooling.h"
- #include "print.h"
- using namespace clang;
- using namespace llvm;
- struct Node {
- std::string word;
- std::array<int, 40> next;
- explicit Node(const std::string &word = "") : word(word) {
- next.fill(0);
- }
- };
- int Min(int a, int b) {
- if (a < b) {
- return a;
- }
- return b;
- }
- inline int Min(int first, int second, int third) {
- return Min(first, Min(second, third));
- }
- int LevenshteinDistance(const std::string &first_string, const std::string &second_string) {
- std::vector<std::vector<int>> dynamic(first_string.size() + 1,
- std::vector<int>(second_string.size() + 1));
- for (int index = 0; index <= static_cast<int>(first_string.size()); ++index) {
- dynamic[index][0] = index;
- }
- for (int index = 0; index <= static_cast<int>(second_string.size()); ++index) {
- dynamic[0][index] = index;
- }
- for (size_t index_first = 1; index_first <= first_string.size(); ++index_first) {
- for (size_t index_second = 1; index_second <= second_string.size(); ++index_second) {
- if (first_string[index_first - 1] != second_string[index_second - 1]) {
- dynamic[index_first][index_second] =
- Min(1 + dynamic[index_first - 1][index_second],
- 1 + dynamic[index_first][index_second - 1],
- 1 + dynamic[index_first - 1][index_second - 1]);
- } else {
- dynamic[index_first][index_second] = dynamic[index_first - 1][index_second - 1];
- }
- }
- }
- return dynamic.back().back();
- }
- class BkTree {
- public:
- BkTree() = default;
- explicit BkTree(int size) : current_element_(0), tree_(size) {
- }
- void SetSize(int size) {
- current_element_ = 0;
- tree_.resize(size);
- }
- void Add(Node &root, Node &node) {
- if (root.word == "") {
- root = node;
- return;
- }
- int dist = LevenshteinDistance(node.word, root.word);
- if (tree_[root.next[dist]].word.empty()) {
- ++current_element_;
- tree_[current_element_] = node;
- root.next[dist] = current_element_;
- } else {
- Add(tree_[root.next[dist]], node);
- }
- }
- std::pair<int, std::string> GetSimilarWords(Node &root, std::string &string) {
- std::pair<int, std::string> current_candidate{4, ""};
- if (root.word.empty()) {
- return current_candidate;
- }
- auto distance = LevenshteinDistance(root.word, string);
- if (distance < current_candidate.first) {
- current_candidate = {distance, root.word};
- }
- if (distance == 0) {
- return current_candidate;
- }
- auto index = (distance <= 3) ? 1 : distance - 3;
- while (index <= distance + 3) {
- auto new_candidate = GetSimilarWords(tree_[root.next[index]], string);
- if (new_candidate.first < current_candidate.first || new_candidate.first ==
- current_candidate.first && new_candidate.second <
- current_candidate.second) {
- current_candidate = new_candidate;
- }
- if (current_candidate.first == 0) {
- return current_candidate;
- }
- ++index;
- }
- return current_candidate;
- }
- Node &GetRoot() {
- return root_;
- }
- bool IsEmpty() {
- return tree_.empty();
- }
- private:
- Node root_;
- int current_element_;
- std::vector<Node> tree_;
- };
- std::unordered_set<std::string> words_set;
- BkTree bk_tree;
- enum class ToPrint { Mistake = 0, BadName = 1 };
- struct BadNameStruct {
- Entity entity;
- std::string name;
- int line;
- std::string bad_name;
- std::string good_name;
- ToPrint to_print;
- BadNameStruct(Entity entity, std::string name, int line, std::string bad_name = "",
- std::string good_name = "", ToPrint to_print = ToPrint::BadName)
- : entity(entity),
- name(name),
- line(line),
- bad_name(bad_name),
- good_name(good_name),
- to_print(to_print) {
- }
- void Print(const std::string &filename) {
- if (to_print == ToPrint::BadName) {
- BadName(entity, name, filename, line);
- } else {
- Mistake(name, bad_name, good_name, filename, line);
- }
- }
- };
- std::vector<BadNameStruct> bad_names;
- // void PrintVector(const std::vector<std::string> &some_vector) {
- // for (size_t i = 0; i < some_vector.size(); ++i) {
- // llvm::outs() << some_vector[i] << " ";
- // }
- // llvm::outs() << "\n";
- //}
- std::pair<bool, std::vector<std::string>> ParseVariable(const std::string &name,
- char delimiter = '_') {
- std::vector<std::string> split;
- std::string current_word;
- if (name.empty()) {
- return {true, {}};
- }
- if (name[0] == delimiter) {
- return {false, {}};
- }
- for (auto letter : name) {
- if (letter == delimiter) {
- if (!current_word.empty()) {
- split.push_back(current_word);
- } else {
- return {false, {}};
- }
- current_word = "";
- continue;
- } else if (!std::islower(letter)) {
- return {false, {}};
- }
- current_word.push_back(letter);
- }
- if (!current_word.empty()) {
- split.push_back(current_word);
- } else {
- return {false, {}};
- }
- return {true, split};
- }
- std::pair<bool, std::vector<std::string>> ParseFunctionOrType(const std::string &name) {
- std::vector<std::string> split;
- std::vector<std::string> words;
- if (name == "main" || name.empty()) {
- return {true, {name}};
- }
- if (!std::isupper(name[0])) {
- return {false, {}};
- }
- std::string current_word;
- bool lowercase = false;
- for (auto letter : name) {
- if (std::isupper(letter)) {
- if (!current_word.empty()) {
- split.push_back(current_word);
- }
- current_word = "";
- } else if (std::islower(letter)) {
- lowercase = true;
- } else {
- return {false, {}};
- }
- current_word.push_back(letter);
- }
- if (!lowercase) {
- return {false, words};
- }
- if (!current_word.empty()) {
- split.push_back(current_word);
- }
- for (size_t index = 0; index < split.size(); ++index) {
- if (split[index].size() > 1) {
- words.push_back(split[index]);
- } else {
- current_word = "";
- while (index < split.size() && split[index].size() == 1) {
- current_word.push_back(split[index][0]);
- ++index;
- }
- if (current_word.size() < 3) {
- return {false, {}};
- }
- words.push_back(current_word);
- if (index < split.size()) {
- words.push_back(split[index]);
- }
- }
- }
- return {true, words};
- }
- void CheckWords(const std::vector<std::string> &words, const std::string& name, int line) {
- if (bk_tree.IsEmpty()) {
- return;
- }
- for (auto word : words) {
- if (word.size() <= 3) {
- continue;
- }
- std::string lower_word;
- lower_word.resize(word.size());
- std::transform(word.begin(), word.end(), lower_word.begin(), ::tolower);
- if (words_set.count(word) == 1) {
- continue;
- }
- auto search_result = bk_tree.GetSimilarWords(bk_tree.GetRoot(), lower_word);
- if (search_result.first < 4 && search_result.second != lower_word) {
- bad_names.emplace_back(Entity::kVariable, name, line, word, search_result.second,
- ToPrint::Mistake);
- }
- }
- }
- class FindNamedClassVisitor : public RecursiveASTVisitor<FindNamedClassVisitor> {
- public:
- explicit FindNamedClassVisitor(ASTContext *context) : context_(context) {
- }
- bool VisitVarDecl(VarDecl *declaration) {
- if (!context_->getSourceManager().isInMainFile(declaration->getBeginLoc())) {
- return true;
- }
- auto name = declaration->getDeclName().getAsString();
- if (name == "firstValue" || name == "secondValue") {
- return true;
- }
- std::string short_name = name;
- auto line = context_->getSourceManager().getSpellingLineNumber(declaration->getBeginLoc());
- if (declaration->getType().isConstQualified()) {
- if (short_name[0] != 'k') {
- bad_names.emplace_back(Entity::kConst, name, line);
- return true;
- }
- short_name.erase(0, 1);
- auto [result, words] = ParseFunctionOrType(short_name);
- if (!result) {
- bad_names.emplace_back(Entity::kConst, name, line);
- }
- CheckWords(words, name, line);
- } else if (declaration->isStaticDataMember()) {
- Entity entity;
- if (declaration->getAccess() == AS_public) {
- entity = Entity::kVariable;
- if (name.back() == '_') {
- bad_names.emplace_back(entity, name, line);
- return true;
- }
- } else {
- entity = Entity::kField;
- if (name.back() != '_') {
- bad_names.emplace_back(entity, name, line);
- return true;
- }
- short_name.resize(short_name.size() - 1);
- }
- auto [result, words] = ParseVariable(short_name);
- if (!result) {
- bad_names.emplace_back(entity, name, line);
- }
- CheckWords(words, name, line);
- } else {
- auto [result, words] = ParseVariable(short_name);
- if (!result) {
- bad_names.emplace_back(Entity::kVariable, name, line);
- }
- CheckWords(words, name, line);
- }
- return true;
- }
- bool VisitTypeAliasDecl(TypeAliasDecl *declaration) {
- if (!context_->getSourceManager().isInMainFile(declaration->getBeginLoc())) {
- return true;
- }
- auto name = declaration->getDeclName().getAsString();
- auto line = context_->getSourceManager().getSpellingLineNumber(declaration->getBeginLoc());
- auto [result, words] = ParseFunctionOrType(name);
- if (!result) {
- bad_names.emplace_back(Entity::kType, name, line);
- }
- CheckWords(words, name, line);
- return true;
- }
- bool VisitTypedefDecl(TypedefDecl *declaration) {
- if (!context_->getSourceManager().isInMainFile(declaration->getBeginLoc())) {
- return true;
- }
- auto name = declaration->getDeclName().getAsString();
- auto line = context_->getSourceManager().getSpellingLineNumber(declaration->getBeginLoc());
- auto [result, words] = ParseFunctionOrType(name);
- if (!result) {
- bad_names.emplace_back(Entity::kType, name, line);
- }
- CheckWords(words, name, line);
- return true;
- }
- bool VisitFieldDecl(FieldDecl *declaration) {
- if (!context_->getSourceManager().isInMainFile(declaration->getBeginLoc())) {
- return true;
- }
- auto name = declaration->getDeclName().getAsString();
- std::string short_name = name;
- auto line = context_->getSourceManager().getSpellingLineNumber(declaration->getBeginLoc());
- if (declaration->getType().isConstQualified()) {
- if (short_name[0] != 'k') {
- bad_names.emplace_back(Entity::kConst, name, line);
- return true;
- }
- short_name.erase(0, 1);
- auto [result, words] = ParseFunctionOrType(short_name);
- if (!result) {
- bad_names.emplace_back(Entity::kConst, name, line);
- }
- CheckWords(words, name, line);
- } else if (declaration->getParent()->isClass()) {
- if (declaration->getAccess() == AS_public) {
- if (name.back() == '_') {
- bad_names.emplace_back(Entity::kField, name, line);
- return true;
- }
- } else {
- if (name.back() != '_') {
- bad_names.emplace_back(Entity::kField, name, line);
- return true;
- }
- short_name.resize(short_name.size() - 1);
- }
- auto [result, words] = ParseVariable(short_name);
- if (!result) {
- bad_names.emplace_back(Entity::kField, name, line);
- }
- CheckWords(words, name, line);
- } else {
- if (name.back() == '_') {
- bad_names.emplace_back(Entity::kVariable, name, line);
- return true;
- }
- auto [result, words] = ParseVariable(short_name);
- if (!result) {
- bad_names.emplace_back(Entity::kVariable, name, line);
- }
- CheckWords(words, name, line);
- }
- return true;
- }
- bool VisitFunctionDecl(FunctionDecl *declaration) {
- if (!context_->getSourceManager().isInMainFile(declaration->getBeginLoc())) {
- return true;
- }
- auto name = declaration->getDeclName().getAsString();
- auto line = context_->getSourceManager().getSpellingLineNumber(declaration->getBeginLoc());
- if (name.rfind("operator", 0) == 0) {
- return true;
- }
- if (name.rfind("<") != std::string::npos && name.rfind(">") != std::string::npos) {
- name.resize(name.rfind("<"));
- }
- auto [result, words] = ParseFunctionOrType(name);
- if (!result) {
- bad_names.emplace_back(Entity::kFunction, name, line);
- }
- CheckWords(words, name, line);
- return true;
- }
- bool VisitRecordDecl(RecordDecl *declaration) {
- if (!context_->getSourceManager().isInMainFile(declaration->getBeginLoc())) {
- return true;
- }
- auto name = declaration->getDeclName().getAsString();
- auto [result, words] = ParseFunctionOrType(name);
- auto line = context_->getSourceManager().getSpellingLineNumber(declaration->getBeginLoc());
- if (!result) {
- bad_names.emplace_back(
- Entity::kType, name, line);
- }
- CheckWords(words, name, line);
- return true;
- }
- bool VisitEnumDecl(EnumDecl *declaration) {
- if (!context_->getSourceManager().isInMainFile(declaration->getBeginLoc())) {
- return true;
- }
- auto name = declaration->getDeclName().getAsString();
- auto line = context_->getSourceManager().getSpellingLineNumber(declaration->getBeginLoc());
- auto [result, words] = ParseFunctionOrType(name);
- if (!result) {
- bad_names.emplace_back(
- Entity::kType, name, line);
- }
- CheckWords(words, name, line);
- return true;
- }
- private:
- ASTContext *context_;
- };
- class FindNamedClassConsumer : public clang::ASTConsumer {
- public:
- explicit FindNamedClassConsumer(ASTContext *context) : visitor_(context) {
- }
- virtual void HandleTranslationUnit(clang::ASTContext &context) {
- visitor_.TraverseDecl(context.getTranslationUnitDecl());
- }
- private:
- FindNamedClassVisitor visitor_;
- };
- class FindNamedClassAction : public clang::ASTFrontendAction {
- public:
- virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance &compiler,
- llvm::StringRef in_file) {
- return std::unique_ptr<clang::ASTConsumer>(
- new FindNamedClassConsumer(&compiler.getASTContext()));
- }
- };
- void ProceedFile(const std::string &filename) {
- std::ifstream t(filename);
- std::string code((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
- bad_names.clear();
- clang::tooling::runToolOnCode(std::make_unique<FindNamedClassAction>(), code);
- int mistakes_count = 0;
- int bad_names_count = 0;
- for (auto bad_name : bad_names) {
- if (bad_name.to_print == ToPrint::Mistake) {
- ++mistakes_count;
- } else {
- ++bad_names_count;
- }
- }
- PrintStatistics(filename, bad_names_count, mistakes_count);
- for (auto bad_name : bad_names) {
- bad_name.Print(filename);
- }
- }
- int main(int argc, const char **argv) {
- if (argc > 1) {
- std::vector<std::string> files_to_check;
- std::string dict;
- for (int index = 1; index < argc; ++index) {
- if (argv[index][0] != '-') {
- files_to_check.emplace_back(argv[index]);
- } else {
- std::string arg_name(argv[index]);
- ++index;
- if (arg_name == "-dict") {
- dict = argv[index];
- }
- }
- }
- if (!dict.empty()) {
- std::vector<std::string> words;
- std::ifstream dict_file(dict);
- std::string word;
- while (dict_file >> word) {
- words_set.insert(word);
- words.push_back(word);
- }
- bk_tree.SetSize(words.size());
- for (auto word : words) {
- auto new_node = Node(word);
- bk_tree.Add(bk_tree.GetRoot(), new_node);
- }
- }
- for (auto filename : files_to_check) {
- ProceedFile(filename);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment