From 4d5e3b3db3e52e2ba8a1223a9e123b9df3558b12 Mon Sep 17 00:00:00 2001 From: Aperzer Date: Thu, 2 Jan 2025 16:42:08 +0800 Subject: [PATCH 1/2] [fat ptr tool] Add fat ptr modify tool. This commit mainly: 1. Add two checkers for fat ptr tool. The collecter will collect advance information, and save it in a '.cfg' file. The transformer will modify the given file with information from collector. 2. Add an entrance program `bsc-build.py`, and a fake clang compiler 'fake_clang.py'. For internal use, check README.txt in 'clang-tools-extra/clang-tidy/tools/bsc/'. All test cases have been passed. --- clang-tools-extra/clang-tidy/ClangTidy.cpp | 17 +- .../clang-tidy/bsc/BSCTidyModule.cpp | 9 + .../clang-tidy/bsc/CMakeLists.txt | 3 + .../clang-tidy/bsc/FatPtrCheck.cpp | 37 +++ .../clang-tidy/bsc/FatPtrCheck.h | 48 ++++ .../clang-tidy/bsc/FatPtrCollecterCheck.cpp | 113 ++++++++ .../clang-tidy/bsc/FatPtrCollecterCheck.h | 36 +++ .../clang-tidy/bsc/FatPtrTransformerCheck.cpp | 271 ++++++++++++++++++ .../clang-tidy/bsc/FatPtrTransformerCheck.h | 74 +++++ .../clang-tidy/tool/bsc/README.txt | 200 +++++++++++++ .../clang-tidy/tool/bsc/bsc-build.py | 221 ++++++++++++++ .../clang-tidy/tool/bsc/fake_clang.py | 93 ++++++ clang-tools-extra/docs/ReleaseNotes.rst | 15 + .../checks/bsc/fat-ptr-collecter.rst | 6 + .../checks/bsc/fat-ptr-transformer.rst | 6 + .../docs/clang-tidy/checks/bsc/fat-ptr.rst | 6 + .../docs/clang-tidy/checks/list.rst | 5 +- .../checkers/bsc/fat-ptr-collecter.cpp | 14 + .../checkers/bsc/fat-ptr-transformer.cpp | 14 + .../test/clang-tidy/checkers/bsc/fat-ptr.cpp | 14 + 20 files changed, 1194 insertions(+), 8 deletions(-) create mode 100644 clang-tools-extra/clang-tidy/bsc/FatPtrCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/bsc/FatPtrCheck.h create mode 100644 clang-tools-extra/clang-tidy/bsc/FatPtrCollecterCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/bsc/FatPtrCollecterCheck.h create mode 100644 clang-tools-extra/clang-tidy/bsc/FatPtrTransformerCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/bsc/FatPtrTransformerCheck.h create mode 100644 clang-tools-extra/clang-tidy/tool/bsc/README.txt create mode 100644 clang-tools-extra/clang-tidy/tool/bsc/bsc-build.py create mode 100644 clang-tools-extra/clang-tidy/tool/bsc/fake_clang.py create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bsc/fat-ptr-collecter.rst create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bsc/fat-ptr-transformer.rst create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bsc/fat-ptr.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bsc/fat-ptr-collecter.cpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bsc/fat-ptr-transformer.cpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bsc/fat-ptr.cpp diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp index f405ace6d7fa..5d93e17ce31a 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -606,14 +606,17 @@ void handleErrors(llvm::ArrayRef Errors, // Situations if users want to disable clang diagnostic checker. std::string CheckName = Error.DiagnosticName; if (IsNoClangDiagnostic) { - std::string CastChecker = "bsc-explicit-cast"; - std::string AccessChecker = "bsc-access-specific-type"; - if (CheckName.find(CastChecker) != std::string::npos || - CheckName.find(AccessChecker) != std::string::npos) { - llvm::outs() << "--------- flag begin ---------\n"; + // std::string CastChecker = "bsc-explicit-cast"; + // std::string AccessChecker = "bsc-access-specific-type"; + // if (CheckName.find(CastChecker) != std::string::npos || + // CheckName.find(AccessChecker) != std::string::npos) { + // llvm::outs() << "--------- flag begin ---------\n"; + // Reporter.reportDiagnostic(Error); + // llvm::outs() << "--------- flag end ---------\n"; + // } + std::string BSCChecker = "bsc-"; + if (CheckName.find(BSCChecker) != std::string::npos) Reporter.reportDiagnostic(Error); - llvm::outs() << "--------- flag end ---------\n"; - } } else { Reporter.reportDiagnostic(Error); } diff --git a/clang-tools-extra/clang-tidy/bsc/BSCTidyModule.cpp b/clang-tools-extra/clang-tidy/bsc/BSCTidyModule.cpp index 6a40e0b72f7a..eefdba0bf4f8 100644 --- a/clang-tools-extra/clang-tidy/bsc/BSCTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bsc/BSCTidyModule.cpp @@ -12,6 +12,9 @@ #include "AccessSpecificTypeCheck.h" #include "AddNewFieldCheck.h" #include "ExplicitCastCheck.h" +#include "FatPtrCheck.h" +#include "FatPtrCollecterCheck.h" +#include "FatPtrTransformerCheck.h" namespace clang { namespace tidy { @@ -26,6 +29,12 @@ public: "bsc-add-new-field"); CheckFactories.registerCheck( "bsc-explicit-cast"); + CheckFactories.registerCheck( + "bsc-fat-ptr"); + CheckFactories.registerCheck( + "bsc-fat-ptr-collecter"); + CheckFactories.registerCheck( + "bsc-fat-ptr-transformer"); } }; diff --git a/clang-tools-extra/clang-tidy/bsc/CMakeLists.txt b/clang-tools-extra/clang-tidy/bsc/CMakeLists.txt index 6053d867b678..7c35b3fe2efe 100644 --- a/clang-tools-extra/clang-tidy/bsc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bsc/CMakeLists.txt @@ -9,6 +9,9 @@ add_clang_library(clangTidyBscModule AddNewFieldCheck.cpp BSCTidyModule.cpp ExplicitCastCheck.cpp + FatPtrCheck.cpp + FatPtrCollecterCheck.cpp + FatPtrTransformerCheck.cpp LINK_LIBS clangTidy diff --git a/clang-tools-extra/clang-tidy/bsc/FatPtrCheck.cpp b/clang-tools-extra/clang-tidy/bsc/FatPtrCheck.cpp new file mode 100644 index 000000000000..5d27c18884cf --- /dev/null +++ b/clang-tools-extra/clang-tidy/bsc/FatPtrCheck.cpp @@ -0,0 +1,37 @@ +//===--- FatPtrCheck.cpp - clang-tidy -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "FatPtrCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bsc { + +void FatPtrCheck::registerMatchers(MatchFinder *Finder) { + // FIXME: Add matchers. + Finder->addMatcher(functionDecl().bind("x"), this); +} + +void FatPtrCheck::check(const MatchFinder::MatchResult &Result) { + // FIXME: Add callback implementation. + const auto *MatchedDecl = Result.Nodes.getNodeAs("x"); + if (!MatchedDecl->getIdentifier() || MatchedDecl->getName().startswith("awesome_")) + return; + diag(MatchedDecl->getLocation(), "function %0 is insufficiently awesome") + << MatchedDecl; + diag(MatchedDecl->getLocation(), "insert 'awesome'", DiagnosticIDs::Note) + << FixItHint::CreateInsertion(MatchedDecl->getLocation(), "awesome_"); +} + +} // namespace bsc +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/bsc/FatPtrCheck.h b/clang-tools-extra/clang-tidy/bsc/FatPtrCheck.h new file mode 100644 index 000000000000..06a38a3a2fbf --- /dev/null +++ b/clang-tools-extra/clang-tidy/bsc/FatPtrCheck.h @@ -0,0 +1,48 @@ +//===--- FatPtrCheck.h - clang-tidy -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BSC_FATPTRCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BSC_FATPTRCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace bsc { + +/// FIXME: Write a short description. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bsc/fat-ptr.html +class FatPtrCheck : public ClangTidyCheck { +public: + FatPtrCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + TopLevelFunctionList(Options.get("TopLevelFunctions", "TEMP_FAILURE_RETRY")), + TopLevelVarList(Options.get("TopLevelVars", "TEMP_FAILURE_RETRY")) { + StringRef(TopLevelFunctionList).split(TopLevelFunctions, ",", -1, false); + StringRef(TopLevelVarList).split(TopLevelVars, ",", -1, false); + } + void storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "TopLevelFunctions", TopLevelFunctionList); + Options.store(Opts, "TopLevelVars", TopLevelVarList); + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +private: + const StringRef TopLevelFunctionList; + SmallVector TopLevelFunctions; + const StringRef TopLevelVarList; + SmallVector TopLevelVars; +}; + +} // namespace bsc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BSC_FATPTRCHECK_H diff --git a/clang-tools-extra/clang-tidy/bsc/FatPtrCollecterCheck.cpp b/clang-tools-extra/clang-tidy/bsc/FatPtrCollecterCheck.cpp new file mode 100644 index 000000000000..bc9e4ba08123 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bsc/FatPtrCollecterCheck.cpp @@ -0,0 +1,113 @@ +//===--- FatPtrCollecterCheck.cpp - clang-tidy ----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include +#include +#include "FatPtrCollecterCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/AST/BSC/DeclBSC.h" +#include "clang/Tooling/CommonOptionsParser.h" + +static llvm::cl::opt CFGPath( + "cfg-path", + llvm::cl::desc( + "Indicate the path of cfg file."), + llvm::cl::init("empty"), llvm::cl::Hidden); + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bsc { + +static inline int SaveInCFG(const NamedDecl *ND) { + if (CFGPath == "Empty") { + std::cerr << "No cfg path received, please check input parameter `--cfg-path`" << std::endl; + return 0; + } + + std::ofstream OutFile; + OutFile.open(CFGPath, std::ios::out | std::ios::app); + if (!OutFile.is_open()) { + std::cerr << "can not open fat_ptr.cfg, fail to save toplevel items." << std::endl; + return 0; + } + + std::string Name = ND->getNameAsString(); + OutFile << "," << Name; + OutFile.close(); + return 1; +} + +// Check whether this Decl comes from Mainfile or header file. +static inline bool CheckFileId(const clang::SourceManager* SM, + FileID MainFileID, const NamedDecl *ND){ + if (MainFileID.isInvalid()) { + MainFileID = SM->getMainFileID(); + if (MainFileID.isInvalid()) + return 0; + } + + FileID LocationID = SM->getFileID(SM->getSpellingLoc(ND->getLocation())); + if (LocationID.isValid()) { + if (MainFileID == LocationID) + return 1; + } + + return 0; +} + +void FatPtrCollecterCheck::registerMatchers(MatchFinder *Finder) { + auto PT = hasUnqualifiedDesugaredType(pointerType()); + auto AT = hasUnqualifiedDesugaredType(arrayType()); + auto RT = hasUnqualifiedDesugaredType(recordType()); + + Finder->addMatcher(functionDecl(hasParent(translationUnitDecl()), hasBody(stmt())).bind("TopLevelFuncDecl"), this); + Finder->addMatcher(varDecl(hasGlobalStorage(), + anyOf(hasType(PT), hasType(AT), hasType(RT))).bind("GlobalVar"), this); +} + +void FatPtrCollecterCheck::check(const MatchFinder::MatchResult &Result) { + const auto *TopLevelFuncDecl = Result.Nodes.getNodeAs("TopLevelFuncDecl"); + const auto *GlobalVar = Result.Nodes.getNodeAs("GlobalVar"); + + if (TopLevelFuncDecl){ + const auto *BSCMD = dyn_cast_or_null(TopLevelFuncDecl); + // Exclude 'Member Function' scenarios. + if (!BSCMD) { + // Exclude 'Extern' scenarios. + if (TopLevelFuncDecl->getStorageClass() != SC_Extern) { + if (!CheckFileId(Result.SourceManager, MainFileID, TopLevelFuncDecl)) + return; + // Save top-level function-name in cfg file. + if (!SaveInCFG(TopLevelFuncDecl)) + diag(TopLevelFuncDecl->getLocation(), + "Failed to save TopLevelFuncDecl: %0", + DiagnosticIDs::Error) << TopLevelFuncDecl; + } + } + } + + if (GlobalVar) { + // Exclude 'Extern' scenarios. + if (!GlobalVar->hasExternalStorage()) { + if (!CheckFileId(Result.SourceManager, MainFileID, GlobalVar)) + return; + // Save top-level var-name in cfg file. + if (!SaveInCFG(GlobalVar)) + diag(GlobalVar->getLocation(), + "Failed to save GlobalVar: %0", + DiagnosticIDs::Error) << GlobalVar; + } + } +} + +} // namespace bsc +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/bsc/FatPtrCollecterCheck.h b/clang-tools-extra/clang-tidy/bsc/FatPtrCollecterCheck.h new file mode 100644 index 000000000000..ccf9b797395b --- /dev/null +++ b/clang-tools-extra/clang-tidy/bsc/FatPtrCollecterCheck.h @@ -0,0 +1,36 @@ +//===--- FatPtrCollecterCheck.h - clang-tidy --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BSC_FATPTRCOLLECTERCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BSC_FATPTRCOLLECTERCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace bsc { + +/// FIXME: Write a short description. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bsc/fat-ptr-collecter.html +class FatPtrCollecterCheck : public ClangTidyCheck { +public: + FatPtrCollecterCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +private: + FileID MainFileID; +}; + +} // namespace bsc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BSC_FATPTRCOLLECTERCHECK_H diff --git a/clang-tools-extra/clang-tidy/bsc/FatPtrTransformerCheck.cpp b/clang-tools-extra/clang-tidy/bsc/FatPtrTransformerCheck.cpp new file mode 100644 index 000000000000..05cea3278f2f --- /dev/null +++ b/clang-tools-extra/clang-tidy/bsc/FatPtrTransformerCheck.cpp @@ -0,0 +1,271 @@ +//===--- FatPtrTransformerCheck.cpp - clang-tidy --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "FatPtrTransformerCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bsc { + +void FatPtrTransformerCheck::AddFat(SourceLocation Loc) { + diag(Loc, "Add 'fat' token here",DiagnosticIDs::Warning) + << FixItHint::CreateInsertion(Loc, "fat "); +} + +void FatPtrTransformerCheck::AddChecked(SourceLocation Loc) { + diag(Loc, "Add 'CHECKED' token here",DiagnosticIDs::Warning) + << FixItHint::CreateInsertion(Loc, "CHECKED "); +} + +void FatPtrTransformerCheck::CheckTypedefAndSetFat(const ValueDecl *D, + SourceManager *SM) { + QualType DType = D->getType(); + if (!DType.getTypePtr()->getAs()) { + AddHeader(SM); + AddFat(D->getLocation()); + } +} + +std::string FatPtrTransformerCheck::GetTypeName(const Expr *Arg) { + switch (Arg->getStmtClass()) { + case Stmt::UnaryExprOrTypeTraitExprClass: { + const auto *UEOTT = dyn_cast(Arg); + return UEOTT->getTypeOfArgument().getAsString(); + } + case Stmt::ImplicitCastExprClass: { + const auto *ImpCE = dyn_cast(Arg); + const auto *CSCE = dyn_cast(Arg); + return GetTypeName(ImpCE->getSubExpr()); + } + case Stmt::CallExprClass: { + const auto *CE = dyn_cast(Arg); + return CE->getType().getAsString(); + } + case Stmt::IntegerLiteralClass: { + const auto *IL = dyn_cast(Arg); + return IL->getType().getAsString(); + } + case Stmt::DeclRefExprClass: { + const auto *DRE = dyn_cast(Arg); + return DRE->getType().getAsString(); + } + default: { + llvm_unreachable("NYI"); + return "Unknow Type"; + } + } +} + +void FatPtrTransformerCheck::TraversalRecordDecl(RecordDecl *RD, + bool *HasArrayField) { + if (RD->isInvalidDecl()) + return; + + for(FieldDecl* DeclField : RD->fields()) { + if (const auto *GRTY = dyn_cast_or_null + (DeclField->getType().getTypePtr())) { + if (const auto *RT = dyn_cast_or_null + (GRTY->getNamedType())) { + if (FindInDeclList(HasArrayField, RT)) + return; + TraversalRecordDecl(RT->getDecl(), HasArrayField); + } + } else if (const auto *RT = dyn_cast_or_null + (DeclField->getType().getTypePtr())) { + if (FindInDeclList(HasArrayField, RT)) + return; + TraversalRecordDecl(RT->getDecl(), HasArrayField); + } + + if(*HasArrayField) { + DeclList.push_back(RD); + return; + } + + if(DeclField->getType()->isArrayType()) { + *HasArrayField = true; + DeclList.push_back(RD); + return; + } + } +} + +void FatPtrTransformerCheck::registerMatchers(MatchFinder *Finder) { + auto PT = hasUnqualifiedDesugaredType(pointerType()); + auto AT = hasUnqualifiedDesugaredType(arrayType()); + auto RT = hasUnqualifiedDesugaredType(recordType()); + + for (auto TopLevelName : TopLevels) { + Finder->addMatcher(parmVarDecl(hasParent(functionDecl( + hasName(std::string(TopLevelName)))), + hasType(PT)).bind("PtParmVarDecl"), this); + + Finder->addMatcher(functionDecl(hasParent(translationUnitDecl()), + hasName(std::string(TopLevelName)), + returns(isAnyPointer())).bind("FuncDeclRtPt"), this); + + Finder->addMatcher(callExpr(callee(functionDecl(hasName("malloc"))), + hasParent(castExpr().bind("MallocParent"))) + .bind("MallocCall"), this); + Finder->addMatcher(callExpr(callee(functionDecl(hasName("free")))).bind("FreecCall"), this); + + Finder->addMatcher(varDecl(hasGlobalStorage(), + hasName(std::string(TopLevelName)), + hasType(PT)).bind("GlobalPointerVar"), this); + Finder->addMatcher(varDecl(hasGlobalStorage(), + hasName(std::string(TopLevelName)), + allOf(hasType(AT), unless(hasType(PT)))).bind("GlobalArrayVar"), this); + Finder->addMatcher(varDecl(hasGlobalStorage(), + hasName(std::string(TopLevelName)), + hasType(RT)).bind("GlobalRecordVar"), this); + + Finder->addMatcher(varDecl(hasAncestor(functionDecl(hasName(std::string(TopLevelName)))), + hasLocalStorage(), hasType(PT)).bind("LocalPointerVar"), this); + + Finder->addMatcher(typedefDecl(hasType(PT)).bind("TypedefPT"), this); + Finder->addMatcher(unaryOperator(hasType(PT), hasOperatorName("&")).bind("UnOpAddr"), this); + Finder->addMatcher(cStyleCastExpr(hasType(PT)).bind("CCastExprPT"), this); + } +} + +void FatPtrTransformerCheck::check(const MatchFinder::MatchResult &Result) { + if (MainFileID.isInvalid()) + MainFileID = Result.SourceManager->getMainFileID(); + + const auto *PtParmVarDecl = Result.Nodes.getNodeAs("PtParmVarDecl"); + const auto *FuncDeclRtPt = Result.Nodes.getNodeAs("FuncDeclRtPt"); + + const auto *GlobalPointerVar = Result.Nodes.getNodeAs("GlobalPointerVar"); + const auto *GlobalArrayVar = Result.Nodes.getNodeAs("GlobalArrayVar"); + const auto *GlobalRecordVar = Result.Nodes.getNodeAs("GlobalRecordVar"); + const auto *LocalPointerVar = Result.Nodes.getNodeAs("LocalPointerVar"); + + const auto *TypedefPT = Result.Nodes.getNodeAs("TypedefPT"); + const auto *UnOpAddr = Result.Nodes.getNodeAs("UnOpAddr"); + const auto *CCastExprPT = Result.Nodes.getNodeAs("CCastExprPT"); + + const auto *MallocCall = Result.Nodes.getNodeAs("MallocCall"); + const auto *MallocParent = Result.Nodes.getNodeAs("MallocParent"); + + const auto *FreecCall = Result.Nodes.getNodeAs("FreecCall"); + + if (UnOpAddr) { + if (UnOpAddr->getOpcode() == UnaryOperatorKind::UO_AddrOf) { + AddHeader(Result.SourceManager); + AddFat(UnOpAddr->getEndLoc()); + } + } + + if (CCastExprPT) { + AddHeader(Result.SourceManager); + AddFat(CCastExprPT->getRParenLoc()); + } + + if (PtParmVarDecl) { + diag(PtParmVarDecl->getBeginLoc(), "Find PtParmVarDecl here", DiagnosticIDs::Warning); + } + + if (MallocCall) { + if (MallocParent) { + if (const clang::Type *CT = dyn_cast(MallocParent->getType().getTypePtr())) { + if (const PointerType *PT = CT->getAs()) { + std::string ReplaceStr = "checked_malloc<"; + ReplaceStr.append(PT->getPointeeType().getAsString()); + ReplaceStr.append(">"); + + SourceLocation BeginLoc = MallocCall->getExprLoc(); + SourceLocation EndLoc = MallocCall->getArg(0)->getExprLoc(); + SourceRange SR = SourceRange(BeginLoc, EndLoc.getLocWithOffset(-2)); + diag(BeginLoc, "Find Malloc Call here", DiagnosticIDs::Warning) + << FixItHint::CreateReplacement(SR, ReplaceStr); + AddHeader(Result.SourceManager); + } + } + } + } + + if (FreecCall) { + if (const CastExpr *Arg = dyn_cast_or_null(FreecCall->getArg(0))) { + if (const clang::Type *CT = dyn_cast(Arg->getSubExpr()->getType().getTypePtr())) { + if (const PointerType *PT = CT->getAs()) { + std::string ReplaceStr = "checked_free<"; + ReplaceStr.append(PT->getPointeeType().getAsString()); + ReplaceStr.append(">"); + + SourceLocation BeginLoc = FreecCall->getExprLoc(); + SourceLocation EndLoc = FreecCall->getArg(0)->getExprLoc(); + SourceRange SR = SourceRange(BeginLoc, EndLoc.getLocWithOffset(-2)); + diag(BeginLoc, "Find Free Call here", DiagnosticIDs::Warning) + << FixItHint::CreateReplacement(SR, ReplaceStr); + AddHeader(Result.SourceManager); + } + } + } + } + + if (GlobalArrayVar){ + if (const auto *CAT = dyn_cast_or_null + (GlobalArrayVar->getType().getTypePtr())) { + AddHeader(Result.SourceManager); + QualType VarType = CAT->getElementType(); + if (const TypedefType *TdefT = dyn_cast_or_null(VarType.getTypePtr())) { + if (!TdefT->getAs()) + AddChecked(GlobalArrayVar->getBeginLoc()); + } else if (const auto *PT = dyn_cast_or_null(VarType.getTypePtr())) { + AddFat(GlobalArrayVar->getLocation()); + } else { + AddChecked(GlobalArrayVar->getBeginLoc()); + } + } + } + + if (GlobalRecordVar){ + if (const auto *GRTY = dyn_cast_or_null + (GlobalRecordVar->getType().getTypePtr())) { + if (const auto *RT = dyn_cast_or_null + (GRTY->getNamedType())) { + bool HasArrayField = false; + if (!FindInDeclList(&HasArrayField, RT)) + TraversalRecordDecl(RT->getDecl(), &HasArrayField); + + if (HasArrayField) { + AddChecked(GlobalRecordVar->getBeginLoc()); + AddHeader(Result.SourceManager); + } + } + } + } + + if (GlobalPointerVar) + CheckTypedefAndSetFat(GlobalPointerVar, Result.SourceManager); + + if (LocalPointerVar) + CheckTypedefAndSetFat(LocalPointerVar, Result.SourceManager); + + if (FuncDeclRtPt) + CheckTypedefAndSetFat(FuncDeclRtPt, Result.SourceManager); + + if (TypedefPT) { + SourceLocation TypedefLoc = TypedefPT->getLocation(); + FileID LocationID = Result.SourceManager->getFileID(Result.SourceManager-> + getSpellingLoc(TypedefLoc)); + if (LocationID.isValid()) { + if (MainFileID == LocationID) { + AddHeader(Result.SourceManager); + AddFat(TypedefPT->getLocation()); + } + } + } +} +} // namespace bsc +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/bsc/FatPtrTransformerCheck.h b/clang-tools-extra/clang-tidy/bsc/FatPtrTransformerCheck.h new file mode 100644 index 000000000000..d4e37c9ff3c8 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bsc/FatPtrTransformerCheck.h @@ -0,0 +1,74 @@ +//===--- FatPtrTransformerCheck.h - clang-tidy ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BSC_FATPTRTRANSFORMERCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BSC_FATPTRTRANSFORMERCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace bsc { + +/// FIXME: Write a short description. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bsc/fat-ptr-transformer.html +class FatPtrTransformerCheck : public ClangTidyCheck { +public: + FatPtrTransformerCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + TopLevelList(Options.get("TopLevels", "TEMP_FAILURE_RETRY")) { + StringRef(TopLevelList).split(TopLevels, ",", -1, false); + } + void storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "TopLevels", TopLevelList); + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +private: + const StringRef TopLevelList; + SmallVector TopLevels; + FileID MainFileID; + bool NeedFix = false; + bool AlreadyAddHeader = false; + std::vector DeclList; + + void TraversalRecordDecl(RecordDecl *RD, bool *HasArrayField); + void AddFat(SourceLocation Loc); + void AddChecked(SourceLocation Loc); + std::string GetTypeName(const Expr *Arg); + void CheckTypedefAndSetFat(const ValueDecl *D, SourceManager *SM); + + inline bool FindInDeclList(bool *HasArrayField, + const clang::RecordType* RT) { + auto Existed = std::find(DeclList.begin(), DeclList.end(), RT->getDecl()); + if (Existed != DeclList.end()) { + *HasArrayField = true; + return true; + } + return false; + } + + inline void AddHeader(SourceManager *SM) { + if (!AlreadyAddHeader) { + if (!MainFileID.isInvalid()){ + SourceLocation StartOfFileLoc = SM->getLocForStartOfFile(MainFileID); + diag(StartOfFileLoc, "Add Header Here.", DiagnosticIDs::Warning) << + FixItHint::CreateInsertion(StartOfFileLoc, "#include \n"); + AlreadyAddHeader = true; + } + } + } +}; + +} // namespace bsc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BSC_FATPTRTRANSFORMERCHECK_H diff --git a/clang-tools-extra/clang-tidy/tool/bsc/README.txt b/clang-tools-extra/clang-tidy/tool/bsc/README.txt new file mode 100644 index 000000000000..584b038edc6d --- /dev/null +++ b/clang-tools-extra/clang-tidy/tool/bsc/README.txt @@ -0,0 +1,200 @@ +//===----------------------------------------------------------------------===// +// BSC Tools repository +//===----------------------------------------------------------------------===// + +============================================================================ +Welcome to the repository of extra BSC Tools. This repository holds tools +that are developed as part of the BSC compiler`s one-stop retrofit tool. + +These tools can help uses to retrofit their C-code with some new features +of the BSC compiler easily, such as `fat-ptr` and 'source-to-source', and +the cost of this kind retrofit would be small. +============================================================================ + +For internal use, if you want to try it in the project source code, +not in the released version, you can try the following steps: + +1. Copy 'bsc-build.py' to $your-path/llvm-project/build/bin, and remove +the '.py' suffix. Then grant executable permission to it. + +Cmd: +''' + cp $your-path/llvm-project/clang-tools-extra/clang-tidy/tool/bsc/bsc-build.py $your-path/llvm-project/build/bin/bsc-build + chmod +x $your-path/llvm-project/build/bin/bsc-build +``` + + +2. Copy 'fake_clang.py' to $your-path/llvm-project/build/bin/fake_compiler/, +and remove the '.py' suffix. Then grant executable permission to it. + +Cmd: +``` + mkdir $your-path/llvm-project/build/bin/fake_compiler/ + cp $your-path/llvm-project/clang-tools-extra/clang-tidy/tool/bsc/fake_clang.py $your-path/llvm-project/build/bin/fake_compiler/clang + chmod +x $your-path/llvm-project/build/bin/fake_compiler/clang +``` + + +3. Run 'bsc-build' in $your-path/llvm-project/build/bin: + The options of bsc-build: + --file-path : + The path of the source code which to be retrofitted. If there are + more than one path, use ';' to separate them, without blank space. + You can use both absolute and relative paths. + e.g.: --file-path=./fat_ptr/test_fat.c + + --build-after-modify : + The origin command to build your project. Use semicolons to warp + them insidek, and it is ok to have blank space in it. If there are + more than one command, use '|' to separate them. + e.g.: ---build-after-modify='which clang | clang ./fat_ptr/test_fat.c' + +Cmd: +``` + $your-path/llvm-project/build/bin/bsc-build --file-path=$source_file_path --build-after-modify='origin_build_cmd_1 | origin_build_cmd_2' +``` + + +===================== Demos ===================== + +===----- test_fat.h -----=== +``` +int Aa = 1; + +struct S { + int arr[3]; +}; + +struct A { + struct S s; + int a; +}; + +struct B { + int b; +}; + +void test_1(); +void test_2(int *i1, struct S* s1); + +void char_test(char *c1) {} +``` + + +===----- test_fat.c -----=== +``` +#include "test_fat.h" +#include + +typedef int* intp; // typedef int* fat intp +typedef struct S* spt; // typedef struct S* fat spt + +typedef int in; // ignore +intp ip; // ignore +spt sp; // ignore + +extern int GlobalVar; // ignore +extern int *GlobalPtr; // ignore +extern void greet(); // ignore + +int p = 1; +float f = 1.5; + +const int *p0; // const int *fat p0 +int * const p1 = &p; // int * const fat p1 + +int *p2; // int *fat p2 +int *p3 = &p; // int *fat p3 = &fat p +int *p4[5]; // int *fat p4[] + +intp p5; // ignore +intp p6[5]; // ignore +spt sp7[5]; // ignore + +float *f1; // float *fat f1 +float *f2 = &f; // float *fat f2 = &fat f + +int *p7 = (int*)&f; // int *fat p7 = (int*fat )&fat f + +char *c1; // char *fat c1 +char *c2 = "c"; // char *fat c2 = "c" todo: char *fat c2 = (char *fat )"c" + +in Arr0[3]; // CHECKED +int Arr1[3]; // CHECKED +int Arr2[3] = {}; // CHECKED +int Arr3[3] = { 10, 20, 30 }; // CHECKED + +// 搞一个缓存,避免多次遍历相同类型的结构体 +struct S s1; // CHECKED +struct S s2 = {}; // CHECKED +struct S s3 = {.arr = {10, 10, 10}}; // CHECKED + +struct A a1; // CHECKED +struct A a2 = {}; // CHECKED +struct A a3 = {.a = 1}; // CHECKED + +struct B b1; // ignore +struct B b2 = {}; // ignore +struct B b3 = {.b = 1}; // ignore + +struct S* sp1 = &s1; // struct S* fat sp1 = &fat s1 +struct A* ap1 = &a1; // struct A* fat ap1 = &fat a1 + +void test_2(int *i1, struct S *s1) {} // void test_2(int *fat i1, struct S *fat s1) + +int* test_3(intp i2) {} // int*fat test_3(intp i2) + +intp test_4(int a1) { + return &a1; // return &fat a1; +} + +int test_5() { // ignore + return 32; +} + +int main() { + + typedef float* flop; // typedef float* fat flop + + static struct A a4; // CHECKED + static struct A a5 = {}; // CHECKED + static struct A a6 = {.a = 1}; // CHECKED + + int a = 1; + int *P1 = &a; // int *fat P1 = &fat a + + int B = 10; + int *P2 = &B; // int *fat P2 = &fat B + + int *P3 = (int *)malloc(sizeof(int)); // int *fat P3 = checked_malloc(sizeof(int)) + P3 = (int *)malloc(sizeof(int)); // P3 = checked_malloc(sizeof(int)) + + float *P4 = (float *)malloc(sizeof(float)); // float *fat P4 = checked_malloc(sizeof(float)) + struct S *P5 = (struct S *)malloc(sizeof(struct S)); // struct S *fat P5 = checked_malloc(sizeof(struct S)) + + int *P6 = (int *)malloc(32); // int *fat P6 = checked_malloc(32) + unsigned aa = 32; + int *P7 = (int *)malloc(aa); // int *fat P7 = checked_malloc(aa) + int *P8 = (int *)malloc(test_5()); // int *fat P8 = checked_malloc(test_5()) + + int *P9 = (int *)malloc(sizeof(int)); // int *fat P9 = (int *fat )checked_malloc(sizeof(int)) + + intp P10 = (int *)malloc(aa); // intp P10 = checked_malloc(aa) + + int *P11; // int* fat P11 + P11 = (int *)&aa; // P11 = &fat aa + spt P12; + P12 = &s1; // P12 = &fat a1 + + + free(P3); // checked_free(P3) + free((void *)P4); // checked_free((void *fat)P4) + free(P10); // checked_free(P10) + free(test_3(P11)); // checked_free(test_3(P11)) + free(test_4(aa)); // checked_free(test_4(aa)) + free(P5); // checked_free(P5) + + return 0; +} + +``` \ No newline at end of file diff --git a/clang-tools-extra/clang-tidy/tool/bsc/bsc-build.py b/clang-tools-extra/clang-tidy/tool/bsc/bsc-build.py new file mode 100644 index 000000000000..822a217f5309 --- /dev/null +++ b/clang-tools-extra/clang-tidy/tool/bsc/bsc-build.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python3 + +import sys +import os +import argparse +import subprocess + +first_create_cfg = False +bsc_build_path = os.path.dirname(os.path.abspath(__file__)) +header_list = [] +h_modify_list = [] + +def excute_command(cmd: str, cmd_name: str = None): + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True) + stdout_c, stderr_c = proc.communicate() + if cmd_name: + print(" ===== " + cmd_name + " Return Code: ", proc.returncode , " ===== ") + return proc.returncode + +def excute_cmd_list(cmd_list: list, env: dict = None): + for cmd in cmd_list: + cmd_list = [item for item in cmd.split(" ") if item.strip()] + if env: + proc_modify = subprocess.Popen( + cmd_list, + env=env + ) + proc_modify.wait() + else: + proc_modify = subprocess.Popen( + cmd_list + ) + proc_modify.wait() + pass + +def gather_top_levels(source_path: str, cfg_path: str): + global bsc_build_path + global header_list + global h_modify_list + + command_c = ( + "find " + source_path + " -type f -name '*.c' " + + " -exec " + bsc_build_path + "/clang-tidy " + + "--no-clang-diagnostic --cfg-path=" + cfg_path + + " -checks='bsc-fat-ptr-collecter' $file {} \;" + ) + excute_command(command_c, "Proc_c") + + command_h = ( + "find " + source_path + " -type f -name '*.h' " + + " -exec " + bsc_build_path + "/clang-tidy " + + "--no-clang-diagnostic --cfg-path=" + cfg_path + + " -checks='bsc-fat-ptr-collecter' $file {} \;" + ) + excute_command(command_h, "Proc_h") + + + command_h_modify = ( + "find " + source_path + " -type f -name '*.h' " + + " -exec " + bsc_build_path + "/clang-tidy " + + "--fix-errors --config-file==" + cfg_path + + " $file {} \;" + ) + h_modify_list.append(command_h_modify) + find_h = ( + "find " + source_path + " -type f -name '*.h' " + ) + proc = subprocess.Popen(find_h, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True) + stdout_c, stderr_c = proc.communicate() + header_list += stdout_c.split("\n")[:-1] + + command_cbs = ( + "find " + source_path + " -type f -name '*.cbs' " + + " -exec " + bsc_build_path + "/clang-tidy " + + "--no-clang-diagnostic --cfg-path=" + cfg_path + + " -checks='bsc-fat-ptr-collecter' $file {} \;" + ) + excute_command(command_cbs, "Proc_cbs") + + command_hbs = ( + "find " + source_path + " -type f -name '*.hbs' " + + " -exec " + bsc_build_path + "/clang-tidy " + + "--no-clang-diagnostic --cfg-path=" + cfg_path + + " -checks='bsc-fat-ptr-collecter' $file {} \;" + ) + excute_command(command_hbs, "Proc_hbs") + +def backup_source_code(source_path: str): + command_backup = ("cp -r " + source_path + " " + source_path + "_backup") + excute_command(command_backup, "Proc_backup") + +def backup_compiler_and_replace(fake_compiler: str): + default_clang = "/usr/bin/clang" + if os.path.exists(default_clang): + clang_backup = "sudo cp -a " + default_clang + " " + default_clang + "_backup" + isbackup = excute_command(clang_backup, "Proc_clang_backup") + + if isbackup==0: + clang_replace = "sudo ln -snf " + fake_compiler + "/clang " + default_clang + excute_command(clang_replace, "Proc_clang_replace") + else: + print(" ===== Failed to backup " + default_clang + " ===== ") + + pass + +def recover_compiler(): + clang_backup = "/usr/bin/clang_backup" + if os.path.exists(clang_backup): + clang_clean = "sudo rm /usr/bin/clang" + excute_command(clang_clean, "Proc_clang_clean") + + clang_recover = "sudo mv -f /usr/bin/clang_backup /usr/bin/clang" + excute_command(clang_recover, "Proc_clang_recover") + +def preparecfg(file_path: str): + global first_create_cfg + global bsc_build_path + cfg_file = bsc_build_path + "/fat_ptr.cfg" + if not first_create_cfg: + content = ( 'Checks: -*, bsc-fat-ptr-transformer\n' + 'CheckOptions:\n - key: ' + 'bsc-fat-ptr-transformer.TopLevels\n' + ' value: "0') + with open(cfg_file, 'w') as file: + file.write(content) + first_create_cfg = True + + paths = file_path.split(";") + for path in paths: + abs_source_path = os.path.abspath(path) + backup_source_code(abs_source_path) + gather_top_levels(abs_source_path, cfg_file) + + with open(cfg_file, 'a') as file: + file.write('"') + print(" =========================== Prepare fat_ptr.cfg done =========================== ") + +def main(): + parser = argparse.ArgumentParser(description='Get the path of source code files.') + parser.add_argument('--file-path', type=str, default=None, dest='file_path', + help='Specify the path of your source code, use ";" to split them if more than one.') + parser.add_argument('--fat-ptr', action='store_true', + dest='fat_ptr', help='Active fat ptr modification.') + parser.add_argument('--translate-to-c', action='store_true', + dest='rewrite', help='Rewrite the modified source code to C code.') + parser.add_argument('--build-after-modify', type=str, default=None, dest='build_after_modify', + help='Build the program by the origin building command after modifination.\n If there are' + ' more than one command, use "|" to split them. e.g.: --cmake build xxx -xxx | make xxx') + parser.add_argument('--h', action='store_true', help='show the information of the options') + args = parser.parse_args() + + if not args.file_path: + sys.stderr.write(f"Error: file path is None. Use '-file-path=xxx' to indicate it\n") + return + + preparecfg(args.file_path) + + if args.build_after_modify: + global bsc_build_path + cmds = args.build_after_modify.split("|") + + if args.fat_ptr: + global header_list + header_dict = {} + for header in header_list: + header_path = os.path.dirname(os.path.abspath(header)) + header_dict[header] = header_path + + print(" =========================== Active fat ptr modify. =========================== ") + + fakecompiler_path = bsc_build_path + "/fake_compiler" + env = os.environ.copy() + env["PATH"] = fakecompiler_path + os.pathsep + env["PATH"] + if "CC" in os.environ: + env["CC"] = fakecompiler_path + os.pathsep + env["CC"] + else: + env["CC"] = fakecompiler_path + + if "CXX" in os.environ: + env["CXX"] = fakecompiler_path + os.pathsep + env["CXX"] + else: + env["CXX"] = fakecompiler_path + + # # Modify headers + # # FIXME: We modify all header now, still need to complete the further logic, to modify the headers that only been used. + # # maybe not, it seems when we modify .c, the used .h will be modified too, need check again. + # excute_cmd_list(h_modify_list) + + if args.rewrite: + print(" =========================== Active source to source after fat-ptr modify. =========================== ") + env["REWRITE"] = "Enable" + # # FIXME: transform all file from .c/.h to .cbs/.hbs, then we can rewrite + # for file, path in header_dict.items(): + # cmd = ( + # bsc_build_path + # + "/clang -x bsc " + # + "-rewrtie-bsc " + # + file + " -o " + path + # ) + # excute_command(cmd) + + # # FIXME: complete /usr/bin/cc situation. + # backup_compiler_and_replace(fakecompiler_path) + + excute_cmd_list(cmds, env) + + # # FIXME: complete /usr/bin/cc situation. + # recover_compiler() + pass + + if args.rewrite and not args.fat_ptr: + # # FIXME: complete or delete this situation. + pass + + + # excute_cmd_list(cmds) + + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/clang-tools-extra/clang-tidy/tool/bsc/fake_clang.py b/clang-tools-extra/clang-tidy/tool/bsc/fake_clang.py new file mode 100644 index 000000000000..4dba453f62b5 --- /dev/null +++ b/clang-tools-extra/clang-tidy/tool/bsc/fake_clang.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 + +import sys +import os +import re +import argparse +import subprocess + + +def get_clang_tidy(): + clang_tidy_path = None + current_file = os.path.abspath(__file__) + if (os.path.islink(current_file)): + clang_tidy_path = os.path.dirname(os.readlink(current_file)) + "/../" + else: + clang_tidy_path = os.path.dirname(current_file) + "/../" + + return clang_tidy_path + +def find_matching_strings(pattern, strings): + matches = [s for s in strings if pattern.match(s)] + return matches + +def find_matching_includes(strings): + pattern = re.compile(r'\-I.*?') + matches = [s for s in strings if pattern.match(s)] + return matches + +def transform_c_file(cfile, includes, clang_tidy_path): + if (clang_tidy_path): + command_c = ( + clang_tidy_path + "clang-tidy " + "--fix-errors --config-file=" + + clang_tidy_path + "fat_ptr.cfg " + + cfile + " -header-filter=.* " + ) + if includes: + command_c += "-- " + for include in includes: + command_c = command_c + include + " " + pass + + proc_c = subprocess.Popen( + command_c, text=True, shell=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + + stdout_c, stderr_c = proc_c.communicate() + print("Proc_modify Return Code:", proc_c.returncode) + pass + +def rewrite_c_file(cfile, includes, clang_tidy_path): + if (clang_tidy_path): + cmd = ( + clang_tidy_path + "clang -x" + " bsc -rewrite-bsc " + cfile + ) + if includes: + for include in includes: + cmd = cmd + " " + include + pass + + proc_c = subprocess.Popen( + cmd, text=True, shell=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + + stdout_c, stderr_c = proc_c.communicate() + print("Proc_rewrite Return Code:", proc_c.returncode, ", " + cfile) + pass + pass + +def main(): + if len(sys.argv) > 1: + pattern_c = re.compile(r'.*?\.c$') + cfile = find_matching_strings(pattern_c, sys.argv) + + pattern_i = re.compile(r'\-I.*?') + includes = find_matching_strings(pattern_i, sys.argv) + + clang_tidy_path = get_clang_tidy() + if (cfile): + transform_c_file(cfile[0], includes, clang_tidy_path) + + env_rewrite = os.environ.get("REWRITE") + if env_rewrite and env_rewrite == "Enable": + rewrite_c_file(cfile[0], includes, clang_tidy_path) + else: + print("No command line arguments provided.") + + +if __name__ == "__main__": + main() diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 7de001b406b8..67881817f449 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -159,6 +159,21 @@ New checks FIXME: add release notes. +- New :doc:`bsc-fat-ptr + ` check. + + FIXME: add release notes. + +- New :doc:`bsc-fat-ptr-collecter + ` check. + + FIXME: add release notes. + +- New :doc:`bsc-fat-ptr-transformer + ` check. + + FIXME: add release notes. + - New :doc:`bugprone-shared-ptr-array-mismatch ` check. Finds initializations of C++ shared pointers to non-array type that are initialized with an array. diff --git a/clang-tools-extra/docs/clang-tidy/checks/bsc/fat-ptr-collecter.rst b/clang-tools-extra/docs/clang-tidy/checks/bsc/fat-ptr-collecter.rst new file mode 100644 index 000000000000..80cdea7bd617 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/bsc/fat-ptr-collecter.rst @@ -0,0 +1,6 @@ +.. title:: clang-tidy - bsc-fat-ptr-collecter + +bsc-fat-ptr-collecter +===================== + +FIXME: Describe what patterns does the check detect and why. Give examples. diff --git a/clang-tools-extra/docs/clang-tidy/checks/bsc/fat-ptr-transformer.rst b/clang-tools-extra/docs/clang-tidy/checks/bsc/fat-ptr-transformer.rst new file mode 100644 index 000000000000..37478d0760d3 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/bsc/fat-ptr-transformer.rst @@ -0,0 +1,6 @@ +.. title:: clang-tidy - bsc-fat-ptr-transformer + +bsc-fat-ptr-transformer +======================= + +FIXME: Describe what patterns does the check detect and why. Give examples. diff --git a/clang-tools-extra/docs/clang-tidy/checks/bsc/fat-ptr.rst b/clang-tools-extra/docs/clang-tidy/checks/bsc/fat-ptr.rst new file mode 100644 index 000000000000..f0f92143cdbf --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/bsc/fat-ptr.rst @@ -0,0 +1,6 @@ +.. title:: clang-tidy - bsc-fat-ptr + +bsc-fat-ptr +=========== + +FIXME: Describe what patterns does the check detect and why. Give examples. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index df2aedc61575..e51ef1bcbfd6 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -77,9 +77,12 @@ Clang-Tidy Checks `android-cloexec-socket `_, "Yes" `android-comparison-in-temp-failure-retry `_, `boost-use-to-string `_, "Yes" - `bsc-access-specific-type `_, "Yes" + `bsc-access-specific-type `_, `bsc-add-new-field `_, "Yes" `bsc-explicit-cast `_, + `bsc-fat-ptr-collecter `_, + `bsc-fat-ptr-transformer `_, "Yes" + `bsc-fat-ptr `_, "Yes" `bugprone-argument-comment `_, "Yes" `bugprone-assert-side-effect `_, `bugprone-assignment-in-if-condition `_, diff --git a/clang-tools-extra/test/clang-tidy/checkers/bsc/fat-ptr-collecter.cpp b/clang-tools-extra/test/clang-tidy/checkers/bsc/fat-ptr-collecter.cpp new file mode 100644 index 000000000000..6c9fb682cacb --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bsc/fat-ptr-collecter.cpp @@ -0,0 +1,14 @@ +// RUN: %check_clang_tidy %s bsc-fat-ptr-collecter %t + +// FIXME: Add something that triggers the check here. +void f(); +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'f' is insufficiently awesome [bsc-fat-ptr-collecter] + +// FIXME: Verify the applied fix. +// * Make the CHECK patterns specific enough and try to make verified lines +// unique to avoid incorrect matches. +// * Use {{}} for regular expressions. +// CHECK-FIXES: {{^}}void awesome_f();{{$}} + +// FIXME: Add something that doesn't trigger the check here. +void awesome_f2(); diff --git a/clang-tools-extra/test/clang-tidy/checkers/bsc/fat-ptr-transformer.cpp b/clang-tools-extra/test/clang-tidy/checkers/bsc/fat-ptr-transformer.cpp new file mode 100644 index 000000000000..a1212205950f --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bsc/fat-ptr-transformer.cpp @@ -0,0 +1,14 @@ +// RUN: %check_clang_tidy %s bsc-fat-ptr-transformer %t + +// FIXME: Add something that triggers the check here. +void f(); +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'f' is insufficiently awesome [bsc-fat-ptr-transformer] + +// FIXME: Verify the applied fix. +// * Make the CHECK patterns specific enough and try to make verified lines +// unique to avoid incorrect matches. +// * Use {{}} for regular expressions. +// CHECK-FIXES: {{^}}void awesome_f();{{$}} + +// FIXME: Add something that doesn't trigger the check here. +void awesome_f2(); diff --git a/clang-tools-extra/test/clang-tidy/checkers/bsc/fat-ptr.cpp b/clang-tools-extra/test/clang-tidy/checkers/bsc/fat-ptr.cpp new file mode 100644 index 000000000000..9f34153f54d3 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bsc/fat-ptr.cpp @@ -0,0 +1,14 @@ +// RUN: %check_clang_tidy %s bsc-fat-ptr %t + +// FIXME: Add something that triggers the check here. +void f(); +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'f' is insufficiently awesome [bsc-fat-ptr] + +// FIXME: Verify the applied fix. +// * Make the CHECK patterns specific enough and try to make verified lines +// unique to avoid incorrect matches. +// * Use {{}} for regular expressions. +// CHECK-FIXES: {{^}}void awesome_f();{{$}} + +// FIXME: Add something that doesn't trigger the check here. +void awesome_f2(); -- Gitee From 109f5ff95ace69d89db26c55793991a3b8eec27c Mon Sep 17 00:00:00 2001 From: Aperzer Date: Thu, 27 Feb 2025 21:24:52 +0800 Subject: [PATCH 2/2] [fat ptr tool] Adjust some logic of checkers and tools 1. Adjust the modification of 'malloc' and 'free'; 2. Fix some bugs, mainly while building or rewriting in bsc-build; 3. Adjust '&' modify in transformer checker; 4. Delete useless code and checker, and annotate the files. --- clang-tools-extra/clang-tidy/ClangTidy.cpp | 8 - .../clang-tidy/bsc/BSCTidyModule.cpp | 3 - .../clang-tidy/bsc/CMakeLists.txt | 1 - .../clang-tidy/bsc/ExplicitCastCheck.h | 5 +- .../clang-tidy/bsc/FatPtrCheck.cpp | 37 --- .../clang-tidy/bsc/FatPtrCheck.h | 48 ---- .../clang-tidy/bsc/FatPtrCollecterCheck.cpp | 58 +++-- .../clang-tidy/bsc/FatPtrCollecterCheck.h | 1 + .../clang-tidy/bsc/FatPtrTransformerCheck.cpp | 232 +++++++++++------- .../clang-tidy/bsc/FatPtrTransformerCheck.h | 20 +- .../clang-tidy/tool/bsc/bsc-build.py | 42 ++-- .../clang-tidy/tool/bsc/fake_clang.py | 62 +++-- clang-tools-extra/docs/ReleaseNotes.rst | 5 - .../docs/clang-tidy/checks/bsc/fat-ptr.rst | 6 - .../docs/clang-tidy/checks/list.rst | 1 - .../test/clang-tidy/checkers/bsc/fat-ptr.cpp | 14 -- 16 files changed, 253 insertions(+), 290 deletions(-) delete mode 100644 clang-tools-extra/clang-tidy/bsc/FatPtrCheck.cpp delete mode 100644 clang-tools-extra/clang-tidy/bsc/FatPtrCheck.h delete mode 100644 clang-tools-extra/docs/clang-tidy/checks/bsc/fat-ptr.rst delete mode 100644 clang-tools-extra/test/clang-tidy/checkers/bsc/fat-ptr.cpp diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp index 5d93e17ce31a..5b6111610c9f 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -606,14 +606,6 @@ void handleErrors(llvm::ArrayRef Errors, // Situations if users want to disable clang diagnostic checker. std::string CheckName = Error.DiagnosticName; if (IsNoClangDiagnostic) { - // std::string CastChecker = "bsc-explicit-cast"; - // std::string AccessChecker = "bsc-access-specific-type"; - // if (CheckName.find(CastChecker) != std::string::npos || - // CheckName.find(AccessChecker) != std::string::npos) { - // llvm::outs() << "--------- flag begin ---------\n"; - // Reporter.reportDiagnostic(Error); - // llvm::outs() << "--------- flag end ---------\n"; - // } std::string BSCChecker = "bsc-"; if (CheckName.find(BSCChecker) != std::string::npos) Reporter.reportDiagnostic(Error); diff --git a/clang-tools-extra/clang-tidy/bsc/BSCTidyModule.cpp b/clang-tools-extra/clang-tidy/bsc/BSCTidyModule.cpp index eefdba0bf4f8..8e2016426fef 100644 --- a/clang-tools-extra/clang-tidy/bsc/BSCTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bsc/BSCTidyModule.cpp @@ -12,7 +12,6 @@ #include "AccessSpecificTypeCheck.h" #include "AddNewFieldCheck.h" #include "ExplicitCastCheck.h" -#include "FatPtrCheck.h" #include "FatPtrCollecterCheck.h" #include "FatPtrTransformerCheck.h" @@ -29,8 +28,6 @@ public: "bsc-add-new-field"); CheckFactories.registerCheck( "bsc-explicit-cast"); - CheckFactories.registerCheck( - "bsc-fat-ptr"); CheckFactories.registerCheck( "bsc-fat-ptr-collecter"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/bsc/CMakeLists.txt b/clang-tools-extra/clang-tidy/bsc/CMakeLists.txt index 7c35b3fe2efe..1e1d5c3a1ff2 100644 --- a/clang-tools-extra/clang-tidy/bsc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bsc/CMakeLists.txt @@ -9,7 +9,6 @@ add_clang_library(clangTidyBscModule AddNewFieldCheck.cpp BSCTidyModule.cpp ExplicitCastCheck.cpp - FatPtrCheck.cpp FatPtrCollecterCheck.cpp FatPtrTransformerCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bsc/ExplicitCastCheck.h b/clang-tools-extra/clang-tidy/bsc/ExplicitCastCheck.h index 0ba11401a406..58cda5fe869c 100644 --- a/clang-tools-extra/clang-tidy/bsc/ExplicitCastCheck.h +++ b/clang-tools-extra/clang-tidy/bsc/ExplicitCastCheck.h @@ -15,10 +15,7 @@ namespace clang { namespace tidy { namespace bsc { -/// FIXME: Write a short description. -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/bsc/explicit-cast.html +// Collect information from the specified file for bsc fat-ptr transformer. class ExplicitCastCheck : public ClangTidyCheck { public: ExplicitCastCheck(StringRef Name, ClangTidyContext *Context) diff --git a/clang-tools-extra/clang-tidy/bsc/FatPtrCheck.cpp b/clang-tools-extra/clang-tidy/bsc/FatPtrCheck.cpp deleted file mode 100644 index 5d27c18884cf..000000000000 --- a/clang-tools-extra/clang-tidy/bsc/FatPtrCheck.cpp +++ /dev/null @@ -1,37 +0,0 @@ -//===--- FatPtrCheck.cpp - clang-tidy -------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "FatPtrCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace bsc { - -void FatPtrCheck::registerMatchers(MatchFinder *Finder) { - // FIXME: Add matchers. - Finder->addMatcher(functionDecl().bind("x"), this); -} - -void FatPtrCheck::check(const MatchFinder::MatchResult &Result) { - // FIXME: Add callback implementation. - const auto *MatchedDecl = Result.Nodes.getNodeAs("x"); - if (!MatchedDecl->getIdentifier() || MatchedDecl->getName().startswith("awesome_")) - return; - diag(MatchedDecl->getLocation(), "function %0 is insufficiently awesome") - << MatchedDecl; - diag(MatchedDecl->getLocation(), "insert 'awesome'", DiagnosticIDs::Note) - << FixItHint::CreateInsertion(MatchedDecl->getLocation(), "awesome_"); -} - -} // namespace bsc -} // namespace tidy -} // namespace clang diff --git a/clang-tools-extra/clang-tidy/bsc/FatPtrCheck.h b/clang-tools-extra/clang-tidy/bsc/FatPtrCheck.h deleted file mode 100644 index 06a38a3a2fbf..000000000000 --- a/clang-tools-extra/clang-tidy/bsc/FatPtrCheck.h +++ /dev/null @@ -1,48 +0,0 @@ -//===--- FatPtrCheck.h - clang-tidy -----------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BSC_FATPTRCHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BSC_FATPTRCHECK_H - -#include "../ClangTidyCheck.h" - -namespace clang { -namespace tidy { -namespace bsc { - -/// FIXME: Write a short description. -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/bsc/fat-ptr.html -class FatPtrCheck : public ClangTidyCheck { -public: - FatPtrCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context), - TopLevelFunctionList(Options.get("TopLevelFunctions", "TEMP_FAILURE_RETRY")), - TopLevelVarList(Options.get("TopLevelVars", "TEMP_FAILURE_RETRY")) { - StringRef(TopLevelFunctionList).split(TopLevelFunctions, ",", -1, false); - StringRef(TopLevelVarList).split(TopLevelVars, ",", -1, false); - } - void storeOptions(ClangTidyOptions::OptionMap &Opts) { - Options.store(Opts, "TopLevelFunctions", TopLevelFunctionList); - Options.store(Opts, "TopLevelVars", TopLevelVarList); - } - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -private: - const StringRef TopLevelFunctionList; - SmallVector TopLevelFunctions; - const StringRef TopLevelVarList; - SmallVector TopLevelVars; -}; - -} // namespace bsc -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BSC_FATPTRCHECK_H diff --git a/clang-tools-extra/clang-tidy/bsc/FatPtrCollecterCheck.cpp b/clang-tools-extra/clang-tidy/bsc/FatPtrCollecterCheck.cpp index bc9e4ba08123..ac7691a4aa17 100644 --- a/clang-tools-extra/clang-tidy/bsc/FatPtrCollecterCheck.cpp +++ b/clang-tools-extra/clang-tidy/bsc/FatPtrCollecterCheck.cpp @@ -6,19 +6,17 @@ // //===----------------------------------------------------------------------===// -#include -#include #include "FatPtrCollecterCheck.h" #include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/AST/BSC/DeclBSC.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Tooling/CommonOptionsParser.h" +#include +#include -static llvm::cl::opt CFGPath( - "cfg-path", - llvm::cl::desc( - "Indicate the path of cfg file."), - llvm::cl::init("empty"), llvm::cl::Hidden); +static llvm::cl::opt + CFGPath("cfg-path", llvm::cl::desc("Indicate the path of cfg file."), + llvm::cl::init("empty"), llvm::cl::Hidden); using namespace clang::ast_matchers; @@ -26,16 +24,20 @@ namespace clang { namespace tidy { namespace bsc { +// Get the name of Decl, and save it into the '.cfg' file. static inline int SaveInCFG(const NamedDecl *ND) { if (CFGPath == "Empty") { - std::cerr << "No cfg path received, please check input parameter `--cfg-path`" << std::endl; + std::cerr + << "No cfg path received, please check input parameter `--cfg-path`" + << std::endl; return 0; } std::ofstream OutFile; OutFile.open(CFGPath, std::ios::out | std::ios::app); - if (!OutFile.is_open()) { - std::cerr << "can not open fat_ptr.cfg, fail to save toplevel items." << std::endl; + if (!OutFile.is_open()) { + std::cerr << "can not open fat_ptr.cfg, fail to save toplevel items." + << std::endl; return 0; } @@ -46,14 +48,14 @@ static inline int SaveInCFG(const NamedDecl *ND) { } // Check whether this Decl comes from Mainfile or header file. -static inline bool CheckFileId(const clang::SourceManager* SM, - FileID MainFileID, const NamedDecl *ND){ +static inline bool CheckFileId(const clang::SourceManager *SM, + FileID MainFileID, const NamedDecl *ND) { if (MainFileID.isInvalid()) { MainFileID = SM->getMainFileID(); if (MainFileID.isInvalid()) return 0; } - + FileID LocationID = SM->getFileID(SM->getSpellingLoc(ND->getLocation())); if (LocationID.isValid()) { if (MainFileID == LocationID) @@ -68,28 +70,34 @@ void FatPtrCollecterCheck::registerMatchers(MatchFinder *Finder) { auto AT = hasUnqualifiedDesugaredType(arrayType()); auto RT = hasUnqualifiedDesugaredType(recordType()); - Finder->addMatcher(functionDecl(hasParent(translationUnitDecl()), hasBody(stmt())).bind("TopLevelFuncDecl"), this); - Finder->addMatcher(varDecl(hasGlobalStorage(), - anyOf(hasType(PT), hasType(AT), hasType(RT))).bind("GlobalVar"), this); + Finder->addMatcher( + functionDecl(hasParent(translationUnitDecl()), hasBody(stmt())) + .bind("TopLevelFuncDecl"), + this); + Finder->addMatcher( + varDecl(hasGlobalStorage(), anyOf(hasType(PT), hasType(AT), hasType(RT))) + .bind("GlobalVar"), + this); } void FatPtrCollecterCheck::check(const MatchFinder::MatchResult &Result) { - const auto *TopLevelFuncDecl = Result.Nodes.getNodeAs("TopLevelFuncDecl"); + const auto *TopLevelFuncDecl = + Result.Nodes.getNodeAs("TopLevelFuncDecl"); const auto *GlobalVar = Result.Nodes.getNodeAs("GlobalVar"); - if (TopLevelFuncDecl){ + if (TopLevelFuncDecl) { const auto *BSCMD = dyn_cast_or_null(TopLevelFuncDecl); // Exclude 'Member Function' scenarios. if (!BSCMD) { // Exclude 'Extern' scenarios. if (TopLevelFuncDecl->getStorageClass() != SC_Extern) { - if (!CheckFileId(Result.SourceManager, MainFileID, TopLevelFuncDecl)) + if (!CheckFileId(Result.SourceManager, MainFileID, TopLevelFuncDecl)) return; // Save top-level function-name in cfg file. if (!SaveInCFG(TopLevelFuncDecl)) diag(TopLevelFuncDecl->getLocation(), - "Failed to save TopLevelFuncDecl: %0", - DiagnosticIDs::Error) << TopLevelFuncDecl; + "Failed to save TopLevelFuncDecl: %0", DiagnosticIDs::Error) + << TopLevelFuncDecl; } } } @@ -101,9 +109,9 @@ void FatPtrCollecterCheck::check(const MatchFinder::MatchResult &Result) { return; // Save top-level var-name in cfg file. if (!SaveInCFG(GlobalVar)) - diag(GlobalVar->getLocation(), - "Failed to save GlobalVar: %0", - DiagnosticIDs::Error) << GlobalVar; + diag(GlobalVar->getLocation(), "Failed to save GlobalVar: %0", + DiagnosticIDs::Error) + << GlobalVar; } } } diff --git a/clang-tools-extra/clang-tidy/bsc/FatPtrCollecterCheck.h b/clang-tools-extra/clang-tidy/bsc/FatPtrCollecterCheck.h index ccf9b797395b..65b55aec5e62 100644 --- a/clang-tools-extra/clang-tidy/bsc/FatPtrCollecterCheck.h +++ b/clang-tools-extra/clang-tidy/bsc/FatPtrCollecterCheck.h @@ -25,6 +25,7 @@ public: : ClangTidyCheck(Name, Context) {} void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + private: FileID MainFileID; }; diff --git a/clang-tools-extra/clang-tidy/bsc/FatPtrTransformerCheck.cpp b/clang-tools-extra/clang-tidy/bsc/FatPtrTransformerCheck.cpp index 05cea3278f2f..a989e7e46882 100644 --- a/clang-tools-extra/clang-tidy/bsc/FatPtrTransformerCheck.cpp +++ b/clang-tools-extra/clang-tidy/bsc/FatPtrTransformerCheck.cpp @@ -17,17 +17,23 @@ namespace tidy { namespace bsc { void FatPtrTransformerCheck::AddFat(SourceLocation Loc) { - diag(Loc, "Add 'fat' token here",DiagnosticIDs::Warning) + diag(Loc, "Add 'fat' token here", DiagnosticIDs::Warning) << FixItHint::CreateInsertion(Loc, "fat "); } void FatPtrTransformerCheck::AddChecked(SourceLocation Loc) { - diag(Loc, "Add 'CHECKED' token here",DiagnosticIDs::Warning) + diag(Loc, "Add 'CHECKED' token here", DiagnosticIDs::Warning) << FixItHint::CreateInsertion(Loc, "CHECKED "); } +// When we use a typedef pointer type to declare a var, we won`t +// add `fat` token before it. +// e.g.: +// typedef int* ip; // add `fat` here -> typedef int* fat ip; +// ip p1 = &p; // not here +// So we will pass the vars which are declared by these kinds. void FatPtrTransformerCheck::CheckTypedefAndSetFat(const ValueDecl *D, - SourceManager *SM) { + SourceManager *SM) { QualType DType = D->getType(); if (!DType.getTypePtr()->getAs()) { AddHeader(SM); @@ -65,33 +71,37 @@ std::string FatPtrTransformerCheck::GetTypeName(const Expr *Arg) { } } +// Traverse a RecordDecl, to find out wheather the RecordDecl itself or +// it`s field (if the field is a record type) has an array-type field. +// When find a RecordDecl with array-type field, we will also store it +// into a buffer, so that we don`t need to traverse it next time. void FatPtrTransformerCheck::TraversalRecordDecl(RecordDecl *RD, bool *HasArrayField) { if (RD->isInvalidDecl()) return; - - for(FieldDecl* DeclField : RD->fields()) { - if (const auto *GRTY = dyn_cast_or_null - (DeclField->getType().getTypePtr())) { - if (const auto *RT = dyn_cast_or_null - (GRTY->getNamedType())) { + + for (FieldDecl *DeclField : RD->fields()) { + if (const auto *GRTY = dyn_cast_or_null( + DeclField->getType().getTypePtr())) { + if (const auto *RT = + dyn_cast_or_null(GRTY->getNamedType())) { if (FindInDeclList(HasArrayField, RT)) return; TraversalRecordDecl(RT->getDecl(), HasArrayField); } - } else if (const auto *RT = dyn_cast_or_null - (DeclField->getType().getTypePtr())) { + } else if (const auto *RT = dyn_cast_or_null( + DeclField->getType().getTypePtr())) { if (FindInDeclList(HasArrayField, RT)) - return; + return; TraversalRecordDecl(RT->getDecl(), HasArrayField); } - - if(*HasArrayField) { + + if (*HasArrayField) { DeclList.push_back(RD); return; } - - if(DeclField->getType()->isArrayType()) { + + if (DeclField->getType()->isArrayType()) { *HasArrayField = true; DeclList.push_back(RD); return; @@ -105,34 +115,48 @@ void FatPtrTransformerCheck::registerMatchers(MatchFinder *Finder) { auto RT = hasUnqualifiedDesugaredType(recordType()); for (auto TopLevelName : TopLevels) { - Finder->addMatcher(parmVarDecl(hasParent(functionDecl( - hasName(std::string(TopLevelName)))), - hasType(PT)).bind("PtParmVarDecl"), this); - Finder->addMatcher(functionDecl(hasParent(translationUnitDecl()), hasName(std::string(TopLevelName)), - returns(isAnyPointer())).bind("FuncDeclRtPt"), this); + returns(isAnyPointer())) + .bind("FuncDeclRtPt"), + this); Finder->addMatcher(callExpr(callee(functionDecl(hasName("malloc"))), - hasParent(castExpr().bind("MallocParent"))) - .bind("MallocCall"), this); - Finder->addMatcher(callExpr(callee(functionDecl(hasName("free")))).bind("FreecCall"), this); - - Finder->addMatcher(varDecl(hasGlobalStorage(), - hasName(std::string(TopLevelName)), - hasType(PT)).bind("GlobalPointerVar"), this); - Finder->addMatcher(varDecl(hasGlobalStorage(), - hasName(std::string(TopLevelName)), - allOf(hasType(AT), unless(hasType(PT)))).bind("GlobalArrayVar"), this); - Finder->addMatcher(varDecl(hasGlobalStorage(), - hasName(std::string(TopLevelName)), - hasType(RT)).bind("GlobalRecordVar"), this); - - Finder->addMatcher(varDecl(hasAncestor(functionDecl(hasName(std::string(TopLevelName)))), - hasLocalStorage(), hasType(PT)).bind("LocalPointerVar"), this); + hasParent(castExpr().bind("MallocParentCast"))) + .bind("MallocCallCast"), + this); + Finder->addMatcher( + callExpr(callee(functionDecl(hasName("malloc"))), hasParent(varDecl())) + .bind("MallocCallVar"), + this); + Finder->addMatcher( + callExpr(callee(functionDecl(hasName("free")))).bind("FreecCall"), + this); + + Finder->addMatcher(varDecl(hasGlobalStorage(), + hasName(std::string(TopLevelName)), hasType(PT)) + .bind("GlobalPointerVar"), + this); + Finder->addMatcher(varDecl(hasGlobalStorage(), + hasName(std::string(TopLevelName)), + allOf(hasType(AT), unless(hasType(PT)))) + .bind("GlobalArrayVar"), + this); + Finder->addMatcher(varDecl(hasGlobalStorage(), + hasName(std::string(TopLevelName)), hasType(RT)) + .bind("GlobalRecordVar"), + this); + + Finder->addMatcher( + varDecl(hasAncestor(functionDecl(hasName(std::string(TopLevelName)))), + hasLocalStorage(), hasType(PT)) + .bind("LocalPointerVar"), + this); Finder->addMatcher(typedefDecl(hasType(PT)).bind("TypedefPT"), this); - Finder->addMatcher(unaryOperator(hasType(PT), hasOperatorName("&")).bind("UnOpAddr"), this); + Finder->addMatcher( + unaryOperator(hasType(PT), hasOperatorName("&")).bind("UnOpAddr"), + this); Finder->addMatcher(cStyleCastExpr(hasType(PT)).bind("CCastExprPT"), this); } } @@ -141,86 +165,121 @@ void FatPtrTransformerCheck::check(const MatchFinder::MatchResult &Result) { if (MainFileID.isInvalid()) MainFileID = Result.SourceManager->getMainFileID(); - const auto *PtParmVarDecl = Result.Nodes.getNodeAs("PtParmVarDecl"); - const auto *FuncDeclRtPt = Result.Nodes.getNodeAs("FuncDeclRtPt"); + const auto *FuncDeclRtPt = + Result.Nodes.getNodeAs("FuncDeclRtPt"); - const auto *GlobalPointerVar = Result.Nodes.getNodeAs("GlobalPointerVar"); - const auto *GlobalArrayVar = Result.Nodes.getNodeAs("GlobalArrayVar"); - const auto *GlobalRecordVar = Result.Nodes.getNodeAs("GlobalRecordVar"); - const auto *LocalPointerVar = Result.Nodes.getNodeAs("LocalPointerVar"); + const auto *GlobalPointerVar = + Result.Nodes.getNodeAs("GlobalPointerVar"); + const auto *GlobalArrayVar = + Result.Nodes.getNodeAs("GlobalArrayVar"); + const auto *GlobalRecordVar = + Result.Nodes.getNodeAs("GlobalRecordVar"); + const auto *LocalPointerVar = + Result.Nodes.getNodeAs("LocalPointerVar"); const auto *TypedefPT = Result.Nodes.getNodeAs("TypedefPT"); const auto *UnOpAddr = Result.Nodes.getNodeAs("UnOpAddr"); - const auto *CCastExprPT = Result.Nodes.getNodeAs("CCastExprPT"); + const auto *CCastExprPT = + Result.Nodes.getNodeAs("CCastExprPT"); - const auto *MallocCall = Result.Nodes.getNodeAs("MallocCall"); - const auto *MallocParent = Result.Nodes.getNodeAs("MallocParent"); + const auto *MallocCallCast = + Result.Nodes.getNodeAs("MallocCallCast"); + const auto *MallocParentCast = + Result.Nodes.getNodeAs("MallocParentCast"); + + const auto *MallocCallVar = Result.Nodes.getNodeAs("MallocCallVar"); const auto *FreecCall = Result.Nodes.getNodeAs("FreecCall"); - + + // Find AddrOf symbol '&'. if (UnOpAddr) { if (UnOpAddr->getOpcode() == UnaryOperatorKind::UO_AddrOf) { AddHeader(Result.SourceManager); - AddFat(UnOpAddr->getEndLoc()); + AddFat(UnOpAddr->getBeginLoc().getLocWithOffset(1)); } } + // Find explicitly cast. if (CCastExprPT) { AddHeader(Result.SourceManager); AddFat(CCastExprPT->getRParenLoc()); } - if (PtParmVarDecl) { - diag(PtParmVarDecl->getBeginLoc(), "Find PtParmVarDecl here", DiagnosticIDs::Warning); - } - - if (MallocCall) { - if (MallocParent) { - if (const clang::Type *CT = dyn_cast(MallocParent->getType().getTypePtr())) { + // Find 'malloc()' call with 'non-void' type. + if (MallocCallCast) { + if (MallocParentCast) { + if (const clang::Type *CT = + dyn_cast(MallocParentCast->getType().getTypePtr())) { if (const PointerType *PT = CT->getAs()) { - std::string ReplaceStr = "checked_malloc<"; - ReplaceStr.append(PT->getPointeeType().getAsString()); - ReplaceStr.append(">"); - - SourceLocation BeginLoc = MallocCall->getExprLoc(); - SourceLocation EndLoc = MallocCall->getArg(0)->getExprLoc(); + std::string ReplaceStr; + if (MallocParentCast->getStmtClass() == Stmt::CStyleCastExprClass) { + ReplaceStr = "checked_malloc"; + } else { + ReplaceStr = "("; + ReplaceStr.append(PT->getPointeeType().getAsString()); + ReplaceStr.append(" *fat)checked_malloc"); + } + + SourceLocation BeginLoc = MallocCallCast->getExprLoc(); + SourceLocation EndLoc = MallocCallCast->getArg(0)->getExprLoc(); SourceRange SR = SourceRange(BeginLoc, EndLoc.getLocWithOffset(-2)); + diag(BeginLoc, "Find Malloc Call here", DiagnosticIDs::Warning) - << FixItHint::CreateReplacement(SR, ReplaceStr); + << FixItHint::CreateReplacement(SR, ReplaceStr); AddHeader(Result.SourceManager); } } } } + // Find 'malloc()' call with 'void *' type. + if (MallocCallVar) { + std::string ReplaceStr = "checked_malloc"; + + SourceLocation BeginLoc = MallocCallVar->getExprLoc(); + SourceLocation EndLoc = MallocCallVar->getArg(0)->getExprLoc(); + SourceRange SR = SourceRange(BeginLoc, EndLoc.getLocWithOffset(-2)); + + diag(BeginLoc, "Find Malloc Call here", DiagnosticIDs::Warning) + << FixItHint::CreateReplacement(SR, ReplaceStr); + AddHeader(Result.SourceManager); + } + + // Find 'free()' call. if (FreecCall) { - if (const CastExpr *Arg = dyn_cast_or_null(FreecCall->getArg(0))) { - if (const clang::Type *CT = dyn_cast(Arg->getSubExpr()->getType().getTypePtr())) { + if (const CastExpr *Arg = + dyn_cast_or_null(FreecCall->getArg(0))) { + if (const clang::Type *CT = dyn_cast( + Arg->getSubExpr()->getType().getTypePtr())) { if (const PointerType *PT = CT->getAs()) { - std::string ReplaceStr = "checked_free<"; - ReplaceStr.append(PT->getPointeeType().getAsString()); - ReplaceStr.append(">"); + std::string ReplaceStr = "checked_free("; + if (Arg->getStmtClass() != Stmt::CStyleCastExprClass) { + ReplaceStr.append("(void *fat)"); + } SourceLocation BeginLoc = FreecCall->getExprLoc(); SourceLocation EndLoc = FreecCall->getArg(0)->getExprLoc(); - SourceRange SR = SourceRange(BeginLoc, EndLoc.getLocWithOffset(-2)); + SourceRange SR = SourceRange(BeginLoc, EndLoc.getLocWithOffset(-1)); diag(BeginLoc, "Find Free Call here", DiagnosticIDs::Warning) - << FixItHint::CreateReplacement(SR, ReplaceStr); + << FixItHint::CreateReplacement(SR, ReplaceStr); AddHeader(Result.SourceManager); } } } } - if (GlobalArrayVar){ - if (const auto *CAT = dyn_cast_or_null - (GlobalArrayVar->getType().getTypePtr())) { + // Find array-type vars with global declaration. + if (GlobalArrayVar) { + if (const auto *CAT = dyn_cast_or_null( + GlobalArrayVar->getType().getTypePtr())) { AddHeader(Result.SourceManager); QualType VarType = CAT->getElementType(); - if (const TypedefType *TdefT = dyn_cast_or_null(VarType.getTypePtr())) { + if (const TypedefType *TdefT = + dyn_cast_or_null(VarType.getTypePtr())) { if (!TdefT->getAs()) AddChecked(GlobalArrayVar->getBeginLoc()); - } else if (const auto *PT = dyn_cast_or_null(VarType.getTypePtr())) { + } else if (const auto *PT = + dyn_cast_or_null(VarType.getTypePtr())) { AddFat(GlobalArrayVar->getLocation()); } else { AddChecked(GlobalArrayVar->getBeginLoc()); @@ -228,11 +287,12 @@ void FatPtrTransformerCheck::check(const MatchFinder::MatchResult &Result) { } } - if (GlobalRecordVar){ - if (const auto *GRTY = dyn_cast_or_null - (GlobalRecordVar->getType().getTypePtr())) { - if (const auto *RT = dyn_cast_or_null - (GRTY->getNamedType())) { + // Find record-type vars with global declaration. + if (GlobalRecordVar) { + if (const auto *GRTY = dyn_cast_or_null( + GlobalRecordVar->getType().getTypePtr())) { + if (const auto *RT = + dyn_cast_or_null(GRTY->getNamedType())) { bool HasArrayField = false; if (!FindInDeclList(&HasArrayField, RT)) TraversalRecordDecl(RT->getDecl(), &HasArrayField); @@ -245,19 +305,23 @@ void FatPtrTransformerCheck::check(const MatchFinder::MatchResult &Result) { } } + // Find pointer-type vars with global declaration. if (GlobalPointerVar) CheckTypedefAndSetFat(GlobalPointerVar, Result.SourceManager); - if (LocalPointerVar) + // Find pointer-type vars with local declaration. + if (LocalPointerVar) CheckTypedefAndSetFat(LocalPointerVar, Result.SourceManager); + // Find pointer-type vars with local declaration. if (FuncDeclRtPt) CheckTypedefAndSetFat(FuncDeclRtPt, Result.SourceManager); + // Find typedef with pointer type. if (TypedefPT) { - SourceLocation TypedefLoc = TypedefPT->getLocation(); - FileID LocationID = Result.SourceManager->getFileID(Result.SourceManager-> - getSpellingLoc(TypedefLoc)); + SourceLocation TypedefLoc = TypedefPT->getLocation(); + FileID LocationID = Result.SourceManager->getFileID( + Result.SourceManager->getSpellingLoc(TypedefLoc)); if (LocationID.isValid()) { if (MainFileID == LocationID) { AddHeader(Result.SourceManager); diff --git a/clang-tools-extra/clang-tidy/bsc/FatPtrTransformerCheck.h b/clang-tools-extra/clang-tidy/bsc/FatPtrTransformerCheck.h index d4e37c9ff3c8..6341149fbae1 100644 --- a/clang-tools-extra/clang-tidy/bsc/FatPtrTransformerCheck.h +++ b/clang-tools-extra/clang-tidy/bsc/FatPtrTransformerCheck.h @@ -15,14 +15,11 @@ namespace clang { namespace tidy { namespace bsc { -/// FIXME: Write a short description. -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/bsc/fat-ptr-transformer.html +// Transform the specified file with bsc fat-ptr. class FatPtrTransformerCheck : public ClangTidyCheck { public: FatPtrTransformerCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context), + : ClangTidyCheck(Name, Context), TopLevelList(Options.get("TopLevels", "TEMP_FAILURE_RETRY")) { StringRef(TopLevelList).split(TopLevels, ",", -1, false); } @@ -31,6 +28,7 @@ public: } void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + private: const StringRef TopLevelList; SmallVector TopLevels; @@ -38,15 +36,14 @@ private: bool NeedFix = false; bool AlreadyAddHeader = false; std::vector DeclList; - + void TraversalRecordDecl(RecordDecl *RD, bool *HasArrayField); void AddFat(SourceLocation Loc); void AddChecked(SourceLocation Loc); std::string GetTypeName(const Expr *Arg); void CheckTypedefAndSetFat(const ValueDecl *D, SourceManager *SM); - inline bool FindInDeclList(bool *HasArrayField, - const clang::RecordType* RT) { + inline bool FindInDeclList(bool *HasArrayField, const clang::RecordType *RT) { auto Existed = std::find(DeclList.begin(), DeclList.end(), RT->getDecl()); if (Existed != DeclList.end()) { *HasArrayField = true; @@ -57,10 +54,11 @@ private: inline void AddHeader(SourceManager *SM) { if (!AlreadyAddHeader) { - if (!MainFileID.isInvalid()){ + if (!MainFileID.isInvalid()) { SourceLocation StartOfFileLoc = SM->getLocForStartOfFile(MainFileID); - diag(StartOfFileLoc, "Add Header Here.", DiagnosticIDs::Warning) << - FixItHint::CreateInsertion(StartOfFileLoc, "#include \n"); + diag(StartOfFileLoc, "Add Header Here.", DiagnosticIDs::Warning) + << FixItHint::CreateInsertion(StartOfFileLoc, + "#include \n"); AlreadyAddHeader = true; } } diff --git a/clang-tools-extra/clang-tidy/tool/bsc/bsc-build.py b/clang-tools-extra/clang-tidy/tool/bsc/bsc-build.py index 822a217f5309..33c01d985386 100644 --- a/clang-tools-extra/clang-tidy/tool/bsc/bsc-build.py +++ b/clang-tools-extra/clang-tidy/tool/bsc/bsc-build.py @@ -5,11 +5,14 @@ import os import argparse import subprocess +# Make sure it`s the first time to create '.cfg' file. first_create_cfg = False +# Get the path of this python scrpit. bsc_build_path = os.path.dirname(os.path.abspath(__file__)) +# store all header files from source path. header_list = [] -h_modify_list = [] +# Run shell command. def excute_command(cmd: str, cmd_name: str = None): proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True) stdout_c, stderr_c = proc.communicate() @@ -17,6 +20,7 @@ def excute_command(cmd: str, cmd_name: str = None): print(" ===== " + cmd_name + " Return Code: ", proc.returncode , " ===== ") return proc.returncode +# Run shell command in a list way, and set new env vars if env is not None. def excute_cmd_list(cmd_list: list, env: dict = None): for cmd in cmd_list: cmd_list = [item for item in cmd.split(" ") if item.strip()] @@ -33,10 +37,10 @@ def excute_cmd_list(cmd_list: list, env: dict = None): proc_modify.wait() pass +# Gather information of top-level vars/funcs from source code files. def gather_top_levels(source_path: str, cfg_path: str): global bsc_build_path global header_list - global h_modify_list command_c = ( "find " + source_path + " -type f -name '*.c' " @@ -54,14 +58,8 @@ def gather_top_levels(source_path: str, cfg_path: str): ) excute_command(command_h, "Proc_h") - - command_h_modify = ( - "find " + source_path + " -type f -name '*.h' " - + " -exec " + bsc_build_path + "/clang-tidy " - + "--fix-errors --config-file==" + cfg_path - + " $file {} \;" - ) - h_modify_list.append(command_h_modify) + # # Find all header files and save into a list. + # # FIXME: Try to use SqlLite to save the information into a DB. find_h = ( "find " + source_path + " -type f -name '*.h' " ) @@ -85,10 +83,14 @@ def gather_top_levels(source_path: str, cfg_path: str): ) excute_command(command_hbs, "Proc_hbs") +# Backup sourece codes. def backup_source_code(source_path: str): command_backup = ("cp -r " + source_path + " " + source_path + "_backup") excute_command(command_backup, "Proc_backup") +# Backup system`s default compilers, like '/usr/bin/clang'. Then replace +# them with our fake compilers, by change the direction of the softlink. +# # FIXME: Add situation of other compilers, like 'gcc' or 'cc'. def backup_compiler_and_replace(fake_compiler: str): default_clang = "/usr/bin/clang" if os.path.exists(default_clang): @@ -100,9 +102,10 @@ def backup_compiler_and_replace(fake_compiler: str): excute_command(clang_replace, "Proc_clang_replace") else: print(" ===== Failed to backup " + default_clang + " ===== ") - pass +# Recover system`s default compilers with backup. +# # FIXME: Add situation of other compilers, like 'gcc' or 'cc'. def recover_compiler(): clang_backup = "/usr/bin/clang_backup" if os.path.exists(clang_backup): @@ -112,10 +115,12 @@ def recover_compiler(): clang_recover = "sudo mv -f /usr/bin/clang_backup /usr/bin/clang" excute_command(clang_recover, "Proc_clang_recover") +# Prepare the '.cfg' file, and gather information for it. def preparecfg(file_path: str): global first_create_cfg global bsc_build_path cfg_file = bsc_build_path + "/fat_ptr.cfg" + # Create file. if not first_create_cfg: content = ( 'Checks: -*, bsc-fat-ptr-transformer\n' 'CheckOptions:\n - key: ' @@ -125,6 +130,7 @@ def preparecfg(file_path: str): file.write(content) first_create_cfg = True + # Backup source codes, and gather information. paths = file_path.split(";") for path in paths: abs_source_path = os.path.abspath(path) @@ -180,16 +186,11 @@ def main(): env["CXX"] = fakecompiler_path + os.pathsep + env["CXX"] else: env["CXX"] = fakecompiler_path - - # # Modify headers - # # FIXME: We modify all header now, still need to complete the further logic, to modify the headers that only been used. - # # maybe not, it seems when we modify .c, the used .h will be modified too, need check again. - # excute_cmd_list(h_modify_list) if args.rewrite: print(" =========================== Active source to source after fat-ptr modify. =========================== ") env["REWRITE"] = "Enable" - # # FIXME: transform all file from .c/.h to .cbs/.hbs, then we can rewrite + # # FIXME: transform all file from .c/.h to .cbs/.hbs, then we can rewrite properly. # for file, path in header_dict.items(): # cmd = ( # bsc_build_path @@ -199,12 +200,12 @@ def main(): # ) # excute_command(cmd) - # # FIXME: complete /usr/bin/cc situation. + # # FIXME: complete softlink like '/usr/bin/cc'. # backup_compiler_and_replace(fakecompiler_path) excute_cmd_list(cmds, env) - # # FIXME: complete /usr/bin/cc situation. + # # FIXME: complete softlink like '/usr/bin/cc'. # recover_compiler() pass @@ -212,7 +213,8 @@ def main(): # # FIXME: complete or delete this situation. pass - + # # Build the origin command with default compilers. + # # //FIXME: Finish this part after fixing the problems of rewrite. # excute_cmd_list(cmds) diff --git a/clang-tools-extra/clang-tidy/tool/bsc/fake_clang.py b/clang-tools-extra/clang-tidy/tool/bsc/fake_clang.py index 4dba453f62b5..b62486ef6dec 100644 --- a/clang-tools-extra/clang-tidy/tool/bsc/fake_clang.py +++ b/clang-tools-extra/clang-tidy/tool/bsc/fake_clang.py @@ -6,27 +6,33 @@ import re import argparse import subprocess - +# Get the path of our clang-tidy. def get_clang_tidy(): - clang_tidy_path = None + clang_tidy_path = "" current_file = os.path.abspath(__file__) if (os.path.islink(current_file)): clang_tidy_path = os.path.dirname(os.readlink(current_file)) + "/../" else: clang_tidy_path = os.path.dirname(current_file) + "/../" - - return clang_tidy_path -def find_matching_strings(pattern, strings): - matches = [s for s in strings if pattern.match(s)] - return matches + return clang_tidy_path -def find_matching_includes(strings): - pattern = re.compile(r'\-I.*?') +# Find the certain string from the command. +def find_matching_strings(pattern: str, strings: list): matches = [s for s in strings if pattern.match(s)] return matches -def transform_c_file(cfile, includes, clang_tidy_path): +# Add the certain options to the new command. +def add_options_to_cmd(cmd: str, options: list): + if options: + for opt in options: + cmd = " " + cmd + opt + return cmd + +# Modify the certain C-file. Add '-I' or '-D' +# options into the new command if exsits. +def transform_c_file(cfile: str, includes: list, + macros: list, clang_tidy_path: str): if (clang_tidy_path): command_c = ( clang_tidy_path + "clang-tidy " @@ -34,31 +40,31 @@ def transform_c_file(cfile, includes, clang_tidy_path): + clang_tidy_path + "fat_ptr.cfg " + cfile + " -header-filter=.* " ) - if includes: + if includes or macros: command_c += "-- " - for include in includes: - command_c = command_c + include + " " - pass + command_c = add_options_to_cmd(command_c, includes) + command_c = add_options_to_cmd(command_c, macros) proc_c = subprocess.Popen( command_c, text=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) - + stdout_c, stderr_c = proc_c.communicate() print("Proc_modify Return Code:", proc_c.returncode) pass -def rewrite_c_file(cfile, includes, clang_tidy_path): +# Rewrite this C-file if the rewrite option is on. +def rewrite_c_file(cfile: str, includes: list, + macros: list, clang_tidy_path: str): if (clang_tidy_path): cmd = ( clang_tidy_path + "clang -x" " bsc -rewrite-bsc " + cfile ) - if includes: - for include in includes: - cmd = cmd + " " + include - pass + if includes or macros: + cmd = add_options_to_cmd(cmd, includes) + cmd = add_options_to_cmd(cmd, macros) proc_c = subprocess.Popen( cmd, text=True, shell=True, @@ -72,22 +78,32 @@ def rewrite_c_file(cfile, includes, clang_tidy_path): def main(): if len(sys.argv) > 1: + # Find C-file from the building command. pattern_c = re.compile(r'.*?\.c$') cfile = find_matching_strings(pattern_c, sys.argv) + # Find include option from the building command. pattern_i = re.compile(r'\-I.*?') includes = find_matching_strings(pattern_i, sys.argv) + # Find macro option from the building command. + pattern_d = re.compile(r'\-D.*?') + macros = find_matching_strings(pattern_d, sys.argv) + clang_tidy_path = get_clang_tidy() if (cfile): - transform_c_file(cfile[0], includes, clang_tidy_path) + # Modify C-file. + transform_c_file(cfile[0], includes, + macros, clang_tidy_path) + # Rewrite C-file. env_rewrite = os.environ.get("REWRITE") if env_rewrite and env_rewrite == "Enable": - rewrite_c_file(cfile[0], includes, clang_tidy_path) + rewrite_c_file(cfile[0], includes, + macros, clang_tidy_path) else: print("No command line arguments provided.") if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 67881817f449..9100baa7bef0 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -159,11 +159,6 @@ New checks FIXME: add release notes. -- New :doc:`bsc-fat-ptr - ` check. - - FIXME: add release notes. - - New :doc:`bsc-fat-ptr-collecter ` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/bsc/fat-ptr.rst b/clang-tools-extra/docs/clang-tidy/checks/bsc/fat-ptr.rst deleted file mode 100644 index f0f92143cdbf..000000000000 --- a/clang-tools-extra/docs/clang-tidy/checks/bsc/fat-ptr.rst +++ /dev/null @@ -1,6 +0,0 @@ -.. title:: clang-tidy - bsc-fat-ptr - -bsc-fat-ptr -=========== - -FIXME: Describe what patterns does the check detect and why. Give examples. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index e51ef1bcbfd6..b3c200d3176a 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -82,7 +82,6 @@ Clang-Tidy Checks `bsc-explicit-cast `_, `bsc-fat-ptr-collecter `_, `bsc-fat-ptr-transformer `_, "Yes" - `bsc-fat-ptr `_, "Yes" `bugprone-argument-comment `_, "Yes" `bugprone-assert-side-effect `_, `bugprone-assignment-in-if-condition `_, diff --git a/clang-tools-extra/test/clang-tidy/checkers/bsc/fat-ptr.cpp b/clang-tools-extra/test/clang-tidy/checkers/bsc/fat-ptr.cpp deleted file mode 100644 index 9f34153f54d3..000000000000 --- a/clang-tools-extra/test/clang-tidy/checkers/bsc/fat-ptr.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// RUN: %check_clang_tidy %s bsc-fat-ptr %t - -// FIXME: Add something that triggers the check here. -void f(); -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'f' is insufficiently awesome [bsc-fat-ptr] - -// FIXME: Verify the applied fix. -// * Make the CHECK patterns specific enough and try to make verified lines -// unique to avoid incorrect matches. -// * Use {{}} for regular expressions. -// CHECK-FIXES: {{^}}void awesome_f();{{$}} - -// FIXME: Add something that doesn't trigger the check here. -void awesome_f2(); -- Gitee