diff --git a/clang/compiler-course/shishkarev_a_implicit_conversions/CMakeLists.txt b/clang/compiler-course/shishkarev_a_implicit_conversions/CMakeLists.txt new file mode 100644 index 0000000000000..0c4429abfa61b --- /dev/null +++ b/clang/compiler-course/shishkarev_a_implicit_conversions/CMakeLists.txt @@ -0,0 +1,18 @@ +set(Title "ImplicitConversionCounter") +set(Student "Shishkarev_Andrey") +set(Group "FIIT2") +set(TARGET_NAME "${Title}_${Student}_${Group}_ClangAST") + +file(GLOB_RECURSE SOURCES *.cpp *.h *.hpp) +add_llvm_library(${TARGET_NAME} MODULE ${SOURCES} PLUGIN_TOOL clang) + +if(WIN32 OR CYGWIN) + set(LLVM_LINK_COMPONENTS Support) + clang_target_link_libraries(${TARGET_NAME} PRIVATE + clangAST + clangBasic + clangFrontend + ) +endif() + +set(CLANG_TEST_DEPS "${TARGET_NAME}" ${CLANG_TEST_DEPS} PARENT_SCOPE) diff --git a/clang/compiler-course/shishkarev_a_implicit_conversions/shishkarev_a_implicit_conversions.cpp b/clang/compiler-course/shishkarev_a_implicit_conversions/shishkarev_a_implicit_conversions.cpp new file mode 100644 index 0000000000000..3343213dccae5 --- /dev/null +++ b/clang/compiler-course/shishkarev_a_implicit_conversions/shishkarev_a_implicit_conversions.cpp @@ -0,0 +1,123 @@ +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendPluginRegistry.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include +#include +#include + +namespace { +class ImplicitConversionVisitor + : public clang::RecursiveASTVisitor { +public: + explicit ImplicitConversionVisitor(clang::ASTContext *Context) + : MContext(Context) {} + + bool VisitFunctionDecl(clang::FunctionDecl *Func) { + llvm::outs() << "Function `" << Func->getName() << "`\n"; + MConversions.clear(); + + if (Func->hasBody()) { + TraverseStmt(Func->getBody()); + } + + MConversions.erase( + std::remove_if(MConversions.begin(), MConversions.end(), + [](const std::pair &Conv) { + return Conv.first == Conv.second; + }), + MConversions.end()); + + std::set> UniqueConversions; + MConversions.erase( + std::remove_if(MConversions.begin(), MConversions.end(), + [&UniqueConversions]( + const std::pair &Conv) { + return !UniqueConversions.insert(Conv).second; + }), + MConversions.end()); + + for (auto It = MConversions.rbegin(); It != MConversions.rend(); ++It) { + llvm::outs() << It->first << " -> " << It->second << ": 1\n"; + } + + return true; + } + + bool VisitImplicitCastExpr(clang::ImplicitCastExpr *Expr) { + auto FromType = Expr->getSubExpr()->getType().getAsString(); + auto ToType = Expr->getType().getAsString(); + + FromType = normalizeType(FromType, ToType); + ToType = normalizeType(ToType, FromType); + + MConversions.emplace_back(FromType, ToType); + + return RecursiveASTVisitor::VisitImplicitCastExpr(Expr); + } + +private: + clang::ASTContext *MContext; + std::vector> MConversions; + + std::string normalizeType(const std::string &Type, + const std::string &OtherType) { + std::string Normalized = Type; + + size_t PtrPos = Normalized.find("(*)"); + if (PtrPos != std::string::npos) { + Normalized.erase(PtrPos, 3); // Удаляем "(*)" + } + + std::string WithoutModifiers = Normalized; + WithoutModifiers.erase( + std::remove(WithoutModifiers.begin(), WithoutModifiers.end(), '&'), + WithoutModifiers.end()); + WithoutModifiers.erase( + std::remove(WithoutModifiers.begin(), WithoutModifiers.end(), '*'), + WithoutModifiers.end()); + + if (WithoutModifiers == OtherType) { + Normalized = WithoutModifiers; + } + + Normalized.erase(std::remove(Normalized.begin(), Normalized.end(), ' '), + Normalized.end()); + + return Normalized; + } +}; + +class ImplicitConversionConsumer : public clang::ASTConsumer { +public: + explicit ImplicitConversionConsumer(clang::ASTContext *Context) + : MVisitor(Context) {} + + void HandleTranslationUnit(clang::ASTContext &Context) override { + MVisitor.TraverseDecl(Context.getTranslationUnitDecl()); + } + +private: + ImplicitConversionVisitor MVisitor; +}; + +class ImplicitConversionAction : public clang::PluginASTAction { +public: + std::unique_ptr + CreateASTConsumer(clang::CompilerInstance &CI, llvm::StringRef) override { + return std::make_unique(&CI.getASTContext()); + } + + bool ParseArgs(const clang::CompilerInstance &CI, + const std::vector &Args) override { + return true; + } +}; +} // namespace + +static clang::FrontendPluginRegistry::Add + X("implicit_conversion_plugin", "Counts implicit type conversions"); \ No newline at end of file diff --git a/clang/test/compiler-course/shishkarev_a_implicit_conversions/shishkarev_a_implicit_conversions_test.cpp b/clang/test/compiler-course/shishkarev_a_implicit_conversions/shishkarev_a_implicit_conversions_test.cpp new file mode 100644 index 0000000000000..ab4a662623ea6 --- /dev/null +++ b/clang/test/compiler-course/shishkarev_a_implicit_conversions/shishkarev_a_implicit_conversions_test.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -load %llvmshlibdir/ImplicitConversionCounter_Shishkarev_Andrey_FIIT2_ClangAST%pluginext -plugin implicit_conversion_plugin -fsyntax-only %s 2>&1 | FileCheck %s + +// CHECK: Function `sum` +// CHECK-NEXT: int -> float: 1 +// CHECK-NEXT: float -> double: 1 + +// CHECK: Function `mul` +// CHECK-NEXT: float -> int: 1 +// CHECK-NEXT: float -> double: 1 +// CHECK-NEXT: double -> int: 1 + +double sum(int a, float b) { + return a + b; +} + +int mul(float a, float b) { + return a + sum(a, b); +} \ No newline at end of file