Index: clang-query/tool/ClangQuery.cpp =================================================================== --- clang-query/tool/ClangQuery.cpp +++ clang-query/tool/ClangQuery.cpp @@ -59,7 +59,7 @@ cl::cat(ClangQueryCategory)); int main(int argc, const char **argv) { - llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); + llvm::sys::PrintStackTraceOnErrorSignal(); CommonOptionsParser OptionsParser(argc, argv, ClangQueryCategory); Index: clang-rename/CMakeLists.txt =================================================================== --- clang-rename/CMakeLists.txt +++ clang-rename/CMakeLists.txt @@ -10,7 +10,6 @@ clangAST clangBasic clangIndex - clangLex clangToolingCore ) Index: clang-rename/RenamingAction.cpp =================================================================== --- clang-rename/RenamingAction.cpp +++ clang-rename/RenamingAction.cpp @@ -49,7 +49,7 @@ std::vector NewCandidates; for (const auto &USR : USRs) { - NewCandidates = getLocationsOfUSR(USR, PrevName, Context.getTranslationUnitDecl()); + NewCandidates = getLocationsOfUSR(USR, Context.getTranslationUnitDecl()); RenamingCandidates.insert(RenamingCandidates.end(), NewCandidates.begin(), NewCandidates.end()); NewCandidates.clear(); Index: clang-rename/USRFinder.h =================================================================== --- clang-rename/USRFinder.h +++ clang-rename/USRFinder.h @@ -30,12 +30,6 @@ const NamedDecl *getNamedDeclAt(const ASTContext &Context, const SourceLocation Point); -// Given an AST context and a fully qualified name, returns a NamedDecl -// identifying the symbol with a matching name. Returns null if nothing is -// found for the name. -const NamedDecl *getNamedDeclFor(const ASTContext &Context, - const std::string &Name); - // Converts a Decl into a USR. std::string getUSRForDecl(const Decl *Decl); Index: clang-rename/USRFinder.cpp =================================================================== --- clang-rename/USRFinder.cpp +++ clang-rename/USRFinder.cpp @@ -40,14 +40,6 @@ Point(Point) { } - // \brief Finds the NamedDecl for a name in the source. - // \param Name the fully qualified name. - explicit NamedDeclFindingASTVisitor(const SourceManager &SourceMgr, - const std::string &Name) - : Result(nullptr), SourceMgr(SourceMgr), - Name(Name) { - } - // Declaration visitors: // \brief Checks if the point falls within the NameDecl. This covers every @@ -101,17 +93,9 @@ // \returns false on success. bool setResult(const NamedDecl *Decl, SourceLocation Start, SourceLocation End) { - if (Name.empty()) { - // Offset is used to find the declaration. - if (!Start.isValid() || !Start.isFileID() || !End.isValid() || - !End.isFileID() || !isPointWithin(Start, End)) { - return true; - } - } else { - // Fully qualified name is used to find the declaration. - if (Name != Decl->getQualifiedNameAsString()) { - return true; - } + if (!Start.isValid() || !Start.isFileID() || !End.isValid() || + !End.isFileID() || !isPointWithin(Start, End)) { + return true; } Result = Decl; return false; @@ -137,7 +121,6 @@ const NamedDecl *Result; const SourceManager &SourceMgr; const SourceLocation Point; // The location to find the NamedDecl. - const std::string Name; }; } @@ -165,22 +148,6 @@ return nullptr; } -const NamedDecl *getNamedDeclFor(const ASTContext &Context, - const std::string &Name) { - const auto &SourceMgr = Context.getSourceManager(); - NamedDeclFindingASTVisitor Visitor(SourceMgr, Name); - auto Decls = Context.getTranslationUnitDecl()->decls(); - - for (auto &CurrDecl : Decls) { - Visitor.TraverseDecl(CurrDecl); - if (const NamedDecl *Result = Visitor.getNamedDecl()) { - return Result; - } - } - - return nullptr; -} - std::string getUSRForDecl(const Decl *Decl) { llvm::SmallVector Buff; Index: clang-rename/USRFindingAction.h =================================================================== --- clang-rename/USRFindingAction.h +++ clang-rename/USRFindingAction.h @@ -25,7 +25,7 @@ namespace rename { struct USRFindingAction { - USRFindingAction(unsigned Offset, const std::string &Name) : SymbolOffset(Offset), OldName(Name) { + USRFindingAction(unsigned Offset) : SymbolOffset(Offset) { } std::unique_ptr newASTConsumer(); @@ -40,7 +40,6 @@ private: unsigned SymbolOffset; - std::string OldName; std::string SpellingName; std::vector USRs; }; Index: clang-rename/USRFindingAction.cpp =================================================================== --- clang-rename/USRFindingAction.cpp +++ clang-rename/USRFindingAction.cpp @@ -68,12 +68,7 @@ SourceMgr.getMainFileID()).getLocWithOffset(SymbolOffset); if (!Point.isValid()) return; - const NamedDecl *FoundDecl = nullptr; - if (OldName.empty()) { - FoundDecl = getNamedDeclAt(Context, Point); - } else { - FoundDecl = getNamedDeclFor(Context, OldName); - } + const NamedDecl *FoundDecl = getNamedDeclAt(Context, Point); if (FoundDecl == nullptr) { FullSourceLoc FullLoc(Point, SourceMgr); errs() << "clang-rename: could not find symbol at " @@ -101,7 +96,6 @@ } unsigned SymbolOffset; - std::string OldName; std::string *SpellingName; std::vector *USRs; }; @@ -112,7 +106,6 @@ new NamedDeclFindingConsumer); SpellingName = ""; Consumer->SymbolOffset = SymbolOffset; - Consumer->OldName = OldName; Consumer->USRs = &USRs; Consumer->SpellingName = &SpellingName; return std::move(Consumer); Index: clang-rename/USRLocFinder.h =================================================================== --- clang-rename/USRLocFinder.h +++ clang-rename/USRLocFinder.h @@ -19,8 +19,6 @@ #include #include -#include "llvm/ADT/StringRef.h" - namespace clang { class Decl; @@ -29,8 +27,7 @@ namespace rename { // FIXME: make this an AST matcher. Wouldn't that be awesome??? I agree! -std::vector getLocationsOfUSR(llvm::StringRef usr, - llvm::StringRef PrevName, +std::vector getLocationsOfUSR(const std::string usr, Decl *decl); } } Index: clang-rename/USRLocFinder.cpp =================================================================== --- clang-rename/USRLocFinder.cpp +++ clang-rename/USRLocFinder.cpp @@ -20,7 +20,6 @@ #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/SourceLocation.h" #include "clang/Index/USRGeneration.h" -#include "clang/Lex/Lexer.h" #include "llvm/ADT/SmallVector.h" using namespace llvm; @@ -34,7 +33,7 @@ class USRLocFindingASTVisitor : public clang::RecursiveASTVisitor { public: - explicit USRLocFindingASTVisitor(StringRef USR, StringRef PrevName) : USR(USR), PrevName(PrevName) { + explicit USRLocFindingASTVisitor(const std::string USR) : USR(USR) { } // Declaration visitors: @@ -46,69 +45,6 @@ return true; } - bool VisitVarDecl(clang::VarDecl *Decl) { - clang::QualType Type = Decl->getType(); - const clang::RecordDecl *RecordDecl = Type->getPointeeCXXRecordDecl(); - if (RecordDecl) { - if (getUSRForDecl(RecordDecl) == USR) { - // The declaration refers to a type that is to be renamed. - LocationsFound.push_back(Decl->getTypeSpecStartLoc()); - } - } - return true; - } - - bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) { - const ASTContext &Context = ConstructorDecl->getASTContext(); - for (clang::CXXConstructorDecl::init_const_iterator it = ConstructorDecl->init_begin(); it != ConstructorDecl->init_end(); ++it) { - const clang::CXXCtorInitializer* Initializer = *it; - if (Initializer->getSourceOrder() == -1) { - // Ignore implicit initializers. - continue; - } - - if (const clang::FieldDecl *FieldDecl = Initializer->getAnyMember()) { - if (getUSRForDecl(FieldDecl) == USR) { - // The initializer refers to a field that is to be renamed. - SourceLocation Location = Initializer->getSourceLocation(); - StringRef TokenName = Lexer::getSourceText(CharSourceRange::getTokenRange(Location), Context.getSourceManager(), Context.getLangOpts()); - if (TokenName == PrevName) { - // The token of the source location we find actually has the old name. - LocationsFound.push_back(Initializer->getSourceLocation()); - } - } - } - } - - if (getUSRForDecl(ConstructorDecl) == USR) { - // This takes care of the class name part of a non-inline ctor definition. - LocationsFound.push_back(ConstructorDecl->getLocStart()); - } - return true; - } - - bool VisitCXXDestructorDecl(clang::CXXDestructorDecl *DestructorDecl) { - if (getUSRForDecl(DestructorDecl->getParent()) == USR) { - // Handles "~Foo" from "Foo::~Foo". - SourceLocation Location = DestructorDecl->getLocation(); - const ASTContext &Context = DestructorDecl->getASTContext(); - StringRef LLVM_ATTRIBUTE_UNUSED TokenName = Lexer::getSourceText( - CharSourceRange::getTokenRange(Location), Context.getSourceManager(), - Context.getLangOpts()); - // 1 is the length of the "~" string that is not to be touched by the - // rename. - assert(TokenName.startswith("~")); - LocationsFound.push_back(Location.getLocWithOffset(1)); - - if (DestructorDecl->isThisDeclarationADefinition()) { - // Handles "Foo" from "Foo::~Foo". - LocationsFound.push_back(DestructorDecl->getLocStart()); - } - } - - return true; - } - // Expression visitors: bool VisitDeclRefExpr(const DeclRefExpr *Expr) { @@ -116,9 +52,7 @@ checkNestedNameSpecifierLoc(Expr->getQualifierLoc()); if (getUSRForDecl(Decl) == USR) { - const SourceManager &Manager = Decl->getASTContext().getSourceManager(); - SourceLocation Location = Manager.getSpellingLoc(Expr->getLocation()); - LocationsFound.push_back(Location); + LocationsFound.push_back(Expr->getLocation()); } return true; @@ -127,40 +61,11 @@ bool VisitMemberExpr(const MemberExpr *Expr) { const auto *Decl = Expr->getFoundDecl().getDecl(); if (getUSRForDecl(Decl) == USR) { - const SourceManager &Manager = Decl->getASTContext().getSourceManager(); - SourceLocation Location = Manager.getSpellingLoc(Expr->getMemberLoc()); - LocationsFound.push_back(Location); + LocationsFound.push_back(Expr->getMemberLoc()); } return true; } - bool VisitCXXConstructExpr(const CXXConstructExpr *Expr) { - CXXConstructorDecl *Decl = Expr->getConstructor(); - - if (getUSRForDecl(Decl) == USR) { - // This takes care of 'new ' expressions. - LocationsFound.push_back(Expr->getLocation()); - } - - return true; - } - - bool VisitCXXStaticCastExpr(clang::CXXStaticCastExpr *Expr) { - return handleCXXNamedCastExpr(Expr); - } - - bool VisitCXXDynamicCastExpr(clang::CXXDynamicCastExpr *Expr) { - return handleCXXNamedCastExpr(Expr); - } - - bool VisitCXXReinterpretCastExpr(clang::CXXReinterpretCastExpr *Expr) { - return handleCXXNamedCastExpr(Expr); - } - - bool VisitCXXConstCastExpr(clang::CXXConstCastExpr *Expr) { - return handleCXXNamedCastExpr(Expr); - } - // Non-visitors: // \brief Returns a list of unique locations. Duplicate or overlapping @@ -180,35 +85,15 @@ } } - bool handleCXXNamedCastExpr(clang::CXXNamedCastExpr *Expr) { - clang::QualType Type = Expr->getType(); - // See if this a cast of a pointer. - const RecordDecl* Decl = Type->getPointeeCXXRecordDecl(); - if (!Decl) { - // See if this is a cast of a reference. - Decl = Type->getAsCXXRecordDecl(); - } - - if (Decl && getUSRForDecl(Decl) == USR) { - SourceLocation Location = Expr->getTypeInfoAsWritten()->getTypeLoc().getBeginLoc(); - LocationsFound.push_back(Location); - } - - return true; - } - // All the locations of the USR were found. const std::string USR; - // Old name that is renamed. - const std::string PrevName; std::vector LocationsFound; }; } // namespace -std::vector getLocationsOfUSR(StringRef USR, - StringRef PrevName, +std::vector getLocationsOfUSR(const std::string USR, Decl *Decl) { - USRLocFindingASTVisitor visitor(USR, PrevName); + USRLocFindingASTVisitor visitor(USR); visitor.TraverseDecl(Decl); return visitor.getLocationsFound(); Index: clang-rename/tool/CMakeLists.txt =================================================================== --- clang-rename/tool/CMakeLists.txt +++ clang-rename/tool/CMakeLists.txt @@ -6,7 +6,6 @@ clangRename clangRewrite clangTooling - clangToolingCore ) install(TARGETS clang-rename RUNTIME DESTINATION bin) Index: clang-rename/tool/ClangRename.cpp =================================================================== --- clang-rename/tool/ClangRename.cpp +++ clang-rename/tool/ClangRename.cpp @@ -32,7 +32,6 @@ #include "clang/Rewrite/Core/Rewriter.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Refactoring.h" -#include "clang/Tooling/ReplacementsYaml.h" #include "clang/Tooling/Tooling.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/Support/Host.h" @@ -53,11 +52,6 @@ "offset", cl::desc("Locates the symbol by offset as opposed to :."), cl::cat(ClangRenameCategory)); -static cl::opt -OldName( - "old-name", - cl::desc("The fully qualified name of the symbol, if -offset is not used."), - cl::cat(ClangRenameCategory)); static cl::opt Inplace( "i", @@ -73,12 +67,6 @@ "pl", cl::desc("Print the locations affected by renaming to stderr."), cl::cat(ClangRenameCategory)); -static cl::opt -ExportFixes( - "export-fixes", - cl::desc("YAML file to store suggested fixes in."), - cl::value_desc("filename"), - cl::cat(ClangRenameCategory)); #define CLANG_RENAME_VERSION "0.0.1" @@ -108,7 +96,7 @@ // Get the USRs. auto Files = OP.getSourcePathList(); tooling::RefactoringTool Tool(OP.getCompilations(), Files); - rename::USRFindingAction USRAction(SymbolOffset, OldName); + rename::USRFindingAction USRAction(SymbolOffset); // Find the USRs. Tool.run(tooling::newFrontendActionFactory(&USRAction).get()); @@ -120,7 +108,7 @@ exit(1); if (PrintName) - errs() << "clang-rename: found name: " << PrevName << "\n"; + errs() << "clang-rename: found name: " << PrevName; // Perform the renaming. rename::RenamingAction RenameAction(NewName, PrevName, USRs, @@ -133,26 +121,6 @@ } else { res = Tool.run(Factory.get()); - if (!ExportFixes.empty()) { - std::error_code EC; - llvm::raw_fd_ostream OS(ExportFixes, EC, llvm::sys::fs::F_None); - if (EC) { - llvm::errs() << "Error opening output file: " << EC.message() << '\n'; - exit(1); - } - - // Export replacements. - tooling::TranslationUnitReplacements TUR; - const tooling::Replacements &Replacements = Tool.getReplacements(); - TUR.Replacements.insert(TUR.Replacements.end(), Replacements.begin(), - Replacements.end()); - - yaml::Output YAML(OS); - YAML << TUR; - OS.close(); - exit(0); - } - // Write every file to stdout. Right now we just barf the files without any // indication of which files start where, other than that we print the files // in the same order we see them. Index: clang-rename/tool/clang-rename.py =================================================================== --- clang-rename/tool/clang-rename.py +++ /dev/null @@ -1,61 +0,0 @@ -''' -Minimal clang-rename integration with Vim. - -Before installing make sure one of the following is satisfied: - -* clang-rename is in your PATH -* `g:clang_rename_path` in ~/.vimrc points to valid clang-rename executable -* `binary` in clang-rename.py points to valid to clang-rename executable - -To install, simply put this into your ~/.vimrc - - map ,cr :pyf /clang-rename.py - -IMPORTANT NOTE: Before running the tool, make sure you saved the file. - -All you have to do now is to place a cursor on a variable/function/class which -you would like to rename and press ',cr'. You will be prompted for a new name if -the cursor points to a valid symbol. -''' - -import vim -import subprocess -import sys - -def main(): - binary = 'clang-rename' - if vim.eval('exists("g:clang_rename_path")') == "1": - binary = vim.eval('g:clang_rename') - - # Get arguments for clang-rename binary. - offset = int(vim.eval('line2byte(line("."))+col(".")')) - 2 - if offset < 0: - print >> sys.stderr, '''Couldn\'t determine cursor position. - Is your file empty?''' - return - filename = vim.current.buffer.name - - new_name_request_message = 'type new name:' - new_name = vim.eval("input('{}\n')".format(new_name_request_message)) - - # Call clang-rename. - command = [binary, - filename, - '-i', - '-offset', str(offset), - '-new-name', str(new_name)] - # FIXME: make it possible to run the tool on unsaved file. - p = subprocess.Popen(command, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, stderr = p.communicate() - - if stderr: - print stderr - - # Reload all buffers in Vim. - vim.command("bufdo edit") - - -if __name__ == '__main__': - main() Index: clang-tidy/CMakeLists.txt =================================================================== --- clang-tidy/CMakeLists.txt +++ clang-tidy/CMakeLists.txt @@ -27,7 +27,6 @@ add_subdirectory(tool) add_subdirectory(plugin) -add_subdirectory(boost) add_subdirectory(cert) add_subdirectory(llvm) add_subdirectory(cppcoreguidelines) Index: clang-tidy/ClangTidy.h =================================================================== --- clang-tidy/ClangTidy.h +++ clang-tidy/ClangTidy.h @@ -94,11 +94,11 @@ /// base class's methods. E.g. to implement a check that validates namespace /// declarations, override ``registerMatchers``: /// -/// ~~~{.cpp} +/// ```c++ /// void registerMatchers(ast_matchers::MatchFinder *Finder) override { /// Finder->addMatcher(namespaceDecl().bind("namespace"), this); /// } -/// ~~~ +/// ``` /// /// and then override ``check(const MatchResult &Result)`` to do the actual /// check for each match. @@ -127,7 +127,7 @@ /// dependent properties, e.g. the order of include directives. virtual void registerPPCallbacks(CompilerInstance &Compiler) {} - /// \brief Override this to register AST matchers with \p Finder. + /// \brief Override this to register ASTMatchers with \p Finder. /// /// This should be used by clang-tidy checks that analyze code properties that /// dependent on AST knowledge. Index: clang-tidy/ClangTidy.cpp =================================================================== --- clang-tidy/ClangTidy.cpp +++ clang-tidy/ClangTidy.cpp @@ -58,7 +58,7 @@ #define GET_CHECKERS #define CHECKER(FULLNAME, CLASS, DESCFILE, HELPTEXT, GROUPINDEX, HIDDEN) \ FULLNAME, -#include "clang/StaticAnalyzer/Checkers/Checkers.inc" +#include "../../../lib/StaticAnalyzer/Checkers/Checkers.inc" #undef CHECKER #undef GET_CHECKERS }; Index: clang-tidy/ClangTidyDiagnosticConsumer.h =================================================================== --- clang-tidy/ClangTidyDiagnosticConsumer.h +++ clang-tidy/ClangTidyDiagnosticConsumer.h @@ -172,6 +172,9 @@ /// The \c CurrentFile can be changed using \c setCurrentFile. GlobList &getChecksFilter(); + /// \brief Returns true if the check name is enabled for the \c CurrentFile. + bool isCheckEnabled(StringRef CheckName) const; + /// \brief Returns check filter for the \c CurrentFile which /// selects checks for upgrade to error. GlobList &getWarningAsErrorFilter(); Index: clang-tidy/ClangTidyDiagnosticConsumer.cpp =================================================================== --- clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -174,6 +174,20 @@ StringRef CheckName, SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level /* = DiagnosticIDs::Warning*/) { assert(Loc.isValid()); + bool Invalid; + const char *CharacterData = + DiagEngine->getSourceManager().getCharacterData(Loc, &Invalid); + if (!Invalid) { + const char *P = CharacterData; + while (*P != '\0' && *P != '\r' && *P != '\n') + ++P; + StringRef RestOfLine(CharacterData, P - CharacterData + 1); + // FIXME: Handle /\bNOLINT\b(\([^)]*\))?/ as cpplint.py does. + if (RestOfLine.find("NOLINT") != StringRef::npos) { + Level = DiagnosticIDs::Ignored; + ++Stats.ErrorsIgnoredNOLINT; + } + } unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID( Level, (Description + " [" + CheckName + "]").str()); if (CheckNamesByDiagnosticID.count(ID) == 0) @@ -223,6 +237,10 @@ return *CheckFilter; } +bool ClangTidyContext::isCheckEnabled(StringRef CheckName) const { + return CheckFilter->contains(CheckName); +} + GlobList &ClangTidyContext::getWarningAsErrorFilter() { assert(WarningAsErrorFilter != nullptr); return *WarningAsErrorFilter; @@ -272,31 +290,8 @@ LastErrorPassesLineFilter = false; } -static bool LineIsMarkedWithNOLINT(SourceManager& SM, SourceLocation Loc) { - bool Invalid; - const char *CharacterData = SM.getCharacterData(Loc, &Invalid); - if (!Invalid) { - const char *P = CharacterData; - while (*P != '\0' && *P != '\r' && *P != '\n') - ++P; - StringRef RestOfLine(CharacterData, P - CharacterData + 1); - // FIXME: Handle /\bNOLINT\b(\([^)]*\))?/ as cpplint.py does. - if (RestOfLine.find("NOLINT") != StringRef::npos) { - return true; - } - } - return false; -} - void ClangTidyDiagnosticConsumer::HandleDiagnostic( DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { - if (Info.getLocation().isValid() && - DiagLevel != DiagnosticsEngine::Error && - DiagLevel != DiagnosticsEngine::Fatal && - LineIsMarkedWithNOLINT(Diags->getSourceManager(), Info.getLocation())) { - ++Context.Stats.ErrorsIgnoredNOLINT; - return; - } // Count warnings/errors. DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info); Index: clang-tidy/ClangTidyModule.cpp =================================================================== --- clang-tidy/ClangTidyModule.cpp +++ clang-tidy/ClangTidyModule.cpp @@ -18,7 +18,7 @@ void ClangTidyCheckFactories::registerCheckFactory(StringRef Name, CheckFactory Factory) { - Factories[Name] = std::move(Factory); + Factories[Name] = Factory; } void ClangTidyCheckFactories::createChecks( Index: clang-tidy/ClangTidyOptions.cpp =================================================================== --- clang-tidy/ClangTidyOptions.cpp +++ clang-tidy/ClangTidyOptions.cpp @@ -218,6 +218,15 @@ std::vector FileOptionsProvider::getRawOptions(StringRef FileName) { DEBUG(llvm::dbgs() << "Getting options for file " << FileName << "...\n"); + SmallString<256> FilePath(FileName); + + if (std::error_code EC = llvm::sys::fs::make_absolute(FilePath)) { + llvm::errs() << "Can't make absolute path from " << FileName << ": " + << EC.message() << "\n"; + // FIXME: Figure out what to do. + } else { + FileName = FilePath; + } std::vector RawOptions = DefaultOptionsProvider::getRawOptions(FileName); Index: clang-tidy/add_new_check.py =================================================================== --- clang-tidy/add_new_check.py +++ clang-tidy/add_new_check.py @@ -137,8 +137,8 @@ const auto *MatchedDecl = Result.Nodes.getNodeAs("x"); if (MatchedDecl->getName().startswith("awesome_")) return; - diag(MatchedDecl->getLocation(), "function %%0 is insufficiently awesome") - << MatchedDecl + diag(MatchedDecl->getLocation(), "function '%%0' is insufficiently awesome") + << MatchedDecl->getName() << FixItHint::CreateInsertion(MatchedDecl->getLocation(), "awesome_"); } Index: clang-tidy/boost/BoostTidyModule.cpp =================================================================== --- clang-tidy/boost/BoostTidyModule.cpp +++ /dev/null @@ -1,38 +0,0 @@ -//===------- BoostTidyModule.cpp - clang-tidy -----------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "../ClangTidy.h" -#include "../ClangTidyModule.h" -#include "../ClangTidyModuleRegistry.h" -#include "UseToStringCheck.h" -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace boost { - -class BoostModule : public ClangTidyModule { -public: - void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { - CheckFactories.registerCheck("boost-use-to-string"); - } -}; - -// Register the BoostModule using this statically initialized variable. -static ClangTidyModuleRegistry::Add X("boost-module", - "Add boost checks."); - -} // namespace boost - -// This anchor is used to force the linker to link in the generated object file -// and thus register the BoostModule. -volatile int BoostModuleAnchorSource = 0; - -} // namespace tidy -} // namespace clang Index: clang-tidy/boost/CMakeLists.txt =================================================================== --- clang-tidy/boost/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -set(LLVM_LINK_COMPONENTS support) - -add_clang_library(clangTidyBoostModule - BoostTidyModule.cpp - UseToStringCheck.cpp - - LINK_LIBS - clangAST - clangASTMatchers - clangBasic - clangLex - clangTidy - clangTidyUtils - ) Index: clang-tidy/boost/UseToStringCheck.h =================================================================== --- clang-tidy/boost/UseToStringCheck.h +++ /dev/null @@ -1,37 +0,0 @@ -//===--- UseToStringCheck.h - clang-tidy-------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BOOST_USE_TO_STRING_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BOOST_USE_TO_STRING_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace boost { - -/// Finds calls to ``boost::lexical_cast`` and -/// ``boost::lexical_cast`` and replaces them with -/// ``std::to_string`` and ``std::to_wstring`` calls. -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/boost-use-to-string.html -class UseToStringCheck : public ClangTidyCheck { -public: - UseToStringCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -}; - -} // namespace boost -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BOOST_USE_TO_STRING_H Index: clang-tidy/boost/UseToStringCheck.cpp =================================================================== --- clang-tidy/boost/UseToStringCheck.cpp +++ /dev/null @@ -1,73 +0,0 @@ -//===--- UseToStringCheck.cpp - clang-tidy---------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "UseToStringCheck.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace boost { - -AST_MATCHER(Type, isStrictlyInteger) { - return Node.isIntegerType() && !Node.isAnyCharacterType() && - !Node.isBooleanType(); -} - -void UseToStringCheck::registerMatchers(MatchFinder *Finder) { - if (!getLangOpts().CPlusPlus) - return; - - Finder->addMatcher( - callExpr( - hasDeclaration(functionDecl( - returns(hasDeclaration(classTemplateSpecializationDecl( - hasName("std::basic_string"), - hasTemplateArgument(0, - templateArgument().bind("char_type"))))), - hasName("boost::lexical_cast"), - hasParameter(0, hasType(qualType(has(substTemplateTypeParmType( - isStrictlyInteger()))))))), - argumentCountIs(1), unless(isInTemplateInstantiation())) - .bind("to_string"), - this); -} - -void UseToStringCheck::check(const MatchFinder::MatchResult &Result) { - const auto *Call = Result.Nodes.getNodeAs("to_string"); - auto CharType = - Result.Nodes.getNodeAs("char_type")->getAsType(); - - StringRef StringType; - if (CharType->isSpecificBuiltinType(BuiltinType::Char_S) || - CharType->isSpecificBuiltinType(BuiltinType::Char_U)) - StringType = "string"; - else if (CharType->isSpecificBuiltinType(BuiltinType::WChar_S) || - CharType->isSpecificBuiltinType(BuiltinType::WChar_U)) - StringType = "wstring"; - else - return; - - auto Loc = Call->getLocStart(); - auto Diag = - diag(Loc, "use std::to_%0 instead of boost::lexical_cast") - << StringType; - - if (Loc.isMacroID()) - return; - - Diag << FixItHint::CreateReplacement( - CharSourceRange::getCharRange(Call->getLocStart(), - Call->getArg(0)->getLocStart()), - (llvm::Twine("std::to_") + StringType + "(").str()); -} - -} // namespace boost -} // namespace tidy -} // namespace clang Index: clang-tidy/cert/CERTTidyModule.cpp =================================================================== --- clang-tidy/cert/CERTTidyModule.cpp +++ clang-tidy/cert/CERTTidyModule.cpp @@ -18,9 +18,9 @@ #include "../misc/ThrowByValueCatchByReferenceCheck.h" #include "CommandProcessorCheck.h" #include "FloatLoopCounter.h" +#include "LimitedRandomnessCheck.h" #include "SetLongJmpCheck.h" #include "StaticObjectExceptionCheck.h" -#include "StrToNumCheck.h" #include "ThrownExceptionTypeCheck.h" #include "VariadicFunctionDefCheck.h" @@ -33,6 +33,8 @@ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { // C++ checkers // DCL + CheckFactories.registerCheck( + "cert-msc50-cpp"); CheckFactories.registerCheck( "cert-dcl50-cpp"); CheckFactories.registerCheck( @@ -40,7 +42,7 @@ CheckFactories.registerCheck( "cert-dcl59-cpp"); // OOP - CheckFactories.registerCheck( + CheckFactories.registerCheck( "cert-oop11-cpp"); // ERR CheckFactories.registerCheck( @@ -49,12 +51,12 @@ "cert-err58-cpp"); CheckFactories.registerCheck( "cert-err60-cpp"); - CheckFactories.registerCheck( + CheckFactories.registerCheck( "cert-err61-cpp"); // C checkers // DCL - CheckFactories.registerCheck( + CheckFactories.registerCheck( "cert-dcl03-c"); // ENV CheckFactories.registerCheck( @@ -63,16 +65,8 @@ CheckFactories.registerCheck( "cert-flp30-c"); // FIO - CheckFactories.registerCheck( + CheckFactories.registerCheck( "cert-fio38-c"); - // ERR - CheckFactories.registerCheck( - "cert-err34-c"); - } - ClangTidyOptions getModuleOptions() override { - ClangTidyOptions Options; - Options.CheckOptions["cert-oop11-cpp.UseCERTSemantics"] = "1"; - return Options; } }; Index: clang-tidy/cert/CMakeLists.txt =================================================================== --- clang-tidy/cert/CMakeLists.txt +++ clang-tidy/cert/CMakeLists.txt @@ -4,14 +4,13 @@ CERTTidyModule.cpp CommandProcessorCheck.cpp FloatLoopCounter.cpp + LimitedRandomnessCheck.cpp SetLongJmpCheck.cpp StaticObjectExceptionCheck.cpp - StrToNumCheck.cpp ThrownExceptionTypeCheck.cpp VariadicFunctionDefCheck.cpp LINK_LIBS - clangAnalysis clangAST clangASTMatchers clangBasic Index: clang-tidy/cert/LimitedRandomnessCheck.h =================================================================== --- /dev/null +++ clang-tidy/cert/LimitedRandomnessCheck.h @@ -0,0 +1,37 @@ +//===--- LimitedRandomnessCheck.h - clang-tidy-------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_LIMITED_RANDOMNESS_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_LIMITED_RANDOMNESS_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace cert { + +/// Pseudorandom number generators are not genuinely random. This checker warns +/// for the usage of std::rand() function. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/cert-msc50-cpp.html +class LimitedRandomnessCheck : public ClangTidyCheck { +public: + LimitedRandomnessCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace cert +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_LIMITED_RANDOMNESS_H + Index: clang-tidy/cert/LimitedRandomnessCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/cert/LimitedRandomnessCheck.cpp @@ -0,0 +1,37 @@ +//===--- LimitedRandomnessCheck.cpp - clang-tidy---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LimitedRandomnessCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace cert { + +void LimitedRandomnessCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + declRefExpr(hasDeclaration(functionDecl(namedDecl(hasName("::rand")), + parameterCountIs(0)))) + .bind("randomGenerator"), + this); +} + +void LimitedRandomnessCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = + Result.Nodes.getNodeAs("randomGenerator"); + diag(MatchedDecl->getLocation(), "rand() function has limited randomness, " + "use C++11 random library instead"); +} + +} // namespace cert +} // namespace tidy +} // namespace clang Index: clang-tidy/cert/StrToNumCheck.h =================================================================== --- clang-tidy/cert/StrToNumCheck.h +++ /dev/null @@ -1,36 +0,0 @@ -//===--- StrToNumCheck.h - clang-tidy----------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_STRTONUMCHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_STRTONUMCHECK_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace cert { - -/// Guards against use of string conversion functions that do not have -/// reasonable error handling for conversion errors. -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/cert-err34-c.html -class StrToNumCheck : public ClangTidyCheck { -public: - StrToNumCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -}; - -} // namespace cert -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_STRTONUMCHECK_H Index: clang-tidy/cert/StrToNumCheck.cpp =================================================================== --- clang-tidy/cert/StrToNumCheck.cpp +++ /dev/null @@ -1,235 +0,0 @@ -//===--- Err34CCheck.cpp - clang-tidy--------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "StrToNumCheck.h" -#include "clang/Analysis/Analyses/FormatString.h" -#include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "llvm/ADT/StringSwitch.h" -#include - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace cert { - -void StrToNumCheck::registerMatchers(MatchFinder *Finder) { - // Match any function call to the C standard library string conversion - // functions that do no error checking. - Finder->addMatcher( - callExpr( - callee(functionDecl(anyOf( - functionDecl(hasAnyName("::atoi", "::atof", "::atol", "::atoll")) - .bind("converter"), - functionDecl(hasAnyName("::scanf", "::sscanf", "::fscanf", - "::vfscanf", "::vscanf", "::vsscanf")) - .bind("formatted"))))) - .bind("expr"), - this); -} - -namespace { -enum class ConversionKind { - None, - ToInt, - ToUInt, - ToLongInt, - ToLongUInt, - ToIntMax, - ToUIntMax, - ToFloat, - ToDouble, - ToLongDouble -}; - -ConversionKind ClassifyConversionFunc(const FunctionDecl *FD) { - return llvm::StringSwitch(FD->getName()) - .Cases("atoi", "atol", ConversionKind::ToInt) - .Case("atoll", ConversionKind::ToLongInt) - .Case("atof", ConversionKind::ToDouble) - .Default(ConversionKind::None); -} - -ConversionKind ClassifyFormatString(StringRef Fmt, const LangOptions &LO, - const TargetInfo &TI) { - // Scan the format string for the first problematic format specifier, then - // report that as the conversion type. This will miss additional conversion - // specifiers, but that is acceptable behavior. - - class Handler : public analyze_format_string::FormatStringHandler { - ConversionKind CK; - - bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, - const char *startSpecifier, - unsigned specifierLen) override { - // If we just consume the argument without assignment, we don't care - // about it having conversion errors. - if (!FS.consumesDataArgument()) - return true; - - // Get the conversion specifier and use it to determine the conversion - // kind. - analyze_scanf::ScanfConversionSpecifier SCS = FS.getConversionSpecifier(); - if (SCS.isIntArg()) { - switch (FS.getLengthModifier().getKind()) { - case analyze_scanf::LengthModifier::AsLongLong: - CK = ConversionKind::ToLongInt; - break; - case analyze_scanf::LengthModifier::AsIntMax: - CK = ConversionKind::ToIntMax; - break; - default: - CK = ConversionKind::ToInt; - break; - } - } else if (SCS.isUIntArg()) { - switch (FS.getLengthModifier().getKind()) { - case analyze_scanf::LengthModifier::AsLongLong: - CK = ConversionKind::ToLongUInt; - break; - case analyze_scanf::LengthModifier::AsIntMax: - CK = ConversionKind::ToUIntMax; - break; - default: - CK = ConversionKind::ToUInt; - break; - } - } else if (SCS.isDoubleArg()) { - switch (FS.getLengthModifier().getKind()) { - case analyze_scanf::LengthModifier::AsLongDouble: - CK = ConversionKind::ToLongDouble; - break; - case analyze_scanf::LengthModifier::AsLong: - CK = ConversionKind::ToDouble; - break; - default: - CK = ConversionKind::ToFloat; - break; - } - } - - // Continue if we have yet to find a conversion kind that we care about. - return CK == ConversionKind::None; - } - - public: - Handler() : CK(ConversionKind::None) {} - - ConversionKind get() const { return CK; } - }; - - Handler H; - analyze_format_string::ParseScanfString(H, Fmt.begin(), Fmt.end(), LO, TI); - - return H.get(); -} - -StringRef ClassifyConversionType(ConversionKind K) { - switch (K) { - case ConversionKind::None: - assert(false && "Unexpected conversion kind"); - case ConversionKind::ToInt: - case ConversionKind::ToLongInt: - case ConversionKind::ToIntMax: - return "an integer value"; - case ConversionKind::ToUInt: - case ConversionKind::ToLongUInt: - case ConversionKind::ToUIntMax: - return "an unsigned integer value"; - case ConversionKind::ToFloat: - case ConversionKind::ToDouble: - case ConversionKind::ToLongDouble: - return "a floating-point value"; - } - llvm_unreachable("Unknown conversion kind"); -} - -StringRef ClassifyReplacement(ConversionKind K) { - switch (K) { - case ConversionKind::None: - assert(false && "Unexpected conversion kind"); - case ConversionKind::ToInt: - return "strtol"; - case ConversionKind::ToUInt: - return "strtoul"; - case ConversionKind::ToIntMax: - return "strtoimax"; - case ConversionKind::ToLongInt: - return "strtoll"; - case ConversionKind::ToLongUInt: - return "strtoull"; - case ConversionKind::ToUIntMax: - return "strtoumax"; - case ConversionKind::ToFloat: - return "strtof"; - case ConversionKind::ToDouble: - return "strtod"; - case ConversionKind::ToLongDouble: - return "strtold"; - } - llvm_unreachable("Unknown conversion kind"); -} -} // unnamed namespace - -void StrToNumCheck::check(const MatchFinder::MatchResult &Result) { - const auto *Call = Result.Nodes.getNodeAs("expr"); - const FunctionDecl *FuncDecl = nullptr; - ConversionKind Conversion; - - if (const auto *ConverterFunc = - Result.Nodes.getNodeAs("converter")) { - // Converter functions are always incorrect to use. - FuncDecl = ConverterFunc; - Conversion = ClassifyConversionFunc(ConverterFunc); - } else if (const auto *FFD = - Result.Nodes.getNodeAs("formatted")) { - StringRef FmtStr; - // The format string comes from the call expression and depends on which - // flavor of scanf is called. - // Index 0: scanf, vscanf, Index 1: fscanf, sscanf, vfscanf, vsscanf. - unsigned Idx = - (FFD->getName() == "scanf" || FFD->getName() == "vscanf") ? 0 : 1; - - // Given the index, see if the call expression argument at that index is - // a string literal. - if (Call->getNumArgs() < Idx) - return; - - if (const Expr *Arg = Call->getArg(Idx)->IgnoreParenImpCasts()) { - if (const auto *SL = dyn_cast(Arg)) { - FmtStr = SL->getString(); - } - } - - // If we could not get the format string, bail out. - if (FmtStr.empty()) - return; - - // Formatted input functions need further checking of the format string to - // determine whether a problematic conversion may be happening. - Conversion = ClassifyFormatString(FmtStr, Result.Context->getLangOpts(), - Result.Context->getTargetInfo()); - if (Conversion != ConversionKind::None) - FuncDecl = FFD; - } - - if (!FuncDecl) - return; - - diag(Call->getExprLoc(), - "%0 used to convert a string to %1, but function will not report " - "conversion errors; consider using '%2' instead") - << FuncDecl << ClassifyConversionType(Conversion) - << ClassifyReplacement(Conversion); -} - -} // namespace cert -} // namespace tidy -} // namespace clang Index: clang-tidy/cert/ThrownExceptionTypeCheck.cpp =================================================================== --- clang-tidy/cert/ThrownExceptionTypeCheck.cpp +++ clang-tidy/cert/ThrownExceptionTypeCheck.cpp @@ -23,10 +23,10 @@ return; Finder->addMatcher( - cxxThrowExpr(has(ignoringParenImpCasts( - cxxConstructExpr(hasDeclaration(cxxConstructorDecl( - isCopyConstructor(), unless(isNoThrow())))) - .bind("expr")))), + cxxThrowExpr( + has(cxxConstructExpr(hasDeclaration(cxxConstructorDecl( + isCopyConstructor(), unless(isNoThrow())))) + .bind("expr"))), this); } Index: clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp =================================================================== --- clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp +++ clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp @@ -10,7 +10,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" -#include "../misc/UnconventionalAssignOperatorCheck.h" +#include "../misc/AssignOperatorSignatureCheck.h" #include "InterfacesGlobalInitCheck.h" #include "ProBoundsArrayToPointerDecayCheck.h" #include "ProBoundsConstantArrayIndexCheck.h" @@ -53,7 +53,7 @@ "cppcoreguidelines-pro-type-union-access"); CheckFactories.registerCheck( "cppcoreguidelines-pro-type-vararg"); - CheckFactories.registerCheck( + CheckFactories.registerCheck( "cppcoreguidelines-c-copy-assignment-signature"); } }; Index: clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.h =================================================================== --- clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.h +++ clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.h @@ -14,8 +14,7 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { - + /// This check flags all array to pointer decays /// /// For the user-facing documentation see: @@ -28,7 +27,6 @@ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; }; -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp =================================================================== --- clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp +++ clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp @@ -15,7 +15,6 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { AST_MATCHER_P(CXXForRangeStmt, hasRangeBeginEndStmt, ast_matchers::internal::Matcher, InnerMatcher) { @@ -75,6 +74,5 @@ "an explicit cast instead"); } -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/cppcoreguidelines/ProBoundsConstantArrayIndexCheck.h =================================================================== --- clang-tidy/cppcoreguidelines/ProBoundsConstantArrayIndexCheck.h +++ clang-tidy/cppcoreguidelines/ProBoundsConstantArrayIndexCheck.h @@ -15,7 +15,6 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { /// This checks that all array subscriptions on static arrays and std::arrays /// have a constant index and are within bounds @@ -24,8 +23,8 @@ /// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-pro-bounds-constant-array-index.html class ProBoundsConstantArrayIndexCheck : public ClangTidyCheck { const std::string GslHeader; - const utils::IncludeSorter::IncludeStyle IncludeStyle; - std::unique_ptr Inserter; + const IncludeSorter::IncludeStyle IncludeStyle; + std::unique_ptr Inserter; public: ProBoundsConstantArrayIndexCheck(StringRef Name, ClangTidyContext *Context); @@ -35,7 +34,6 @@ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; }; -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/cppcoreguidelines/ProBoundsConstantArrayIndexCheck.cpp =================================================================== --- clang-tidy/cppcoreguidelines/ProBoundsConstantArrayIndexCheck.cpp +++ clang-tidy/cppcoreguidelines/ProBoundsConstantArrayIndexCheck.cpp @@ -17,12 +17,11 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { ProBoundsConstantArrayIndexCheck::ProBoundsConstantArrayIndexCheck( StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), GslHeader(Options.get("GslHeader", "")), - IncludeStyle(utils::IncludeSorter::parseIncludeStyle( + IncludeStyle(IncludeSorter::parseIncludeStyle( Options.get("IncludeStyle", "llvm"))) {} void ProBoundsConstantArrayIndexCheck::storeOptions( @@ -36,8 +35,8 @@ if (!getLangOpts().CPlusPlus) return; - Inserter.reset(new utils::IncludeInserter( - Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle)); + Inserter.reset(new IncludeInserter(Compiler.getSourceManager(), + Compiler.getLangOpts(), IncludeStyle)); Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks()); } @@ -129,6 +128,5 @@ } } -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.h =================================================================== --- clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.h +++ clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.h @@ -14,7 +14,6 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { /// Flags all kinds of pointer arithmetic that have result of pointer type, i.e. /// +, -, +=, -=, ++, --. In addition, the [] operator on pointers (not on arrays) is flagged. @@ -29,7 +28,6 @@ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; }; -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp =================================================================== --- clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp +++ clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp @@ -15,7 +15,6 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { void ProBoundsPointerArithmeticCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) @@ -54,6 +53,5 @@ diag(MatchedExpr->getExprLoc(), "do not use pointer arithmetic"); } -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/cppcoreguidelines/ProTypeConstCastCheck.h =================================================================== --- clang-tidy/cppcoreguidelines/ProTypeConstCastCheck.h +++ clang-tidy/cppcoreguidelines/ProTypeConstCastCheck.h @@ -14,8 +14,7 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { - + /// This check flags all instances of const_cast /// /// For the user-facing documentation see: @@ -28,7 +27,6 @@ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; }; -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/cppcoreguidelines/ProTypeConstCastCheck.cpp =================================================================== --- clang-tidy/cppcoreguidelines/ProTypeConstCastCheck.cpp +++ clang-tidy/cppcoreguidelines/ProTypeConstCastCheck.cpp @@ -15,8 +15,7 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { - + void ProTypeConstCastCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; @@ -29,6 +28,5 @@ diag(MatchedCast->getOperatorLoc(), "do not use const_cast"); } -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.h =================================================================== --- clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.h +++ clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.h @@ -14,7 +14,6 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { /// This check flags all use of C-style casts that perform a static_cast /// downcast, const_cast, or reinterpret_cast. @@ -29,7 +28,6 @@ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; }; -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp =================================================================== --- clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp +++ clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp @@ -16,7 +16,6 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { static bool needsConstCast(QualType SourceType, QualType DestType) { SourceType = SourceType.getNonReferenceType(); @@ -104,6 +103,5 @@ } } -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp =================================================================== --- clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp +++ clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp @@ -27,23 +27,14 @@ namespace { -// Iterate over all the fields in a record type, both direct and indirect (e.g. -// if the record contains an anonmyous struct). If OneFieldPerUnion is true and -// the record type (or indirect field) is a union, forEachField will stop after -// the first field. -template -void forEachField(const RecordDecl *Record, const T &Fields, - bool OneFieldPerUnion, Func &&Fn) { +void fieldsRequiringInit(const RecordDecl::field_range &Fields, + ASTContext &Context, + SmallPtrSetImpl &FieldsToInit) { for (const FieldDecl *F : Fields) { - if (F->isAnonymousStructOrUnion()) { - if (const CXXRecordDecl *R = F->getType()->getAsCXXRecordDecl()) - forEachField(R, R->fields(), OneFieldPerUnion, Fn); - } else { - Fn(F); - } - - if (OneFieldPerUnion && Record->isUnion()) - break; + QualType Type = F->getType(); + if (!F->hasInClassInitializer() && + type_traits::isTriviallyDefaultConstructible(Type, Context)) + FieldsToInit.insert(F); } } @@ -121,12 +112,12 @@ SourceLocation Location; switch (Placement) { case InitializerPlacement::New: - Location = utils::lexer::getPreviousNonCommentToken( + Location = lexer_utils::getPreviousNonCommentToken( Context, Constructor.getBody()->getLocStart()) .getLocation(); break; case InitializerPlacement::Before: - Location = utils::lexer::getPreviousNonCommentToken( + Location = lexer_utils::getPreviousNonCommentToken( Context, Where->getSourceRange().getBegin()) .getLocation(); break; @@ -186,9 +177,9 @@ // Gets either the field or base class being initialized by the provided // initializer. const auto *InitDecl = - Init->isAnyMemberInitializer() - ? static_cast(Init->getAnyMember()) - : Init->getBaseClass()->getAsCXXRecordDecl(); + Init->isMemberInitializer() + ? static_cast(Init->getMember()) + : Init->getBaseClass()->getAs()->getDecl(); // Add all fields between current field up until the next intializer. for (; Decl != std::end(OrderedDecls) && *Decl != InitDecl; ++Decl) { @@ -223,8 +214,7 @@ Decls.emplace_back(Decl); } } - forEachField(ClassDecl, ClassDecl->fields(), false, - [&](const FieldDecl *F) { Decls.push_back(F); }); + Decls.append(ClassDecl->fields().begin(), ClassDecl->fields().end()); } template @@ -246,6 +236,22 @@ } } +template +void forEachField(const RecordDecl *Record, const T &Fields, + bool OneFieldPerUnion, Func &&Fn) { + for (const FieldDecl *F : Fields) { + if (F->isAnonymousStructOrUnion()) { + if (const RecordDecl *R = getCanonicalRecordDecl(F->getType())) + forEachField(R, R->fields(), OneFieldPerUnion, Fn); + } else { + Fn(F); + } + + if (OneFieldPerUnion && Record->isUnion()) + break; + } +} + } // anonymous namespace ProTypeMemberInitCheck::ProTypeMemberInitCheck(StringRef Name, @@ -275,7 +281,6 @@ isDefaultConstructor(), unless(isUserProvided()))))); Finder->addMatcher( varDecl(isDefinition(), HasDefaultConstructor, - hasAutomaticStorageDuration(), hasType(recordDecl(has(fieldDecl()), isTriviallyDefaultConstructible()))) .bind("var"), @@ -306,14 +311,8 @@ if (IsUnion && ClassDecl->hasInClassInitializer()) return; - // Gather all fields (direct and indirect) that need to be initialized. SmallPtrSet FieldsToInit; - forEachField(ClassDecl, ClassDecl->fields(), false, [&](const FieldDecl *F) { - if (!F->hasInClassInitializer() && - utils::type_traits::isTriviallyDefaultConstructible(F->getType(), - Context)) - FieldsToInit.insert(F); - }); + fieldsRequiringInit(ClassDecl->fields(), Context, FieldsToInit); if (FieldsToInit.empty()) return; @@ -323,7 +322,7 @@ if (Init->isAnyMemberInitializer() && Init->isWritten()) { if (IsUnion) return; // We can only initialize one member of a union. - FieldsToInit.erase(Init->getAnyMember()); + FieldsToInit.erase(Init->getMember()); } } removeFieldsInitializedInBody(*Ctor->getBody(), Context, FieldsToInit); @@ -387,8 +386,7 @@ if (const auto *BaseClassDecl = getCanonicalRecordDecl(Base.getType())) { AllBases.emplace_back(BaseClassDecl); if (!BaseClassDecl->field_empty() && - utils::type_traits::isTriviallyDefaultConstructible(Base.getType(), - Context)) + type_traits::isTriviallyDefaultConstructible(Base.getType(), Context)) BasesToInit.insert(BaseClassDecl); } } @@ -399,7 +397,7 @@ // Remove any bases that were explicitly written in the initializer list. for (const CXXCtorInitializer *Init : Ctor->inits()) { if (Init->isBaseInitializer() && Init->isWritten()) - BasesToInit.erase(Init->getBaseClass()->getAsCXXRecordDecl()); + BasesToInit.erase(Init->getBaseClass()->getAs()->getDecl()); } if (BasesToInit.empty()) Index: clang-tidy/cppcoreguidelines/ProTypeReinterpretCastCheck.h =================================================================== --- clang-tidy/cppcoreguidelines/ProTypeReinterpretCastCheck.h +++ clang-tidy/cppcoreguidelines/ProTypeReinterpretCastCheck.h @@ -14,7 +14,6 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { /// Flags all occurrences of reinterpret_cast /// @@ -28,7 +27,6 @@ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; }; -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/cppcoreguidelines/ProTypeReinterpretCastCheck.cpp =================================================================== --- clang-tidy/cppcoreguidelines/ProTypeReinterpretCastCheck.cpp +++ clang-tidy/cppcoreguidelines/ProTypeReinterpretCastCheck.cpp @@ -15,7 +15,6 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { void ProTypeReinterpretCastCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) @@ -31,6 +30,5 @@ diag(MatchedCast->getOperatorLoc(), "do not use reinterpret_cast"); } -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.h =================================================================== --- clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.h +++ clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.h @@ -14,8 +14,7 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { - + /// Checks for usages of static_cast, where a base class is downcasted to a derived class. /// /// For the user-facing documentation see: @@ -28,7 +27,6 @@ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; }; -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.cpp =================================================================== --- clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.cpp +++ clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.cpp @@ -15,8 +15,7 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { - + void ProTypeStaticCastDowncastCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; @@ -49,6 +48,5 @@ "do not use static_cast to downcast from a base to a derived class"); } -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/cppcoreguidelines/ProTypeUnionAccessCheck.h =================================================================== --- clang-tidy/cppcoreguidelines/ProTypeUnionAccessCheck.h +++ clang-tidy/cppcoreguidelines/ProTypeUnionAccessCheck.h @@ -14,7 +14,6 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { /// This check flags all access to members of unions. /// Access to a union as a whole (e.g. passing to a function) is not flagged. @@ -29,7 +28,6 @@ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; }; -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/cppcoreguidelines/ProTypeUnionAccessCheck.cpp =================================================================== --- clang-tidy/cppcoreguidelines/ProTypeUnionAccessCheck.cpp +++ clang-tidy/cppcoreguidelines/ProTypeUnionAccessCheck.cpp @@ -15,7 +15,6 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { void ProTypeUnionAccessCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) @@ -29,7 +28,6 @@ diag(Matched->getMemberLoc(), "do not access members of unions; use (boost::)variant instead"); } -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/cppcoreguidelines/ProTypeVarargCheck.h =================================================================== --- clang-tidy/cppcoreguidelines/ProTypeVarargCheck.h +++ clang-tidy/cppcoreguidelines/ProTypeVarargCheck.h @@ -14,7 +14,6 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { /// This check flags all calls to c-style variadic functions and all use /// of va_arg. @@ -29,7 +28,6 @@ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; }; -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/cppcoreguidelines/ProTypeVarargCheck.cpp =================================================================== --- clang-tidy/cppcoreguidelines/ProTypeVarargCheck.cpp +++ clang-tidy/cppcoreguidelines/ProTypeVarargCheck.cpp @@ -15,7 +15,6 @@ namespace clang { namespace tidy { -namespace cppcoreguidelines { const internal::VariadicDynCastAllOfMatcher vAArgExpr; @@ -73,6 +72,5 @@ } } -} // namespace cppcoreguidelines } // namespace tidy } // namespace clang Index: clang-tidy/google/CMakeLists.txt =================================================================== --- clang-tidy/google/CMakeLists.txt +++ clang-tidy/google/CMakeLists.txt @@ -2,7 +2,6 @@ add_clang_library(clangTidyGoogleModule AvoidCStyleCastsCheck.cpp - DefaultArgumentsCheck.cpp ExplicitConstructorCheck.cpp ExplicitMakePairCheck.cpp GlobalNamesInHeadersCheck.cpp Index: clang-tidy/google/DefaultArgumentsCheck.h =================================================================== --- clang-tidy/google/DefaultArgumentsCheck.h +++ /dev/null @@ -1,34 +0,0 @@ -//===--- DefaultArgumentsCheck.h - clang-tidy--------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_DEFAULT_ARGUMENTS_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_DEFAULT_ARGUMENTS_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace google { - -/// Checks that default parameters are not given for virtual methods. -/// -/// See https://google.github.io/styleguide/cppguide.html#Default_Arguments -class DefaultArgumentsCheck : public ClangTidyCheck { -public: - DefaultArgumentsCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -}; - -} // namespace google -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_DEFAULT_ARGUMENTS_H Index: clang-tidy/google/DefaultArgumentsCheck.cpp =================================================================== --- clang-tidy/google/DefaultArgumentsCheck.cpp +++ /dev/null @@ -1,36 +0,0 @@ -//===--- DefaultArgumentsCheck.cpp - clang-tidy----------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "DefaultArgumentsCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace google { - -void DefaultArgumentsCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher( - cxxMethodDecl(anyOf(isOverride(), isVirtual()), - hasAnyParameter(parmVarDecl(hasInitializer(expr())))) - .bind("Decl"), - this); -} - -void DefaultArgumentsCheck::check(const MatchFinder::MatchResult &Result) { - const auto *MatchedDecl = Result.Nodes.getNodeAs("Decl"); - diag(MatchedDecl->getLocation(), - "default arguments on virtual or override methods are prohibited"); -} - -} // namespace google -} // namespace tidy -} // namespace clang Index: clang-tidy/google/ExplicitConstructorCheck.cpp =================================================================== --- clang-tidy/google/ExplicitConstructorCheck.cpp +++ clang-tidy/google/ExplicitConstructorCheck.cpp @@ -29,8 +29,7 @@ // Looks for the token matching the predicate and returns the range of the found // token including trailing whitespace. -static SourceRange FindToken(const SourceManager &Sources, - const LangOptions &LangOpts, +static SourceRange FindToken(const SourceManager &Sources, LangOptions LangOpts, SourceLocation StartLoc, SourceLocation EndLoc, bool (*Pred)(const Token &)) { if (StartLoc.isMacroID() || EndLoc.isMacroID()) Index: clang-tidy/google/GlobalNamesInHeadersCheck.h =================================================================== --- clang-tidy/google/GlobalNamesInHeadersCheck.h +++ clang-tidy/google/GlobalNamesInHeadersCheck.h @@ -23,7 +23,7 @@ /// /// The check supports these options: /// - `HeaderFileExtensions`: a comma-separated list of filename extensions -/// of header files (the filename extensions should not contain "." prefix). +/// of header files (The filename extensions should not contain "." prefix). /// "h" by default. /// For extension-less header files, using an empty string or leaving an /// empty string between "," if there are other filename extensions. Index: clang-tidy/google/GoogleTidyModule.cpp =================================================================== --- clang-tidy/google/GoogleTidyModule.cpp +++ clang-tidy/google/GoogleTidyModule.cpp @@ -15,7 +15,6 @@ #include "../readability/NamespaceCommentCheck.h" #include "../readability/RedundantSmartptrGetCheck.h" #include "AvoidCStyleCastsCheck.h" -#include "DefaultArgumentsCheck.h" #include "ExplicitConstructorCheck.h" #include "ExplicitMakePairCheck.h" #include "GlobalNamesInHeadersCheck.h" @@ -43,8 +42,6 @@ "google-build-namespaces"); CheckFactories.registerCheck( "google-build-using-namespace"); - CheckFactories.registerCheck( - "google-default-arguments"); CheckFactories.registerCheck( "google-explicit-constructor"); CheckFactories.registerCheck( Index: clang-tidy/llvm/HeaderGuardCheck.h =================================================================== --- clang-tidy/llvm/HeaderGuardCheck.h +++ clang-tidy/llvm/HeaderGuardCheck.h @@ -17,7 +17,7 @@ namespace llvm { /// Finds and fixes header guards that do not adhere to LLVM style. -class LLVMHeaderGuardCheck : public utils::HeaderGuardCheck { +class LLVMHeaderGuardCheck : public HeaderGuardCheck { public: LLVMHeaderGuardCheck(StringRef Name, ClangTidyContext *Context) : HeaderGuardCheck(Name, Context) {} Index: clang-tidy/llvm/TwineLocalCheck.cpp =================================================================== --- clang-tidy/llvm/TwineLocalCheck.cpp +++ clang-tidy/llvm/TwineLocalCheck.cpp @@ -33,8 +33,7 @@ if (VD->hasInit()) { // Peel away implicit constructors and casts so we can see the actual type // of the initializer. - const Expr *C = VD->getInit()->IgnoreImplicit(); - + const Expr *C = VD->getInit(); while (isa(C)) C = cast(C)->getArg(0)->IgnoreParenImpCasts(); Index: clang-tidy/misc/ArgumentCommentCheck.h =================================================================== --- clang-tidy/misc/ArgumentCommentCheck.h +++ clang-tidy/misc/ArgumentCommentCheck.h @@ -43,6 +43,8 @@ bool isLikelyTypo(llvm::ArrayRef Params, StringRef ArgName, unsigned ArgIndex); + std::vector> + getCommentsInRange(ASTContext *Ctx, SourceRange Range); void checkCallArgs(ASTContext *Ctx, const FunctionDecl *Callee, SourceLocation ArgBeginLoc, llvm::ArrayRef Args); Index: clang-tidy/misc/ArgumentCommentCheck.cpp =================================================================== --- clang-tidy/misc/ArgumentCommentCheck.cpp +++ clang-tidy/misc/ArgumentCommentCheck.cpp @@ -37,8 +37,8 @@ Finder->addMatcher(cxxConstructExpr().bind("expr"), this); } -static std::vector> -getCommentsInRange(ASTContext *Ctx, CharSourceRange Range) { +std::vector> +ArgumentCommentCheck::getCommentsInRange(ASTContext *Ctx, SourceRange Range) { std::vector> Comments; auto &SM = Ctx->getSourceManager(); std::pair BeginLoc = SM.getDecomposedLoc(Range.getBegin()), @@ -132,13 +132,16 @@ } } - CharSourceRange BeforeArgument = CharSourceRange::getCharRange( - i == 0 ? ArgBeginLoc : Args[i - 1]->getLocEnd(), - Args[i]->getLocStart()); - BeforeArgument = Lexer::makeFileCharRange( - BeforeArgument, Ctx->getSourceManager(), Ctx->getLangOpts()); + SourceLocation BeginSLoc, EndSLoc = Args[i]->getLocStart(); + if (i == 0) + BeginSLoc = ArgBeginLoc; + else + BeginSLoc = Args[i - 1]->getLocEnd(); + if (BeginSLoc.isMacroID() || EndSLoc.isMacroID()) + continue; - for (auto Comment : getCommentsInRange(Ctx, BeforeArgument)) { + for (auto Comment : + getCommentsInRange(Ctx, SourceRange(BeginSLoc, EndSLoc))) { llvm::SmallVector Matches; if (IdentRE.match(Comment.second, &Matches)) { if (Matches[2] != II->getName()) { Index: clang-tidy/misc/AssertSideEffectCheck.h =================================================================== --- clang-tidy/misc/AssertSideEffectCheck.h +++ clang-tidy/misc/AssertSideEffectCheck.h @@ -17,7 +17,6 @@ namespace clang { namespace tidy { -namespace misc { /// Finds `assert()` with side effect. /// @@ -45,7 +44,6 @@ SmallVector AssertMacros; }; -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/AssertSideEffectCheck.cpp =================================================================== --- clang-tidy/misc/AssertSideEffectCheck.cpp +++ clang-tidy/misc/AssertSideEffectCheck.cpp @@ -21,9 +21,6 @@ using namespace clang::ast_matchers; namespace clang { -namespace tidy { -namespace misc { - namespace { AST_MATCHER_P(Expr, hasSideEffect, bool, CheckFunctionCalls) { @@ -69,6 +66,8 @@ } // namespace +namespace tidy { + AssertSideEffectCheck::AssertSideEffectCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), @@ -122,6 +121,5 @@ diag(Loc, "found %0() with side effect") << AssertMacroName; } -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/AssignOperatorSignatureCheck.h =================================================================== --- /dev/null +++ clang-tidy/misc/AssignOperatorSignatureCheck.h @@ -0,0 +1,37 @@ +//===--- AssignOperatorSignatureCheck.h - clang-tidy ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_ASSIGNOPERATORSIGNATURECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_ASSIGNOPERATORSIGNATURECHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace misc { + +/// Finds declarations of assign operators with the wrong return and/or argument +/// types. +/// +/// * The return type must be `Class&`. +/// * Works with move-assign and assign by value. +/// * Private and deleted operators are ignored. +class AssignOperatorSignatureCheck : public ClangTidyCheck { +public: + AssignOperatorSignatureCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace misc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_ASSIGNOPERATORSIGNATURECHECK_H Index: clang-tidy/misc/AssignOperatorSignatureCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/misc/AssignOperatorSignatureCheck.cpp @@ -0,0 +1,102 @@ +//===--- AssignOperatorSignatureCheck.cpp - clang-tidy ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AssignOperatorSignatureCheck.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace misc { + +void AssignOperatorSignatureCheck::registerMatchers( + ast_matchers::MatchFinder *Finder) { + // Only register the matchers for C++; the functionality currently does not + // provide any benefit to other languages, despite being benign. + if (!getLangOpts().CPlusPlus) + return; + + const auto HasGoodReturnType = cxxMethodDecl(returns( + lValueReferenceType(pointee(unless(isConstQualified()), + hasDeclaration(equalsBoundNode("class")))))); + + const auto IsSelf = qualType( + anyOf(hasDeclaration(equalsBoundNode("class")), + referenceType(pointee(hasDeclaration(equalsBoundNode("class")))))); + const auto IsAssign = + cxxMethodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())), + hasName("operator="), ofClass(recordDecl().bind("class"))) + .bind("method"); + const auto IsSelfAssign = + cxxMethodDecl(IsAssign, hasParameter(0, parmVarDecl(hasType(IsSelf)))) + .bind("method"); + + Finder->addMatcher( + cxxMethodDecl(IsAssign, unless(HasGoodReturnType)).bind("ReturnType"), + this); + + const auto BadSelf = referenceType( + anyOf(lValueReferenceType(pointee(unless(isConstQualified()))), + rValueReferenceType(pointee(isConstQualified())))); + + Finder->addMatcher( + cxxMethodDecl(IsSelfAssign, + hasParameter(0, parmVarDecl(hasType(BadSelf)))) + .bind("ArgumentType"), + this); + + Finder->addMatcher( + cxxMethodDecl(IsSelfAssign, anyOf(isConst(), isVirtual())).bind("cv"), + this); + + Finder->addMatcher( + cxxMethodDecl(IsSelfAssign, isDefinition(), unless(hasDescendant(returnStmt()))) + .bind("NoReturn"), + this); + + const auto GoodReturn = + returnStmt(unless(has(unaryOperator(hasOperatorName("*"), + hasUnaryOperand(cxxThisExpr()))))) + .bind("ReturnThis"); + + Finder->addMatcher(cxxMethodDecl(IsSelfAssign, forEachDescendant(GoodReturn)), + this); + +} + +void AssignOperatorSignatureCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *Method = Result.Nodes.getNodeAs("method"); + std::string Name = Method->getParent()->getName(); + + static const char *const Messages[][2] = { + {"ReturnType", "operator=() should return '%0&'"}, + {"ArgumentType", "operator=() should take '%0 const&', '%0&&' or '%0'"}, + {"cv", "operator=() should not be marked '%1'"}, + {"NoReturn", "operator=() should return *this"} + }; + + for (const auto &Message : Messages) { + if (Result.Nodes.getNodeAs(Message[0])) + diag(Method->getLocStart(), Message[1]) + << Name << (Method->isConst() ? "const" : "virtual"); + } + + const auto* Retstmt = Result.Nodes.getNodeAs("ReturnThis"); + if (Retstmt) { + const auto Location = Retstmt->getRetValue()->getLocStart(); + diag(Location, Messages[3][1]); + } +} + +} // namespace misc +} // namespace tidy +} // namespace clang Index: clang-tidy/misc/BoolPointerImplicitConversionCheck.cpp =================================================================== --- clang-tidy/misc/BoolPointerImplicitConversionCheck.cpp +++ clang-tidy/misc/BoolPointerImplicitConversionCheck.cpp @@ -12,6 +12,14 @@ using namespace clang::ast_matchers; namespace clang { +namespace { + +AST_MATCHER(CastExpr, isPointerToBoolean) { + return Node.getCastKind() == CK_PointerToBoolean; +} + +} // namespace + namespace tidy { namespace misc { @@ -24,7 +32,7 @@ hasSourceExpression(expr( hasType(pointerType(pointee(booleanType()))), ignoringParenImpCasts(declRefExpr().bind("expr")))), - hasCastKind(CK_PointerToBoolean))))), + isPointerToBoolean())))), unless(isInTemplateInstantiation())).bind("if"), this); } @@ -47,18 +55,15 @@ auto DeclRef = ignoringParenImpCasts(declRefExpr(to(equalsNode(D)))); if (!match(findAll( unaryOperator(hasOperatorName("*"), hasUnaryOperand(DeclRef))), - *If, *Result.Context) - .empty() || + *If, *Result.Context).empty() || !match(findAll(arraySubscriptExpr(hasBase(DeclRef))), *If, - *Result.Context) - .empty() || + *Result.Context).empty() || // FIXME: We should still warn if the paremater is implicitly converted to // bool. !match(findAll(callExpr(hasAnyArgument(ignoringParenImpCasts(DeclRef)))), *If, *Result.Context) .empty() || - !match(findAll(cxxDeleteExpr(has(ignoringParenImpCasts(expr(DeclRef))))), - *If, *Result.Context) + !match(findAll(cxxDeleteExpr(has(expr(DeclRef)))), *If, *Result.Context) .empty()) return; Index: clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tidy/misc/CMakeLists.txt +++ clang-tidy/misc/CMakeLists.txt @@ -3,8 +3,7 @@ add_clang_library(clangTidyMiscModule ArgumentCommentCheck.cpp AssertSideEffectCheck.cpp - MisplacedConstCheck.cpp - UnconventionalAssignOperatorCheck.cpp + AssignOperatorSignatureCheck.cpp BoolPointerImplicitConversionCheck.cpp DanglingHandleCheck.cpp DefinitionsInHeadersCheck.cpp @@ -51,5 +50,4 @@ clangLex clangTidy clangTidyUtils - clangTooling ) Index: clang-tidy/misc/DanglingHandleCheck.cpp =================================================================== --- clang-tidy/misc/DanglingHandleCheck.cpp +++ clang-tidy/misc/DanglingHandleCheck.cpp @@ -8,13 +8,10 @@ //===----------------------------------------------------------------------===// #include "DanglingHandleCheck.h" -#include "../utils/Matchers.h" -#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" using namespace clang::ast_matchers; -using namespace clang::tidy::matchers; namespace clang { namespace tidy { @@ -22,15 +19,29 @@ namespace { +static const char HandleClassesDelimiter[] = ";"; + +std::vector parseClasses(StringRef Option) { + SmallVector Classes; + Option.split(Classes, HandleClassesDelimiter); + std::vector Result; + for (StringRef &Class : Classes) { + Class = Class.trim(); + if (!Class.empty()) + Result.push_back(Class); + } + return Result; +} + ast_matchers::internal::BindableMatcher -handleFrom(const ast_matchers::internal::Matcher &IsAHandle, - const ast_matchers::internal::Matcher &Arg) { +handleFrom(ast_matchers::internal::Matcher IsAHandle, + ast_matchers::internal::Matcher Arg) { return cxxConstructExpr(hasDeclaration(cxxMethodDecl(ofClass(IsAHandle))), hasArgument(0, Arg)); } ast_matchers::internal::Matcher handleFromTemporaryValue( - const ast_matchers::internal::Matcher &IsAHandle) { + ast_matchers::internal::Matcher IsAHandle) { // If a ternary operator returns a temporary value, then both branches hold a // temporary value. If one of them is not a temporary then it must be copied // into one to satisfy the type of the operator. @@ -56,8 +67,8 @@ "::std::unordered_multimap"); } -ast_matchers::internal::BindableMatcher makeContainerMatcher( - const ast_matchers::internal::Matcher &IsAHandle) { +ast_matchers::internal::BindableMatcher +makeContainerMatcher(ast_matchers::internal::Matcher IsAHandle) { // This matcher could be expanded to detect: // - Constructors: eg. vector(3, string("A")); // - emplace*(): This requires a different logic to determine that @@ -86,7 +97,7 @@ DanglingHandleCheck::DanglingHandleCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), - HandleClasses(utils::options::parseStringList(Options.get( + HandleClasses(parseClasses(Options.get( "HandleClasses", "std::basic_string_view;std::experimental::basic_string_view"))), IsAHandle(cxxRecordDecl(hasAnyName(std::vector( @@ -95,7 +106,8 @@ void DanglingHandleCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "HandleClasses", - utils::options::serializeStringList(HandleClasses)); + llvm::join(HandleClasses.begin(), HandleClasses.end(), + HandleClassesDelimiter)); } void DanglingHandleCheck::registerMatchersForVariables(MatchFinder *Finder) { @@ -105,17 +117,15 @@ Finder->addMatcher( varDecl(hasType(cxxRecordDecl(IsAHandle)), hasInitializer( - exprWithCleanups(has(ignoringParenImpCasts(ConvertedHandle))) - .bind("bad_stmt"))), + exprWithCleanups(has(ConvertedHandle)).bind("bad_stmt"))), this); // Find 'Handle foo = ReturnsAValue();' Finder->addMatcher( - varDecl( - hasType(cxxRecordDecl(IsAHandle)), unless(parmVarDecl()), - hasInitializer(exprWithCleanups(has(ignoringParenImpCasts(handleFrom( - IsAHandle, ConvertedHandle)))) - .bind("bad_stmt"))), + varDecl(hasType(cxxRecordDecl(IsAHandle)), unless(parmVarDecl()), + hasInitializer( + exprWithCleanups(has(handleFrom(IsAHandle, ConvertedHandle))) + .bind("bad_stmt"))), this); // Find 'foo = ReturnsAValue(); // foo is Handle' Finder->addMatcher( @@ -137,7 +147,7 @@ // 1. Value to Handle conversion. // 2. Handle copy construction. // We have to match both. - has(ignoringImplicit(handleFrom( + has(handleFrom( IsAHandle, handleFrom(IsAHandle, declRefExpr(to(varDecl( // Is function scope ... @@ -145,7 +155,7 @@ // ... and it is a local array or Value. anyOf(hasType(arrayType()), hasType(recordDecl( - unless(IsAHandle))))))))))), + unless(IsAHandle)))))))))), // Temporary fix for false positives inside lambdas. unless(hasAncestor(lambdaExpr()))) .bind("bad_stmt"), @@ -153,9 +163,8 @@ // Return a temporary. Finder->addMatcher( - returnStmt( - has(ignoringParenImpCasts(exprWithCleanups(has(ignoringParenImpCasts( - handleFrom(IsAHandle, handleFromTemporaryValue(IsAHandle)))))))) + returnStmt(has(exprWithCleanups(has(handleFrom( + IsAHandle, handleFromTemporaryValue(IsAHandle)))))) .bind("bad_stmt"), this); } Index: clang-tidy/misc/DefinitionsInHeadersCheck.cpp =================================================================== --- clang-tidy/misc/DefinitionsInHeadersCheck.cpp +++ clang-tidy/misc/DefinitionsInHeadersCheck.cpp @@ -53,17 +53,15 @@ void DefinitionsInHeadersCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; - auto DefinitionMatcher = - anyOf(functionDecl(isDefinition(), unless(isDeleted())), - varDecl(isDefinition())); if (UseHeaderFileExtension) { - Finder->addMatcher(namedDecl(DefinitionMatcher, - usesHeaderFileExtension(HeaderFileExtensions)) - .bind("name-decl"), - this); + Finder->addMatcher( + namedDecl(anyOf(functionDecl(isDefinition()), varDecl(isDefinition())), + usesHeaderFileExtension(HeaderFileExtensions)) + .bind("name-decl"), + this); } else { Finder->addMatcher( - namedDecl(DefinitionMatcher, + namedDecl(anyOf(functionDecl(isDefinition()), varDecl(isDefinition())), anyOf(usesHeaderFileExtension(HeaderFileExtensions), unless(isExpansionInMainFile()))) .bind("name-decl"), @@ -72,10 +70,6 @@ } void DefinitionsInHeadersCheck::check(const MatchFinder::MatchResult &Result) { - // Don't run the check in failing TUs. - if (Result.Context->getDiagnostics().hasErrorOccurred()) - return; - // C++ [basic.def.odr] p6: // There can be more than one definition of a class type, enumeration type, // inline function with external linkage, class template, non-static function Index: clang-tidy/misc/InaccurateEraseCheck.cpp =================================================================== --- clang-tidy/misc/InaccurateEraseCheck.cpp +++ clang-tidy/misc/InaccurateEraseCheck.cpp @@ -25,20 +25,19 @@ return; const auto CheckForEndCall = hasArgument( - 1, anyOf(cxxConstructExpr(has(ignoringParenImpCasts( - cxxMemberCallExpr(callee(cxxMethodDecl(hasName("end")))) - .bind("InaccEndCall")))), + 1, anyOf(cxxConstructExpr( + has(cxxMemberCallExpr(callee(cxxMethodDecl(hasName("end")))) + .bind("InaccEndCall"))), anything())); Finder->addMatcher( cxxMemberCallExpr( on(hasType(namedDecl(matchesName("^::std::")))), callee(cxxMethodDecl(hasName("erase"))), argumentCountIs(1), - hasArgument(0, has(ignoringParenImpCasts( - callExpr(callee(functionDecl(matchesName( + hasArgument(0, has(callExpr(callee(functionDecl(matchesName( "^::std::(remove(_if)?|unique)$"))), CheckForEndCall) - .bind("InaccAlgCall")))), + .bind("InaccAlgCall"))), unless(isInTemplateInstantiation())) .bind("InaccErase"), this); Index: clang-tidy/misc/IncorrectRoundings.cpp =================================================================== --- clang-tidy/misc/IncorrectRoundings.cpp +++ clang-tidy/misc/IncorrectRoundings.cpp @@ -14,13 +14,8 @@ #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Lex/Lexer.h" -using namespace clang::ast_matchers; - namespace clang { -namespace tidy { -namespace misc { - -namespace { +namespace ast_matchers { AST_MATCHER(FloatingLiteral, floatHalf) { const auto &literal = Node.getValue(); if ((&Node.getSemantics()) == &llvm::APFloat::IEEEsingle) @@ -29,9 +24,14 @@ return literal.convertToDouble() == 0.5; return false; } -} // namespace +} // namespace ast_matchers +} // namespace clang +using namespace clang::ast_matchers; +namespace clang { +namespace tidy { +namespace misc { void IncorrectRoundings::registerMatchers(MatchFinder *MatchFinder) { // Match a floating literal with value 0.5. auto FloatHalf = floatLiteral(floatHalf()); @@ -42,8 +42,7 @@ // Match a floating literal of 0.5 or a floating literal of 0.5 implicitly. // cast to floating type. auto FloatOrCastHalf = - anyOf(FloatHalf, - implicitCastExpr(FloatType, has(ignoringParenImpCasts(FloatHalf)))); + anyOf(FloatHalf, implicitCastExpr(FloatType, has(FloatHalf))); // Match if either the LHS or RHS is a floating literal of 0.5 or a floating // literal of 0.5 and the other is of type double or vice versa. Index: clang-tidy/misc/InefficientAlgorithmCheck.cpp =================================================================== --- clang-tidy/misc/InefficientAlgorithmCheck.cpp +++ clang-tidy/misc/InefficientAlgorithmCheck.cpp @@ -45,19 +45,18 @@ callExpr( callee(functionDecl(Algorithms)), hasArgument( - 0, cxxConstructExpr(has(ignoringParenImpCasts(cxxMemberCallExpr( + 0, cxxConstructExpr(has(cxxMemberCallExpr( callee(cxxMethodDecl(hasName("begin"))), on(declRefExpr( hasDeclaration(decl().bind("IneffContObj")), anyOf(hasType(ContainerMatcher.bind("IneffCont")), hasType(pointsTo( ContainerMatcher.bind("IneffContPtr"))))) - .bind("IneffContExpr"))))))), - hasArgument( - 1, cxxConstructExpr(has(ignoringParenImpCasts(cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("end"))), - on(declRefExpr( - hasDeclaration(equalsBoundNode("IneffContObj"))))))))), + .bind("IneffContExpr")))))), + hasArgument(1, cxxConstructExpr(has(cxxMemberCallExpr( + callee(cxxMethodDecl(hasName("end"))), + on(declRefExpr(hasDeclaration( + equalsBoundNode("IneffContObj")))))))), hasArgument(2, expr().bind("AlgParam")), unless(isInTemplateInstantiation())) .bind("IneffAlg"); Index: clang-tidy/misc/MacroParenthesesCheck.h =================================================================== --- clang-tidy/misc/MacroParenthesesCheck.h +++ clang-tidy/misc/MacroParenthesesCheck.h @@ -14,7 +14,6 @@ namespace clang { namespace tidy { -namespace misc { /// Finds macros that can have unexpected behaviour due to missing parentheses. /// @@ -36,7 +35,6 @@ void registerPPCallbacks(CompilerInstance &Compiler) override; }; -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/MacroParenthesesCheck.cpp =================================================================== --- clang-tidy/misc/MacroParenthesesCheck.cpp +++ clang-tidy/misc/MacroParenthesesCheck.cpp @@ -14,12 +14,12 @@ namespace clang { namespace tidy { -namespace misc { namespace { class MacroParenthesesPPCallbacks : public PPCallbacks { public: - MacroParenthesesPPCallbacks(Preprocessor *PP, MacroParenthesesCheck *Check) + MacroParenthesesPPCallbacks(Preprocessor *PP, + MacroParenthesesCheck *Check) : PP(PP), Check(Check) {} void MacroDefined(const Token &MacroNameTok, @@ -66,46 +66,8 @@ tok::amp, tok::pipe, tok::caret); } -/// Is given Token a keyword that is used in variable declarations? -static bool isVarDeclKeyword(const Token &T) { - return T.isOneOf(tok::kw_bool, tok::kw_char, tok::kw_short, tok::kw_int, - tok::kw_long, tok::kw_float, tok::kw_double, tok::kw_const, - tok::kw_enum, tok::kw_inline, tok::kw_static, tok::kw_struct, - tok::kw_signed, tok::kw_unsigned); -} - -/// Is there a possible variable declaration at Tok? -static bool possibleVarDecl(const MacroInfo *MI, const Token *Tok) { - if (Tok == MI->tokens_end()) - return false; - - // If we see int/short/struct/etc., just assume this is a variable declaration. - if (isVarDeclKeyword(*Tok)) - return true; - - // Variable declarations start with identifier or coloncolon. - if (!Tok->isOneOf(tok::identifier, tok::raw_identifier, tok::coloncolon)) - return false; - - // Skip possible types, etc - while ( - Tok != MI->tokens_end() && - Tok->isOneOf(tok::identifier, tok::raw_identifier, tok::coloncolon, - tok::star, tok::amp, tok::ampamp, tok::less, tok::greater)) - Tok++; - - // Return true for possible variable declarations. - return Tok == MI->tokens_end() || - Tok->isOneOf(tok::equal, tok::semi, tok::l_square, tok::l_paren) || - isVarDeclKeyword(*Tok); -} - void MacroParenthesesPPCallbacks::replacementList(const Token &MacroNameTok, const MacroInfo *MI) { - // Make sure macro replacement isn't a variable declaration. - if (possibleVarDecl(MI, MI->tokens_begin())) - return; - // Count how deep we are in parentheses/braces/squares. int Count = 0; @@ -154,9 +116,6 @@ void MacroParenthesesPPCallbacks::argument(const Token &MacroNameTok, const MacroInfo *MI) { - - // Skip variable declaration. - bool VarDecl = possibleVarDecl(MI, MI->tokens_begin()); for (auto TI = MI->tokens_begin(), TE = MI->tokens_end(); TI != TE; ++TI) { // First token. @@ -172,13 +131,6 @@ const Token &Tok = *TI; - // There should not be extra parentheses in possible variable declaration. - if (VarDecl) { - if (Tok.isOneOf(tok::equal, tok::semi, tok::l_square, tok::l_paren)) - VarDecl = false; - continue; - } - // Only interested in identifiers. if (!Tok.isOneOf(tok::identifier, tok::raw_identifier)) continue; @@ -231,14 +183,6 @@ Next.isOneOf(tok::comma, tok::greater)) continue; - // Namespaces. - if (Prev.is(tok::kw_namespace)) - continue; - - // Variadic templates - if (MI->isVariadic()) - continue; - Check->diag(Tok.getLocation(), "macro argument should be enclosed in " "parentheses") << FixItHint::CreateInsertion(Tok.getLocation(), "(") @@ -254,6 +198,5 @@ &Compiler.getPreprocessor(), this)); } -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tidy/misc/MiscTidyModule.cpp +++ clang-tidy/misc/MiscTidyModule.cpp @@ -12,8 +12,7 @@ #include "../ClangTidyModuleRegistry.h" #include "ArgumentCommentCheck.h" #include "AssertSideEffectCheck.h" -#include "MisplacedConstCheck.h" -#include "UnconventionalAssignOperatorCheck.h" +#include "AssignOperatorSignatureCheck.h" #include "BoolPointerImplicitConversionCheck.h" #include "DanglingHandleCheck.h" #include "DefinitionsInHeadersCheck.h" @@ -62,10 +61,8 @@ CheckFactories.registerCheck("misc-argument-comment"); CheckFactories.registerCheck( "misc-assert-side-effect"); - CheckFactories.registerCheck( - "misc-misplaced-const"); - CheckFactories.registerCheck( - "misc-unconventional-assign-operator"); + CheckFactories.registerCheck( + "misc-assign-operator-signature"); CheckFactories.registerCheck( "misc-bool-pointer-implicit-conversion"); CheckFactories.registerCheck( Index: clang-tidy/misc/MisplacedConstCheck.h =================================================================== --- clang-tidy/misc/MisplacedConstCheck.h +++ /dev/null @@ -1,36 +0,0 @@ -//===--- MisplacedConstCheck.h - clang-tidy----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MISPLACED_CONST_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MISPLACED_CONST_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace misc { - -/// This check diagnoses when a const qualifier is applied to a typedef to a -/// pointer type rather than to the pointee. -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/misc-misplaced-const.html -class MisplacedConstCheck : public ClangTidyCheck { -public: - MisplacedConstCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -}; - -} // namespace misc -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MISPLACED_CONST_H Index: clang-tidy/misc/MisplacedConstCheck.cpp =================================================================== --- clang-tidy/misc/MisplacedConstCheck.cpp +++ /dev/null @@ -1,63 +0,0 @@ -//===--- MisplacedConstCheck.cpp - clang-tidy------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "MisplacedConstCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace misc { - -void MisplacedConstCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher( - valueDecl(hasType(isConstQualified()), - hasType(typedefType(hasDeclaration( - typedefDecl(hasType(pointerType(unless(pointee( - anyOf(isConstQualified(), - ignoringParens(functionType()))))))) - .bind("typedef"))))) - .bind("decl"), - this); -} - -static QualType guessAlternateQualification(ASTContext &Context, QualType QT) { - // We're given a QualType from a typedef where the qualifiers apply to the - // pointer instead of the pointee. Strip the const qualifier from the pointer - // type and add it to the pointee instead. - if (!QT->isPointerType()) - return QT; - - Qualifiers Quals = QT.getLocalQualifiers(); - Quals.removeConst(); - - QualType NewQT = Context.getPointerType( - QualType(QT->getPointeeType().getTypePtr(), Qualifiers::Const)); - return NewQT.withCVRQualifiers(Quals.getCVRQualifiers()); -} - -void MisplacedConstCheck::check(const MatchFinder::MatchResult &Result) { - const auto *Var = Result.Nodes.getNodeAs("decl"); - const auto *Typedef = Result.Nodes.getNodeAs("typedef"); - ASTContext &Ctx = *Result.Context; - QualType CanQT = Var->getType().getCanonicalType(); - - diag(Var->getLocation(), "%0 declared with a const-qualified typedef type; " - "results in the type being '%1' instead of '%2'") - << Var << CanQT.getAsString(Ctx.getPrintingPolicy()) - << guessAlternateQualification(Ctx, CanQT) - .getAsString(Ctx.getPrintingPolicy()); - diag(Typedef->getLocation(), "typedef declared here", DiagnosticIDs::Note); -} - -} // namespace misc -} // namespace tidy -} // namespace clang Index: clang-tidy/misc/MisplacedWideningCastCheck.cpp =================================================================== --- clang-tidy/misc/MisplacedWideningCastCheck.cpp +++ clang-tidy/misc/MisplacedWideningCastCheck.cpp @@ -37,11 +37,10 @@ hasType(isInteger())) .bind("Calc"); - const auto ExplicitCast = explicitCastExpr(hasDestinationType(isInteger()), - has(ignoringParenImpCasts(Calc))); + const auto ExplicitCast = + explicitCastExpr(hasDestinationType(isInteger()), has(Calc)); const auto ImplicitCast = - implicitCastExpr(hasImplicitDestinationType(isInteger()), - has(ignoringParenImpCasts(Calc))); + implicitCastExpr(hasImplicitDestinationType(isInteger()), has(Calc)); const auto Cast = expr(anyOf(ExplicitCast, ImplicitCast)).bind("Cast"); Finder->addMatcher(varDecl(hasInitializer(Cast)), this); Index: clang-tidy/misc/MoveConstantArgumentCheck.h =================================================================== --- clang-tidy/misc/MoveConstantArgumentCheck.h +++ clang-tidy/misc/MoveConstantArgumentCheck.h @@ -1,4 +1,4 @@ -//===--- MoveConstantArgumentCheck.h - clang-tidy -------------------------===// +//===--- MoveConstandArgumentCheck.h - clang-tidy -------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTANTARGUMENTCHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTANTARGUMENTCHECK_H +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONTANTARGUMENTCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONTANTARGUMENTCHECK_H #include "../ClangTidy.h" @@ -28,4 +28,4 @@ } // namespace tidy } // namespace clang -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTANTARGUMENTCHECK_H +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONTANTARGUMENTCHECK_H Index: clang-tidy/misc/MoveConstantArgumentCheck.cpp =================================================================== --- clang-tidy/misc/MoveConstantArgumentCheck.cpp +++ clang-tidy/misc/MoveConstantArgumentCheck.cpp @@ -1,4 +1,4 @@ -//===--- MoveConstantArgumentCheck.cpp - clang-tidy -----------------------===// +//===--- MoveConstandArgumentCheck.cpp - clang-tidy -----------------------===// // // The LLVM Compiler Infrastructure // @@ -9,70 +9,38 @@ #include "MoveConstantArgumentCheck.h" -#include "clang/Lex/Lexer.h" - -using namespace clang::ast_matchers; +#include namespace clang { namespace tidy { namespace misc { -static void ReplaceCallWithArg(const CallExpr *Call, DiagnosticBuilder &Diag, - const SourceManager &SM, - const LangOptions &LangOpts) { - const Expr *Arg = Call->getArg(0); - - CharSourceRange BeforeArgumentsRange = Lexer::makeFileCharRange( - CharSourceRange::getCharRange(Call->getLocStart(), Arg->getLocStart()), - SM, LangOpts); - CharSourceRange AfterArgumentsRange = Lexer::makeFileCharRange( - CharSourceRange::getCharRange(Call->getLocEnd(), - Call->getLocEnd().getLocWithOffset(1)), - SM, LangOpts); - - if (BeforeArgumentsRange.isValid() && AfterArgumentsRange.isValid()) { - Diag << FixItHint::CreateRemoval(BeforeArgumentsRange) - << FixItHint::CreateRemoval(AfterArgumentsRange); - } -} +using namespace ast_matchers; void MoveConstantArgumentCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; - - auto MoveCallMatcher = - callExpr(callee(functionDecl(hasName("::std::move"))), argumentCountIs(1), - unless(isInTemplateInstantiation())) - .bind("call-move"); - - Finder->addMatcher(MoveCallMatcher, this); - - auto ConstParamMatcher = forEachArgumentWithParam( - MoveCallMatcher, parmVarDecl(hasType(references(isConstQualified())))); - - Finder->addMatcher(callExpr(ConstParamMatcher).bind("receiving-expr"), this); - Finder->addMatcher(cxxConstructExpr(ConstParamMatcher).bind("receiving-expr"), + Finder->addMatcher(callExpr(callee(functionDecl(hasName("::std::move"))), + argumentCountIs(1), + unless(isInTemplateInstantiation())) + .bind("call-move"), this); } void MoveConstantArgumentCheck::check(const MatchFinder::MatchResult &Result) { const auto *CallMove = Result.Nodes.getNodeAs("call-move"); - const auto *ReceivingExpr = Result.Nodes.getNodeAs("receiving-expr"); const Expr *Arg = CallMove->getArg(0); SourceManager &SM = Result.Context->getSourceManager(); - CharSourceRange MoveRange = - CharSourceRange::getCharRange(CallMove->getSourceRange()); - CharSourceRange FileMoveRange = - Lexer::makeFileCharRange(MoveRange, SM, getLangOpts()); - if (!FileMoveRange.isValid()) - return; - bool IsConstArg = Arg->getType().isConstQualified(); bool IsTriviallyCopyable = Arg->getType().isTriviallyCopyableType(*Result.Context); if (IsConstArg || IsTriviallyCopyable) { + auto MoveRange = CharSourceRange::getCharRange(CallMove->getSourceRange()); + auto FileMoveRange = Lexer::makeFileCharRange(MoveRange, SM, getLangOpts()); + if (!FileMoveRange.isValid()) + return; bool IsVariable = isa(Arg); auto Diag = diag(FileMoveRange.getBegin(), "std::move of the %select{|const }0" @@ -81,13 +49,19 @@ "has no effect; remove std::move()") << IsConstArg << IsVariable << IsTriviallyCopyable; - ReplaceCallWithArg(CallMove, Diag, SM, getLangOpts()); - } else if (ReceivingExpr) { - auto Diag = diag(FileMoveRange.getBegin(), - "passing result of std::move() as a const reference " - "argument; no move will actually happen"); - - ReplaceCallWithArg(CallMove, Diag, SM, getLangOpts()); + auto BeforeArgumentsRange = Lexer::makeFileCharRange( + CharSourceRange::getCharRange(CallMove->getLocStart(), + Arg->getLocStart()), + SM, getLangOpts()); + auto AfterArgumentsRange = Lexer::makeFileCharRange( + CharSourceRange::getCharRange( + CallMove->getLocEnd(), CallMove->getLocEnd().getLocWithOffset(1)), + SM, getLangOpts()); + + if (BeforeArgumentsRange.isValid() && AfterArgumentsRange.isValid()) { + Diag << FixItHint::CreateRemoval(BeforeArgumentsRange) + << FixItHint::CreateRemoval(AfterArgumentsRange); + } } } Index: clang-tidy/misc/MoveConstructorInitCheck.h =================================================================== --- clang-tidy/misc/MoveConstructorInitCheck.h +++ clang-tidy/misc/MoveConstructorInitCheck.h @@ -17,7 +17,6 @@ namespace clang { namespace tidy { -namespace misc { /// The check flags user-defined move constructors that have a ctor-initializer /// initializing a member or base class through a copy constructor instead of a @@ -38,12 +37,11 @@ void handleParamNotMoved(const ast_matchers::MatchFinder::MatchResult &Result); - std::unique_ptr Inserter; - const utils::IncludeSorter::IncludeStyle IncludeStyle; + std::unique_ptr Inserter; + const IncludeSorter::IncludeStyle IncludeStyle; const bool UseCERTSemantics; }; -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/MoveConstructorInitCheck.cpp =================================================================== --- clang-tidy/misc/MoveConstructorInitCheck.cpp +++ clang-tidy/misc/MoveConstructorInitCheck.cpp @@ -19,7 +19,6 @@ namespace clang { namespace tidy { -namespace misc { namespace { @@ -42,9 +41,9 @@ MoveConstructorInitCheck::MoveConstructorInitCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), - IncludeStyle(utils::IncludeSorter::parseIncludeStyle( + IncludeStyle(IncludeSorter::parseIncludeStyle( Options.get("IncludeStyle", "llvm"))), - UseCERTSemantics(Options.get("UseCERTSemantics", 0) != 0) {} + UseCERTSemantics(Context->isCheckEnabled("cert-oop11-cpp")) {} void MoveConstructorInitCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++11; the functionality currently does not @@ -72,7 +71,7 @@ // This checker is also used to implement cert-oop11-cpp, but when using that // form of the checker, we do not want to diagnose movable parameters. - if (!UseCERTSemantics) { + if (!UseCERTSemantics) Finder->addMatcher( cxxConstructorDecl( allOf( @@ -89,7 +88,6 @@ .bind("init-arg"))))))) .bind("ctor-decl"), this); - } } void MoveConstructorInitCheck::check(const MatchFinder::MatchResult &Result) { @@ -110,9 +108,8 @@ if (parmVarDeclRefExprOccurences(*MovableParam, *ConstructorDecl, *Result.Context) > 1) return; - auto DiagOut = diag(InitArg->getLocStart(), - "value argument %0 can be moved to avoid copy") - << MovableParam; + auto DiagOut = + diag(InitArg->getLocStart(), "value argument can be moved to avoid copy"); DiagOut << FixItHint::CreateReplacement( InitArg->getSourceRange(), (Twine("std::move(") + MovableParam->getName() + ")").str()); @@ -169,17 +166,14 @@ } void MoveConstructorInitCheck::registerPPCallbacks(CompilerInstance &Compiler) { - Inserter.reset(new utils::IncludeInserter( - Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle)); + Inserter.reset(new IncludeInserter(Compiler.getSourceManager(), + Compiler.getLangOpts(), IncludeStyle)); Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks()); } void MoveConstructorInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { - Options.store(Opts, "IncludeStyle", - utils::IncludeSorter::toString(IncludeStyle)); - Options.store(Opts, "UseCERTSemantics", UseCERTSemantics ? 1 : 0); + Options.store(Opts, "IncludeStyle", IncludeSorter::toString(IncludeStyle)); } -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/NewDeleteOverloadsCheck.cpp =================================================================== --- clang-tidy/misc/NewDeleteOverloadsCheck.cpp +++ clang-tidy/misc/NewDeleteOverloadsCheck.cpp @@ -14,11 +14,7 @@ using namespace clang::ast_matchers; namespace clang { -namespace tidy { -namespace misc { - namespace { - AST_MATCHER(FunctionDecl, isPlacementOverload) { bool New; switch (Node.getOverloadedOperator()) { @@ -61,7 +57,12 @@ return true; } +} // namespace +namespace tidy { +namespace misc { + +namespace { OverloadedOperatorKind getCorrespondingOverload(const FunctionDecl *FD) { switch (FD->getOverloadedOperator()) { default: break; @@ -124,7 +125,6 @@ return false; } - } // anonymous namespace void NewDeleteOverloadsCheck::registerMatchers(MatchFinder *Finder) { Index: clang-tidy/misc/NoexceptMoveConstructorCheck.h =================================================================== --- clang-tidy/misc/NoexceptMoveConstructorCheck.h +++ clang-tidy/misc/NoexceptMoveConstructorCheck.h @@ -14,7 +14,6 @@ namespace clang { namespace tidy { -namespace misc { /// The check flags user-defined move constructors and assignment operators not /// marked with `noexcept` or marked with `noexcept(expr)` where `expr` @@ -31,7 +30,6 @@ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; }; -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/NoexceptMoveConstructorCheck.cpp =================================================================== --- clang-tidy/misc/NoexceptMoveConstructorCheck.cpp +++ clang-tidy/misc/NoexceptMoveConstructorCheck.cpp @@ -15,7 +15,6 @@ namespace clang { namespace tidy { -namespace misc { void NoexceptMoveConstructorCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++11; the functionality currently does not @@ -68,7 +67,6 @@ } } -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/NonCopyableObjects.h =================================================================== --- clang-tidy/misc/NonCopyableObjects.h +++ clang-tidy/misc/NonCopyableObjects.h @@ -14,7 +14,6 @@ namespace clang { namespace tidy { -namespace misc { /// The check flags dereferences and non-pointer declarations of objects that /// are not meant to be passed by value, such as C FILE objects. @@ -26,7 +25,6 @@ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; }; -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/NonCopyableObjects.cpp =================================================================== --- clang-tidy/misc/NonCopyableObjects.cpp +++ clang-tidy/misc/NonCopyableObjects.cpp @@ -15,9 +15,6 @@ using namespace clang::ast_matchers; namespace clang { -namespace tidy { -namespace misc { - namespace { // FIXME: it would be good to make a list that is also user-configurable so that // users can add their own elements to the list. However, it may require some @@ -52,6 +49,7 @@ } } // namespace +namespace tidy { void NonCopyableObjectsCheck::registerMatchers(MatchFinder *Finder) { // There are two ways to get into trouble with objects like FILE *: // dereferencing the pointer type to be a non-pointer type, and declaring @@ -93,7 +91,6 @@ << BD; } -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/RedundantExpressionCheck.h =================================================================== --- clang-tidy/misc/RedundantExpressionCheck.h +++ clang-tidy/misc/RedundantExpressionCheck.h @@ -26,11 +26,6 @@ : ClangTidyCheck(Name, Context) {} void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; - -private: - void checkArithmeticExpr(const ast_matchers::MatchFinder::MatchResult &R); - void checkBitwiseExpr(const ast_matchers::MatchFinder::MatchResult &R); - void checkRelationalExpr(const ast_matchers::MatchFinder::MatchResult &R); }; } // namespace misc Index: clang-tidy/misc/RedundantExpressionCheck.cpp =================================================================== --- clang-tidy/misc/RedundantExpressionCheck.cpp +++ clang-tidy/misc/RedundantExpressionCheck.cpp @@ -9,40 +9,16 @@ #include "RedundantExpressionCheck.h" #include "../utils/Matchers.h" -#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Lex/Lexer.h" using namespace clang::ast_matchers; -using namespace clang::tidy::matchers; namespace clang { namespace tidy { namespace misc { -namespace { -using llvm::APSInt; -} // namespace - -static const char KnownBannedMacroNames[] = - "EAGAIN;EWOULDBLOCK;SIGCLD;SIGCHLD;"; - -static bool incrementWithoutOverflow(const APSInt &Value, APSInt &Result) { - Result = Value; - ++Result; - return Value < Result; -} - -static bool areEquivalentNameSpecifier(const NestedNameSpecifier *Left, - const NestedNameSpecifier *Right) { - llvm::FoldingSetNodeID LeftID, RightID; - Left->Profile(LeftID); - Right->Profile(RightID); - return LeftID == RightID; -} - -static bool areEquivalentExpr(const Expr *Left, const Expr *Right) { +static bool AreIdenticalExpr(const Expr *Left, const Expr *Right) { if (!Left || !Right) return !Left && !Right; @@ -57,8 +33,8 @@ Expr::const_child_iterator LeftIter = Left->child_begin(); Expr::const_child_iterator RightIter = Right->child_begin(); while (LeftIter != Left->child_end() && RightIter != Right->child_end()) { - if (!areEquivalentExpr(dyn_cast(*LeftIter), - dyn_cast(*RightIter))) + if (!AreIdenticalExpr(dyn_cast(*LeftIter), + dyn_cast(*RightIter))) return false; ++LeftIter; ++RightIter; @@ -77,8 +53,7 @@ case Stmt::IntegerLiteralClass: { llvm::APInt LeftLit = cast(Left)->getValue(); llvm::APInt RightLit = cast(Right)->getValue(); - return LeftLit.getBitWidth() == RightLit.getBitWidth() && - LeftLit == RightLit; + return LeftLit.getBitWidth() == RightLit.getBitWidth() && LeftLit == RightLit; } case Stmt::FloatingLiteralClass: return cast(Left)->getValue().bitwiseIsEqual( @@ -87,13 +62,6 @@ return cast(Left)->getBytes() == cast(Right)->getBytes(); - case Stmt::DependentScopeDeclRefExprClass: - if (cast(Left)->getDeclName() != - cast(Right)->getDeclName()) - return false; - return areEquivalentNameSpecifier( - cast(Left)->getQualifier(), - cast(Right)->getQualifier()); case Stmt::DeclRefExprClass: return cast(Left)->getDecl() == cast(Right)->getDecl(); @@ -121,348 +89,22 @@ } } -// For a given expression 'x', returns whether the ranges covered by the -// relational operators are equivalent (i.e. x <= 4 is equivalent to x < 5). -static bool areEquivalentRanges(BinaryOperatorKind OpcodeLHS, - const APSInt &ValueLHS, - BinaryOperatorKind OpcodeRHS, - const APSInt &ValueRHS) { - assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 && - "Values must be ordered"); - // Handle the case where constants are the same: x <= 4 <==> x <= 4. - if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) - return OpcodeLHS == OpcodeRHS; - - // Handle the case where constants are off by one: x <= 4 <==> x < 5. - APSInt ValueLHS_plus1; - return ((OpcodeLHS == BO_LE && OpcodeRHS == BO_LT) || - (OpcodeLHS == BO_GT && OpcodeRHS == BO_GE)) && - incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) && - APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0; -} - -// For a given expression 'x', returns whether the ranges covered by the -// relational operators are fully disjoint (i.e. x < 4 and x > 7). -static bool areExclusiveRanges(BinaryOperatorKind OpcodeLHS, - const APSInt &ValueLHS, - BinaryOperatorKind OpcodeRHS, - const APSInt &ValueRHS) { - assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 && - "Values must be ordered"); - - // Handle cases where the constants are the same. - if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) { - switch (OpcodeLHS) { - case BO_EQ: - return OpcodeRHS == BO_NE || OpcodeRHS == BO_GT || OpcodeRHS == BO_LT; - case BO_NE: - return OpcodeRHS == BO_EQ; - case BO_LE: - return OpcodeRHS == BO_GT; - case BO_GE: - return OpcodeRHS == BO_LT; - case BO_LT: - return OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE; - case BO_GT: - return OpcodeRHS == BO_EQ || OpcodeRHS == BO_LT || OpcodeRHS == BO_LE; - default: - return false; - } - } - - // Handle cases where the constants are different. - if ((OpcodeLHS == BO_EQ || OpcodeLHS == BO_LE || OpcodeLHS == BO_LE) && - (OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE)) - return true; - - // Handle the case where constants are off by one: x > 5 && x < 6. - APSInt ValueLHS_plus1; - if (OpcodeLHS == BO_GT && OpcodeRHS == BO_LT && - incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) && - APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0) - return true; - - return false; -} - -// Returns whether the ranges covered by the union of both relational -// expressions covers the whole domain (i.e. x < 10 and x > 0). -static bool rangesFullyCoverDomain(BinaryOperatorKind OpcodeLHS, - const APSInt &ValueLHS, - BinaryOperatorKind OpcodeRHS, - const APSInt &ValueRHS) { - assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 && - "Values must be ordered"); - - // Handle cases where the constants are the same: x < 5 || x >= 5. - if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) { - switch (OpcodeLHS) { - case BO_EQ: - return OpcodeRHS == BO_NE; - case BO_NE: - return OpcodeRHS == BO_EQ; - case BO_LE: - return OpcodeRHS == BO_GT || OpcodeRHS == BO_GE; - case BO_LT: - return OpcodeRHS == BO_GE; - case BO_GE: - return OpcodeRHS == BO_LT || OpcodeRHS == BO_LE; - case BO_GT: - return OpcodeRHS == BO_LE; - default: - return false; - } - } - - // Handle the case where constants are off by one: x <= 4 || x >= 5. - APSInt ValueLHS_plus1; - if (OpcodeLHS == BO_LE && OpcodeRHS == BO_GE && - incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) && - APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0) - return true; - - // Handle cases where the constants are different: x > 4 || x <= 7. - if ((OpcodeLHS == BO_GT || OpcodeLHS == BO_GE) && - (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE)) - return true; - - return false; -} - -static bool rangeSubsumesRange(BinaryOperatorKind OpcodeLHS, - const APSInt &ValueLHS, - BinaryOperatorKind OpcodeRHS, - const APSInt &ValueRHS) { - int Comparison = APSInt::compareValues(ValueLHS, ValueRHS); - switch (OpcodeLHS) { - case BO_EQ: - return OpcodeRHS == BO_EQ && Comparison == 0; - case BO_NE: - return (OpcodeRHS == BO_NE && Comparison == 0) || - (OpcodeRHS == BO_EQ && Comparison != 0) || - (OpcodeRHS == BO_LT && Comparison >= 0) || - (OpcodeRHS == BO_LE && Comparison > 0) || - (OpcodeRHS == BO_GT && Comparison <= 0) || - (OpcodeRHS == BO_GE && Comparison < 0); - - case BO_LT: - return ((OpcodeRHS == BO_LT && Comparison >= 0) || - (OpcodeRHS == BO_LE && Comparison > 0) || - (OpcodeRHS == BO_EQ && Comparison > 0)); - case BO_GT: - return ((OpcodeRHS == BO_GT && Comparison <= 0) || - (OpcodeRHS == BO_GE && Comparison < 0) || - (OpcodeRHS == BO_EQ && Comparison < 0)); - case BO_LE: - return (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE || OpcodeRHS == BO_EQ) && - Comparison >= 0; - case BO_GE: - return (OpcodeRHS == BO_GT || OpcodeRHS == BO_GE || OpcodeRHS == BO_EQ) && - Comparison <= 0; - default: - return false; - } -} - -static void canonicalNegateExpr(BinaryOperatorKind &Opcode, APSInt &Value) { - if (Opcode == BO_Sub) { - Opcode = BO_Add; - Value = -Value; - } -} - -AST_MATCHER(Expr, isIntegerConstantExpr) { - if (Node.isInstantiationDependent()) - return false; - return Node.isIntegerConstantExpr(Finder->getASTContext()); -} - -// Returns a matcher for integer constant expression. -static ast_matchers::internal::Matcher -matchIntegerConstantExpr(StringRef Id) { - std::string CstId = (Id + "-const").str(); - return expr(isIntegerConstantExpr()).bind(CstId); -} - -// Retrieve the integer value matched by 'matchIntegerConstantExpr' with name -// 'Id' and store it into 'Value'. -static bool retrieveIntegerConstantExpr(const MatchFinder::MatchResult &Result, - StringRef Id, APSInt &Value) { - std::string CstId = (Id + "-const").str(); - const auto *CstExpr = Result.Nodes.getNodeAs(CstId); - return CstExpr && CstExpr->isIntegerConstantExpr(Value, *Result.Context); -} - -// Returns a matcher for a symbolic expression (any expression except ingeter -// constant expression). -static ast_matchers::internal::Matcher matchSymbolicExpr(StringRef Id) { - std::string SymId = (Id + "-sym").str(); - return ignoringParenImpCasts( - expr(unless(isIntegerConstantExpr())).bind(SymId)); -} - -// Retrieve the expression matched by 'matchSymbolicExpr' with name 'Id' and -// store it into 'SymExpr'. -static bool retrieveSymbolicExpr(const MatchFinder::MatchResult &Result, - StringRef Id, const Expr *&SymExpr) { - std::string SymId = (Id + "-sym").str(); - if (const auto *Node = Result.Nodes.getNodeAs(SymId)) { - SymExpr = Node; - return true; - } - return false; -} - -// Match a binary operator between a symbolic expression and an integer constant -// expression. -static ast_matchers::internal::Matcher -matchBinOpIntegerConstantExpr(StringRef Id) { - const auto BinOpCstExpr = - expr( - anyOf(binaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("|"), - hasOperatorName("&")), - hasEitherOperand(matchSymbolicExpr(Id)), - hasEitherOperand(matchIntegerConstantExpr(Id))), - binaryOperator(hasOperatorName("-"), - hasLHS(matchSymbolicExpr(Id)), - hasRHS(matchIntegerConstantExpr(Id))))) - .bind(Id); - return ignoringParenImpCasts(BinOpCstExpr); -} - -// Retrieve sub-expressions matched by 'matchBinOpIntegerConstantExpr' with -// name 'Id'. -static bool -retrieveBinOpIntegerConstantExpr(const MatchFinder::MatchResult &Result, - StringRef Id, BinaryOperatorKind &Opcode, - const Expr *&Symbol, APSInt &Value) { - if (const auto *BinExpr = Result.Nodes.getNodeAs(Id)) { - Opcode = BinExpr->getOpcode(); - return retrieveSymbolicExpr(Result, Id, Symbol) && - retrieveIntegerConstantExpr(Result, Id, Value); - } - return false; -} - -// Matches relational expression: 'Expr k' (i.e. x < 2, x != 3, 12 <= x). -static ast_matchers::internal::Matcher -matchRelationalIntegerConstantExpr(StringRef Id) { - std::string CastId = (Id + "-cast").str(); - std::string SwapId = (Id + "-swap").str(); - std::string NegateId = (Id + "-negate").str(); - - const auto RelationalExpr = ignoringParenImpCasts(binaryOperator( - isComparisonOperator(), expr().bind(Id), - anyOf(allOf(hasLHS(matchSymbolicExpr(Id)), - hasRHS(matchIntegerConstantExpr(Id))), - allOf(hasLHS(matchIntegerConstantExpr(Id)), - hasRHS(matchSymbolicExpr(Id)), expr().bind(SwapId))))); - - // A cast can be matched as a comparator to zero. (i.e. if (x) is equivalent - // to if (x != 0)). - const auto CastExpr = - implicitCastExpr(hasCastKind(CK_IntegralToBoolean), - hasSourceExpression(matchSymbolicExpr(Id))) - .bind(CastId); - - const auto NegateRelationalExpr = - unaryOperator(hasOperatorName("!"), - hasUnaryOperand(anyOf(CastExpr, RelationalExpr))) - .bind(NegateId); - - const auto NegateNegateRelationalExpr = - unaryOperator(hasOperatorName("!"), - hasUnaryOperand(unaryOperator( - hasOperatorName("!"), - hasUnaryOperand(anyOf(CastExpr, RelationalExpr))))); - - return anyOf(RelationalExpr, CastExpr, NegateRelationalExpr, - NegateNegateRelationalExpr); -} - -// Retrieve sub-expressions matched by 'matchRelationalIntegerConstantExpr' with -// name 'Id'. -static bool -retrieveRelationalIntegerConstantExpr(const MatchFinder::MatchResult &Result, - StringRef Id, const Expr *&OperandExpr, - BinaryOperatorKind &Opcode, - const Expr *&Symbol, APSInt &Value) { - std::string CastId = (Id + "-cast").str(); - std::string SwapId = (Id + "-swap").str(); - std::string NegateId = (Id + "-negate").str(); - - if (const auto *Bin = Result.Nodes.getNodeAs(Id)) { - // Operand received with explicit comparator. - Opcode = Bin->getOpcode(); - OperandExpr = Bin; - if (!retrieveIntegerConstantExpr(Result, Id, Value)) - return false; - } else if (const auto *Cast = Result.Nodes.getNodeAs(CastId)) { - // Operand received with implicit comparator (cast). - Opcode = BO_NE; - OperandExpr = Cast; - Value = APSInt(32, 0); - } else { - return false; - } - - if (!retrieveSymbolicExpr(Result, Id, Symbol)) - return false; - - if (Result.Nodes.getNodeAs(SwapId)) - Opcode = BinaryOperator::reverseComparisonOp(Opcode); - if (Result.Nodes.getNodeAs(NegateId)) - Opcode = BinaryOperator::negateComparisonOp(Opcode); - - return true; -} - -AST_MATCHER(BinaryOperator, operandsAreEquivalent) { - return areEquivalentExpr(Node.getLHS(), Node.getRHS()); -} - -AST_MATCHER(ConditionalOperator, expressionsAreEquivalent) { - return areEquivalentExpr(Node.getTrueExpr(), Node.getFalseExpr()); -} - -AST_MATCHER(CallExpr, parametersAreEquivalent) { - return Node.getNumArgs() == 2 && - areEquivalentExpr(Node.getArg(0), Node.getArg(1)); +AST_MATCHER(BinaryOperator, OperandsAreEquivalent) { + return AreIdenticalExpr(Node.getLHS(), Node.getRHS()); } -AST_MATCHER(BinaryOperator, binaryOperatorIsInMacro) { +AST_MATCHER(BinaryOperator, isInMacro) { return Node.getOperatorLoc().isMacroID(); } -AST_MATCHER(ConditionalOperator, conditionalOperatorIsInMacro) { - return Node.getQuestionLoc().isMacroID() || Node.getColonLoc().isMacroID(); -} - -AST_MATCHER(Expr, isMacro) { return Node.getExprLoc().isMacroID(); } - -AST_MATCHER_P(Expr, expandedByMacro, std::set, Names) { - const SourceManager &SM = Finder->getASTContext().getSourceManager(); - const LangOptions &LO = Finder->getASTContext().getLangOpts(); - SourceLocation Loc = Node.getExprLoc(); - while (Loc.isMacroID()) { - std::string MacroName = Lexer::getImmediateMacroName(Loc, SM, LO); - if (Names.find(MacroName) != Names.end()) - return true; - Loc = SM.getImmediateMacroCallerLoc(Loc); - } - return false; +AST_MATCHER(Expr, isInstantiationDependent) { + return Node.isInstantiationDependent(); } void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) { const auto AnyLiteralExpr = ignoringParenImpCasts( anyOf(cxxBoolLiteral(), characterLiteral(), integerLiteral())); - std::vector MacroNames = - utils::options::parseStringList(KnownBannedMacroNames); - std::set Names(MacroNames.begin(), MacroNames.end()); - - const auto BannedIntegerLiteral = integerLiteral(expandedByMacro(Names)); - Finder->addMatcher( binaryOperator(anyOf(hasOperatorName("-"), hasOperatorName("/"), hasOperatorName("%"), hasOperatorName("|"), @@ -470,256 +112,20 @@ matchers::isComparisonOperator(), hasOperatorName("&&"), hasOperatorName("||"), hasOperatorName("=")), - operandsAreEquivalent(), + OperandsAreEquivalent(), // Filter noisy false positives. - unless(isInTemplateInstantiation()), - unless(binaryOperatorIsInMacro()), + unless(isInstantiationDependent()), + unless(isInMacro()), unless(hasType(realFloatingPointType())), unless(hasEitherOperand(hasType(realFloatingPointType()))), - unless(hasLHS(AnyLiteralExpr)), - unless(hasDescendant(BannedIntegerLiteral))) + unless(hasLHS(AnyLiteralExpr))) .bind("binary"), this); - - Finder->addMatcher( - conditionalOperator(expressionsAreEquivalent(), - // Filter noisy false positives. - unless(conditionalOperatorIsInMacro()), - unless(hasTrueExpression(AnyLiteralExpr)), - unless(isInTemplateInstantiation())) - .bind("cond"), - this); - - Finder->addMatcher( - cxxOperatorCallExpr( - anyOf( - hasOverloadedOperatorName("-"), hasOverloadedOperatorName("/"), - hasOverloadedOperatorName("%"), hasOverloadedOperatorName("|"), - hasOverloadedOperatorName("&"), hasOverloadedOperatorName("^"), - hasOverloadedOperatorName("=="), hasOverloadedOperatorName("!="), - hasOverloadedOperatorName("<"), hasOverloadedOperatorName("<="), - hasOverloadedOperatorName(">"), hasOverloadedOperatorName(">="), - hasOverloadedOperatorName("&&"), hasOverloadedOperatorName("||"), - hasOverloadedOperatorName("=")), - parametersAreEquivalent(), - // Filter noisy false positives. - unless(isMacro()), unless(isInTemplateInstantiation())) - .bind("call"), - this); - - // Match common expressions and apply more checks to find redundant - // sub-expressions. - // a) Expr K1 == K2 - // b) Expr K1 == Expr - // c) Expr K1 == Expr K2 - // see: 'checkArithmeticExpr' and 'checkBitwiseExpr' - const auto BinOpCstLeft = matchBinOpIntegerConstantExpr("lhs"); - const auto BinOpCstRight = matchBinOpIntegerConstantExpr("rhs"); - const auto CstRight = matchIntegerConstantExpr("rhs"); - const auto SymRight = matchSymbolicExpr("rhs"); - - // Match expressions like: x 0xFF == 0xF00. - Finder->addMatcher(binaryOperator(isComparisonOperator(), - hasEitherOperand(BinOpCstLeft), - hasEitherOperand(CstRight)) - .bind("binop-const-compare-to-const"), - this); - - // Match expressions like: x 0xFF == x. - Finder->addMatcher( - binaryOperator(isComparisonOperator(), - anyOf(allOf(hasLHS(BinOpCstLeft), hasRHS(SymRight)), - allOf(hasLHS(SymRight), hasRHS(BinOpCstLeft)))) - .bind("binop-const-compare-to-sym"), - this); - - // Match expressions like: x 10 == x 12. - Finder->addMatcher(binaryOperator(isComparisonOperator(), - hasLHS(BinOpCstLeft), hasRHS(BinOpCstRight), - // Already reported as redundant. - unless(operandsAreEquivalent())) - .bind("binop-const-compare-to-binop-const"), - this); - - // Match relational expressions combined with logical operators and find - // redundant sub-expressions. - // see: 'checkRelationalExpr' - - // Match expressions like: x < 2 && x > 2. - const auto ComparisonLeft = matchRelationalIntegerConstantExpr("lhs"); - const auto ComparisonRight = matchRelationalIntegerConstantExpr("rhs"); - Finder->addMatcher( - binaryOperator(anyOf(hasOperatorName("||"), hasOperatorName("&&")), - hasLHS(ComparisonLeft), hasRHS(ComparisonRight), - // Already reported as redundant. - unless(operandsAreEquivalent())) - .bind("comparisons-of-symbol-and-const"), - this); -} - -void RedundantExpressionCheck::checkArithmeticExpr( - const MatchFinder::MatchResult &Result) { - APSInt LhsValue, RhsValue; - const Expr *LhsSymbol = nullptr, *RhsSymbol = nullptr; - BinaryOperatorKind LhsOpcode, RhsOpcode; - - if (const auto *ComparisonOperator = Result.Nodes.getNodeAs( - "binop-const-compare-to-sym")) { - BinaryOperatorKind Opcode = ComparisonOperator->getOpcode(); - if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol, - LhsValue) || - !retrieveSymbolicExpr(Result, "rhs", RhsSymbol) || - !areEquivalentExpr(LhsSymbol, RhsSymbol)) - return; - - // Check expressions: x + k == x or x - k == x. - if (LhsOpcode == BO_Add || LhsOpcode == BO_Sub) { - if ((LhsValue != 0 && Opcode == BO_EQ) || - (LhsValue == 0 && Opcode == BO_NE)) - diag(ComparisonOperator->getOperatorLoc(), - "logical expression is always false"); - else if ((LhsValue == 0 && Opcode == BO_EQ) || - (LhsValue != 0 && Opcode == BO_NE)) - diag(ComparisonOperator->getOperatorLoc(), - "logical expression is always true"); - } - } else if (const auto *ComparisonOperator = - Result.Nodes.getNodeAs( - "binop-const-compare-to-binop-const")) { - BinaryOperatorKind Opcode = ComparisonOperator->getOpcode(); - - if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol, - LhsValue) || - !retrieveBinOpIntegerConstantExpr(Result, "rhs", RhsOpcode, RhsSymbol, - RhsValue) || - !areEquivalentExpr(LhsSymbol, RhsSymbol)) - return; - - canonicalNegateExpr(LhsOpcode, LhsValue); - canonicalNegateExpr(RhsOpcode, RhsValue); - - // Check expressions: x + 1 == x + 2 or x + 1 != x + 2. - if (LhsOpcode == BO_Add && RhsOpcode == BO_Add) { - if ((Opcode == BO_EQ && APSInt::compareValues(LhsValue, RhsValue) == 0) || - (Opcode == BO_NE && APSInt::compareValues(LhsValue, RhsValue) != 0)) { - diag(ComparisonOperator->getOperatorLoc(), - "logical expression is always true"); - } else if ((Opcode == BO_EQ && - APSInt::compareValues(LhsValue, RhsValue) != 0) || - (Opcode == BO_NE && - APSInt::compareValues(LhsValue, RhsValue) == 0)) { - diag(ComparisonOperator->getOperatorLoc(), - "logical expression is always false"); - } - } - } -} - -void RedundantExpressionCheck::checkBitwiseExpr( - const MatchFinder::MatchResult &Result) { - if (const auto *ComparisonOperator = Result.Nodes.getNodeAs( - "binop-const-compare-to-const")) { - BinaryOperatorKind Opcode = ComparisonOperator->getOpcode(); - - APSInt LhsValue, RhsValue; - const Expr *LhsSymbol = nullptr; - BinaryOperatorKind LhsOpcode; - if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol, - LhsValue) || - !retrieveIntegerConstantExpr(Result, "rhs", RhsValue)) - return; - - uint64_t LhsConstant = LhsValue.getZExtValue(); - uint64_t RhsConstant = RhsValue.getZExtValue(); - SourceLocation Loc = ComparisonOperator->getOperatorLoc(); - - // Check expression: x & k1 == k2 (i.e. x & 0xFF == 0xF00) - if (LhsOpcode == BO_And && (LhsConstant & RhsConstant) != RhsConstant) { - if (Opcode == BO_EQ) - diag(Loc, "logical expression is always false"); - else if (Opcode == BO_NE) - diag(Loc, "logical expression is always true"); - } - - // Check expression: x | k1 == k2 (i.e. x | 0xFF == 0xF00) - if (LhsOpcode == BO_Or && (LhsConstant | RhsConstant) != RhsConstant) { - if (Opcode == BO_EQ) - diag(Loc, "logical expression is always false"); - else if (Opcode == BO_NE) - diag(Loc, "logical expression is always true"); - } - } -} - -void RedundantExpressionCheck::checkRelationalExpr( - const MatchFinder::MatchResult &Result) { - if (const auto *ComparisonOperator = Result.Nodes.getNodeAs( - "comparisons-of-symbol-and-const")) { - // Matched expressions are: (x k1) (x k2). - BinaryOperatorKind Opcode = ComparisonOperator->getOpcode(); - - const Expr *LhsExpr = nullptr, *RhsExpr = nullptr; - APSInt LhsValue, RhsValue; - const Expr *LhsSymbol = nullptr, *RhsSymbol = nullptr; - BinaryOperatorKind LhsOpcode, RhsOpcode; - if (!retrieveRelationalIntegerConstantExpr( - Result, "lhs", LhsExpr, LhsOpcode, LhsSymbol, LhsValue) || - !retrieveRelationalIntegerConstantExpr( - Result, "rhs", RhsExpr, RhsOpcode, RhsSymbol, RhsValue) || - !areEquivalentExpr(LhsSymbol, RhsSymbol)) - return; - - // Bring to a canonical form: smallest constant must be on the left side. - if (APSInt::compareValues(LhsValue, RhsValue) > 0) { - std::swap(LhsExpr, RhsExpr); - std::swap(LhsValue, RhsValue); - std::swap(LhsSymbol, RhsSymbol); - std::swap(LhsOpcode, RhsOpcode); - } - - if ((Opcode == BO_LAnd || Opcode == BO_LOr) && - areEquivalentRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) { - diag(ComparisonOperator->getOperatorLoc(), - "equivalent expression on both side of logical operator"); - return; - } - - if (Opcode == BO_LAnd) { - if (areExclusiveRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) { - diag(ComparisonOperator->getOperatorLoc(), - "logical expression is always false"); - } else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) { - diag(LhsExpr->getExprLoc(), "expression is redundant"); - } else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) { - diag(RhsExpr->getExprLoc(), "expression is redundant"); - } - } - - if (Opcode == BO_LOr) { - if (rangesFullyCoverDomain(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) { - diag(ComparisonOperator->getOperatorLoc(), - "logical expression is always true"); - } else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) { - diag(RhsExpr->getExprLoc(), "expression is redundant"); - } else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) { - diag(LhsExpr->getExprLoc(), "expression is redundant"); - } - } - } } void RedundantExpressionCheck::check(const MatchFinder::MatchResult &Result) { if (const auto *BinOp = Result.Nodes.getNodeAs("binary")) diag(BinOp->getOperatorLoc(), "both side of operator are equivalent"); - if (const auto *CondOp = Result.Nodes.getNodeAs("cond")) - diag(CondOp->getColonLoc(), "'true' and 'false' expression are equivalent"); - if (const auto *Call = Result.Nodes.getNodeAs("call")) - diag(Call->getOperatorLoc(), - "both side of overloaded operator are equivalent"); - - checkArithmeticExpr(Result); - checkBitwiseExpr(Result); - checkRelationalExpr(Result); } } // namespace misc Index: clang-tidy/misc/SizeofContainerCheck.h =================================================================== --- clang-tidy/misc/SizeofContainerCheck.h +++ clang-tidy/misc/SizeofContainerCheck.h @@ -14,7 +14,6 @@ namespace clang { namespace tidy { -namespace misc { /// Find usages of sizeof on expressions of STL container types. Most likely the /// user wanted to use `.size()` instead. @@ -29,7 +28,6 @@ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; }; -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/SizeofContainerCheck.cpp =================================================================== --- clang-tidy/misc/SizeofContainerCheck.cpp +++ clang-tidy/misc/SizeofContainerCheck.cpp @@ -15,17 +15,16 @@ namespace clang { namespace tidy { -namespace misc { void SizeofContainerCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( expr(unless(isInTemplateInstantiation()), - expr(sizeOfExpr(has(ignoringParenImpCasts( + expr(sizeOfExpr(has( expr(hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl( matchesName("^(::std::|::string)"), unless(matchesName("^::std::(bitset|array)$")), hasMethod(cxxMethodDecl(hasName("size"), isPublic(), - isConst()))))))))))) + isConst())))))))))) .bind("sizeof"), // Ignore ARRAYSIZE() pattern. unless(hasAncestor(binaryOperator( @@ -44,7 +43,6 @@ "container; did you mean .size()?"); } -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/SizeofExpressionCheck.cpp =================================================================== --- clang-tidy/misc/SizeofExpressionCheck.cpp +++ clang-tidy/misc/SizeofExpressionCheck.cpp @@ -81,23 +81,21 @@ const auto SizeOfExpr = expr(anyOf(sizeOfExpr(has(type())), sizeOfExpr(has(expr())))); const auto SizeOfZero = expr( - sizeOfExpr(has(ignoringParenImpCasts(expr(integerLiteral(equals(0))))))); + sizeOfExpr(has(expr(ignoringParenImpCasts(integerLiteral(equals(0))))))); // Detect expression like: sizeof(ARRAYLEN); // Note: The expression 'sizeof(sizeof(0))' is a portable trick used to know // the sizeof size_t. if (WarnOnSizeOfConstant) { - Finder->addMatcher( - expr(sizeOfExpr(has(ignoringParenImpCasts(ConstantExpr))), - unless(SizeOfZero)) - .bind("sizeof-constant"), - this); + Finder->addMatcher(expr(sizeOfExpr(has(ConstantExpr)), unless(SizeOfZero)) + .bind("sizeof-constant"), + this); } // Detect expression like: sizeof(this); if (WarnOnSizeOfThis) { Finder->addMatcher( - expr(sizeOfExpr(has(ignoringParenImpCasts(expr(cxxThisExpr()))))) + expr(sizeOfExpr(has(expr(ignoringParenImpCasts(cxxThisExpr()))))) .bind("sizeof-this"), this); } @@ -107,12 +105,12 @@ const auto ConstStrLiteralDecl = varDecl(isDefinition(), hasType(qualType(hasCanonicalType(CharPtrType))), hasInitializer(ignoringParenImpCasts(stringLiteral()))); - Finder->addMatcher(expr(sizeOfExpr(has(ignoringParenImpCasts(expr( - hasType(qualType(hasCanonicalType(CharPtrType))), - ignoringParenImpCasts(declRefExpr( - hasDeclaration(ConstStrLiteralDecl)))))))) - .bind("sizeof-charp"), - this); + Finder->addMatcher( + expr(sizeOfExpr(has(expr(hasType(qualType(hasCanonicalType(CharPtrType))), + ignoringParenImpCasts(declRefExpr( + hasDeclaration(ConstStrLiteralDecl))))))) + .bind("sizeof-charp"), + this); // Detect sizeof(ptr) where ptr points to an aggregate (i.e. sizeof(&S)). const auto ArrayExpr = expr(ignoringParenImpCasts( @@ -190,11 +188,10 @@ // Detect strange double-sizeof expression like: sizeof(sizeof(...)); // Note: The expression 'sizeof(sizeof(0))' is accepted. - Finder->addMatcher( - expr(sizeOfExpr(has(ignoringParenImpCasts(expr( - hasSizeOfDescendant(8, expr(SizeOfExpr, unless(SizeOfZero)))))))) - .bind("sizeof-sizeof-expr"), - this); + Finder->addMatcher(expr(sizeOfExpr(has(expr(hasSizeOfDescendant( + 8, expr(SizeOfExpr, unless(SizeOfZero))))))) + .bind("sizeof-sizeof-expr"), + this); } void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) { Index: clang-tidy/misc/StaticAssertCheck.h =================================================================== --- clang-tidy/misc/StaticAssertCheck.h +++ clang-tidy/misc/StaticAssertCheck.h @@ -16,7 +16,6 @@ namespace clang { namespace tidy { -namespace misc { /// Replaces `assert()` with `static_assert()` if the condition is evaluatable /// at compile time. @@ -34,7 +33,6 @@ SourceLocation AssertLoc); }; -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/StaticAssertCheck.cpp =================================================================== --- clang-tidy/misc/StaticAssertCheck.cpp +++ clang-tidy/misc/StaticAssertCheck.cpp @@ -22,7 +22,6 @@ namespace clang { namespace tidy { -namespace misc { StaticAssertCheck::StaticAssertCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context) {} @@ -33,13 +32,12 @@ if (!(getLangOpts().CPlusPlus11 || getLangOpts().C11)) return; - auto IsAlwaysFalse = + auto IsAlwaysFalse = expr(ignoringParenImpCasts( expr(anyOf(cxxBoolLiteral(equals(false)), integerLiteral(equals(0)), cxxNullPtrLiteralExpr(), gnuNullExpr())) - .bind("isAlwaysFalse"); + .bind("isAlwaysFalse"))); auto IsAlwaysFalseWithCast = ignoringParenImpCasts(anyOf( - IsAlwaysFalse, cStyleCastExpr(has(ignoringParenImpCasts(IsAlwaysFalse))) - .bind("castExpr"))); + IsAlwaysFalse, cStyleCastExpr(has(IsAlwaysFalse)).bind("castExpr"))); auto AssertExprRoot = anyOf( binaryOperator( anyOf(hasOperatorName("&&"), hasOperatorName("==")), @@ -64,15 +62,11 @@ hasArgument(0, AssertCondition))), AssertCondition); - Finder->addMatcher(conditionalOperator(hasCondition(Condition), - unless(isInTemplateInstantiation())) + Finder->addMatcher(stmt(anyOf(conditionalOperator(hasCondition(Condition)), + ifStmt(hasCondition(Condition))), + unless(isInTemplateInstantiation())) .bind("condStmt"), this); - - Finder->addMatcher( - ifStmt(hasCondition(Condition), unless(isInTemplateInstantiation())) - .bind("condStmt"), - this); } void StaticAssertCheck::check(const MatchFinder::MatchResult &Result) { @@ -170,6 +164,5 @@ return Token.getLocation(); } -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/StringConstructorCheck.cpp =================================================================== --- clang-tidy/misc/StringConstructorCheck.cpp +++ clang-tidy/misc/StringConstructorCheck.cpp @@ -10,7 +10,6 @@ #include "StringConstructorCheck.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Tooling/FixIt.h" using namespace clang::ast_matchers; @@ -55,7 +54,7 @@ isDefinition(), hasType(pointerType(pointee(isAnyCharacter(), isConstQualified()))), hasInitializer(ignoringParenImpCasts(BoundStringLiteral))); - const auto ConstStrLiteral = expr(ignoringParenImpCasts(anyOf( + auto ConstStrLiteral = expr(ignoringParenImpCasts(anyOf( BoundStringLiteral, declRefExpr(hasDeclaration(anyOf( ConstPtrStrLiteralDecl, ConstStrLiteralDecl)))))); @@ -89,7 +88,7 @@ // Detect the expression: string("...", 0); hasArgument(1, ZeroExpr.bind("empty-string")), // Detect the expression: string("...", -4); - hasArgument(1, NegativeExpr.bind("negative-length")), + hasArgument(1, NegativeExpr.bind("negative-length")), // Detect the expression: string("lit", 0x1234567); hasArgument(1, LargeLengthExpr.bind("large-length")), // Detect the expression: string("lit", 5) @@ -101,18 +100,11 @@ } void StringConstructorCheck::check(const MatchFinder::MatchResult &Result) { - const ASTContext &Ctx = *Result.Context; - const auto *E = Result.Nodes.getNodeAs("constructor"); - assert(E && "missing constructor expression"); + const auto *E = Result.Nodes.getNodeAs("constructor"); SourceLocation Loc = E->getLocStart(); if (Result.Nodes.getNodeAs("swapped-parameter")) { - const Expr *P0 = E->getArg(0); - const Expr *P1 = E->getArg(1); - diag(Loc, "string constructor parameters are probably swapped;" - " expecting string(count, character)") - << tooling::fixit::createReplacement(*P0, *P1, Ctx) - << tooling::fixit::createReplacement(*P1, *P0, Ctx); + diag(Loc, "constructor parameters are probably swapped"); } else if (Result.Nodes.getNodeAs("empty-string")) { diag(Loc, "constructor creating an empty string"); } else if (Result.Nodes.getNodeAs("negative-length")) { Index: clang-tidy/misc/StringIntegerAssignmentCheck.h =================================================================== --- clang-tidy/misc/StringIntegerAssignmentCheck.h +++ clang-tidy/misc/StringIntegerAssignmentCheck.h @@ -14,7 +14,6 @@ namespace clang { namespace tidy { -namespace misc { /// Finds instances where an integer is assigned to a string. /// @@ -28,7 +27,6 @@ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; }; -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/StringIntegerAssignmentCheck.cpp =================================================================== --- clang-tidy/misc/StringIntegerAssignmentCheck.cpp +++ clang-tidy/misc/StringIntegerAssignmentCheck.cpp @@ -16,7 +16,6 @@ namespace clang { namespace tidy { -namespace misc { void StringIntegerAssignmentCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) @@ -82,6 +81,5 @@ } } -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/SuspiciousMissingCommaCheck.cpp =================================================================== --- clang-tidy/misc/SuspiciousMissingCommaCheck.cpp +++ clang-tidy/misc/SuspiciousMissingCommaCheck.cpp @@ -88,7 +88,7 @@ const auto StringsInitializerList = initListExpr(hasType(constantArrayType()), - has(ignoringParenImpCasts(expr(ConcatenatedStringLiteral)))); + has(expr(ignoringImpCasts(ConcatenatedStringLiteral)))); Finder->addMatcher(StringsInitializerList.bind("list"), this); } Index: clang-tidy/misc/SuspiciousSemicolonCheck.cpp =================================================================== --- clang-tidy/misc/SuspiciousSemicolonCheck.cpp +++ clang-tidy/misc/SuspiciousSemicolonCheck.cpp @@ -40,7 +40,7 @@ return; ASTContext &Ctxt = *Result.Context; - auto Token = utils::lexer::getPreviousNonCommentToken(Ctxt, LocStart); + auto Token = lexer_utils::getPreviousNonCommentToken(Ctxt, LocStart); auto &SM = *Result.SourceManager; unsigned SemicolonLine = SM.getSpellingLineNumber(LocStart); Index: clang-tidy/misc/SuspiciousStringCompareCheck.cpp =================================================================== --- clang-tidy/misc/SuspiciousStringCompareCheck.cpp +++ clang-tidy/misc/SuspiciousStringCompareCheck.cpp @@ -8,11 +8,10 @@ //===----------------------------------------------------------------------===// #include "SuspiciousStringCompareCheck.h" -#include "../utils/Matchers.h" -#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Lex/Lexer.h" +#include "../utils/Matchers.h" using namespace clang::ast_matchers; @@ -20,9 +19,6 @@ namespace tidy { namespace misc { - -// Semicolon separated list of known string compare-like functions. The list -// must ends with a semicolon. static const char KnownStringCompareFunctions[] = "__builtin_memcmp;" "__builtin_strcasecmp;" "__builtin_strcmp;" @@ -68,6 +64,19 @@ "wcsnicmp;" "wmemcmp;"; +static const char StringCompareLikeFunctionsDelimiter[] = ";"; + +static void ParseFunctionNames(StringRef Option, + std::vector *Result) { + SmallVector Functions; + Option.split(Functions, StringCompareLikeFunctionsDelimiter); + for (StringRef &Function : Functions) { + Function = Function.trim(); + if (!Function.empty()) + Result->push_back(Function); + } +} + SuspiciousStringCompareCheck::SuspiciousStringCompareCheck( StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), @@ -93,9 +102,9 @@ // Add the list of known string compare-like functions and add user-defined // functions. - std::vector FunctionNames = utils::options::parseStringList( - (llvm::Twine(KnownStringCompareFunctions) + StringCompareLikeFunctions) - .str()); + std::vector FunctionNames; + ParseFunctionNames(KnownStringCompareFunctions, &FunctionNames); + ParseFunctionNames(StringCompareLikeFunctions, &FunctionNames); // Match a call to a string compare functions. const auto FunctionCompareDecl = @@ -156,9 +165,8 @@ // Detect comparison to invalid constant: 'strcmp() == -1'. const auto InvalidLiteral = ignoringParenImpCasts( anyOf(integerLiteral(unless(equals(0))), - unaryOperator( - hasOperatorName("-"), - has(ignoringParenImpCasts(integerLiteral(unless(equals(0)))))), + unaryOperator(hasOperatorName("-"), + has(integerLiteral(unless(equals(0))))), characterLiteral(), cxxBoolLiteral())); Finder->addMatcher(binaryOperator(matchers::isComparisonOperator(), Index: clang-tidy/misc/SwappedArgumentsCheck.cpp =================================================================== --- clang-tidy/misc/SwappedArgumentsCheck.cpp +++ clang-tidy/misc/SwappedArgumentsCheck.cpp @@ -10,7 +10,6 @@ #include "SwappedArgumentsCheck.h" #include "clang/AST/ASTContext.h" #include "clang/Lex/Lexer.h" -#include "clang/Tooling/FixIt.h" #include "llvm/ADT/SmallPtrSet.h" using namespace clang::ast_matchers; @@ -47,9 +46,25 @@ Cast->getCastKind() == CK_PointerToBoolean; } +/// \brief Get a StringRef representing a SourceRange. +static StringRef getAsString(const MatchFinder::MatchResult &Result, + SourceRange R) { + const SourceManager &SM = *Result.SourceManager; + // Don't even try to resolve macro or include contraptions. Not worth emitting + // a fixit for. + if (R.getBegin().isMacroID() || + !SM.isWrittenInSameFile(R.getBegin(), R.getEnd())) + return StringRef(); + + const char *Begin = SM.getCharacterData(R.getBegin()); + const char *End = SM.getCharacterData(Lexer::getLocForEndOfToken( + R.getEnd(), 0, SM, Result.Context->getLangOpts())); + + return StringRef(Begin, End - Begin); +} + void SwappedArgumentsCheck::check(const MatchFinder::MatchResult &Result) { - const ASTContext &Ctx = *Result.Context; - const auto *Call = Result.Nodes.getStmtAs("call"); + auto *Call = Result.Nodes.getStmtAs("call"); llvm::SmallPtrSet UsedArgs; for (unsigned I = 1, E = Call->getNumArgs(); I < E; ++I) { @@ -84,14 +99,24 @@ continue; // Emit a warning and fix-its that swap the arguments. - diag(Call->getLocStart(), "argument with implicit conversion from %0 " - "to %1 followed by argument converted from " - "%2 to %3, potentially swapped arguments.") + SourceRange LHSRange = LHS->getSourceRange(), + RHSRange = RHS->getSourceRange(); + auto D = + diag(Call->getLocStart(), "argument with implicit conversion from %0 " + "to %1 followed by argument converted from " + "%2 to %3, potentially swapped arguments.") << LHS->getType() << LHSFrom->getType() << RHS->getType() - << RHSFrom->getType() - << tooling::fixit::createReplacement(*LHS, *RHS, Ctx) - << tooling::fixit::createReplacement(*RHS, *LHS, Ctx); - + << RHSFrom->getType() << LHSRange << RHSRange; + + StringRef RHSString = getAsString(Result, RHSRange); + StringRef LHSString = getAsString(Result, LHSRange); + if (!LHSString.empty() && !RHSString.empty()) { + D << FixItHint::CreateReplacement( + CharSourceRange::getTokenRange(LHSRange), RHSString) + << FixItHint::CreateReplacement( + CharSourceRange::getTokenRange(RHSRange), LHSString); + } + // Remember that we emitted a warning for this argument. UsedArgs.insert(RHSCast); } Index: clang-tidy/misc/ThrowByValueCatchByReferenceCheck.h =================================================================== --- clang-tidy/misc/ThrowByValueCatchByReferenceCheck.h +++ clang-tidy/misc/ThrowByValueCatchByReferenceCheck.h @@ -14,7 +14,6 @@ namespace clang { namespace tidy { -namespace misc { ///\brief checks for locations that do not throw by value // or catch by reference. @@ -44,7 +43,6 @@ const bool CheckAnonymousTemporaries; }; -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/ThrowByValueCatchByReferenceCheck.cpp =================================================================== --- clang-tidy/misc/ThrowByValueCatchByReferenceCheck.cpp +++ clang-tidy/misc/ThrowByValueCatchByReferenceCheck.cpp @@ -16,7 +16,6 @@ namespace clang { namespace tidy { -namespace misc { ThrowByValueCatchByReferenceCheck::ThrowByValueCatchByReferenceCheck( StringRef Name, ClangTidyContext *Context) @@ -156,6 +155,5 @@ } } -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/UnconventionalAssignOperatorCheck.h =================================================================== --- clang-tidy/misc/UnconventionalAssignOperatorCheck.h +++ /dev/null @@ -1,42 +0,0 @@ -//===--- UnconventionalAssignOperatorCheck.h - clang-tidy -------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_ASSIGNOPERATORSIGNATURECHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_ASSIGNOPERATORSIGNATURECHECK_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace misc { - -/// Finds declarations of assignment operators with the wrong return and/or -/// argument types and definitions with good return type but wrong return -/// statements. -/// -/// * The return type must be `Class&`. -/// * Works with move-assign and assign by value. -/// * Private and deleted operators are ignored. -/// * The operator must always return ``*this``. -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/misc-unconventional-assign-operator.html -class UnconventionalAssignOperatorCheck : public ClangTidyCheck { -public: - UnconventionalAssignOperatorCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -}; - -} // namespace misc -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_ASSIGNOPERATORSIGNATURECHECK_H Index: clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp =================================================================== --- clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp +++ /dev/null @@ -1,89 +0,0 @@ -//===--- UnconventionalAssignOperatorCheck.cpp - clang-tidy -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "UnconventionalAssignOperatorCheck.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/ASTMatchers/ASTMatchers.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace misc { - -void UnconventionalAssignOperatorCheck::registerMatchers(ast_matchers::MatchFinder *Finder) { - // Only register the matchers for C++; the functionality currently does not - // provide any benefit to other languages, despite being benign. - if (!getLangOpts().CPlusPlus) - return; - - const auto HasGoodReturnType = cxxMethodDecl(returns( - lValueReferenceType(pointee(unless(isConstQualified()), - hasDeclaration(equalsBoundNode("class")))))); - - const auto IsSelf = qualType( - anyOf(hasDeclaration(equalsBoundNode("class")), - referenceType(pointee(hasDeclaration(equalsBoundNode("class")))))); - const auto IsAssign = - cxxMethodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())), - hasName("operator="), ofClass(recordDecl().bind("class"))) - .bind("method"); - const auto IsSelfAssign = - cxxMethodDecl(IsAssign, hasParameter(0, parmVarDecl(hasType(IsSelf)))) - .bind("method"); - - Finder->addMatcher( - cxxMethodDecl(IsAssign, unless(HasGoodReturnType)).bind("ReturnType"), - this); - - const auto BadSelf = referenceType( - anyOf(lValueReferenceType(pointee(unless(isConstQualified()))), - rValueReferenceType(pointee(isConstQualified())))); - - Finder->addMatcher( - cxxMethodDecl(IsSelfAssign, - hasParameter(0, parmVarDecl(hasType(BadSelf)))) - .bind("ArgumentType"), - this); - - Finder->addMatcher( - cxxMethodDecl(IsSelfAssign, anyOf(isConst(), isVirtual())).bind("cv"), - this); - - const auto IsBadReturnStatement = returnStmt(unless(has(ignoringParenImpCasts( - unaryOperator(hasOperatorName("*"), hasUnaryOperand(cxxThisExpr())))))); - const auto IsGoodAssign = cxxMethodDecl(IsAssign, HasGoodReturnType); - - Finder->addMatcher(returnStmt(IsBadReturnStatement, forFunction(IsGoodAssign)) - .bind("returnStmt"), - this); -} - -void UnconventionalAssignOperatorCheck::check(const MatchFinder::MatchResult &Result) { - if (const auto *RetStmt = Result.Nodes.getNodeAs("returnStmt")) { - diag(RetStmt->getLocStart(), "operator=() should always return '*this'"); - } else { - static const char *const Messages[][2] = { - {"ReturnType", "operator=() should return '%0&'"}, - {"ArgumentType", "operator=() should take '%0 const&', '%0&&' or '%0'"}, - {"cv", "operator=() should not be marked '%1'"}}; - - const auto *Method = Result.Nodes.getNodeAs("method"); - for (const auto &Message : Messages) { - if (Result.Nodes.getNodeAs(Message[0])) - diag(Method->getLocStart(), Message[1]) - << Method->getParent()->getName() - << (Method->isConst() ? "const" : "virtual"); - } - } -} - -} // namespace misc -} // namespace tidy -} // namespace clang Index: clang-tidy/misc/UndelegatedConstructor.cpp =================================================================== --- clang-tidy/misc/UndelegatedConstructor.cpp +++ clang-tidy/misc/UndelegatedConstructor.cpp @@ -14,8 +14,6 @@ using namespace clang::ast_matchers; namespace clang { -namespace tidy { -namespace misc { namespace { AST_MATCHER_P(Stmt, ignoringTemporaryExpr, @@ -48,6 +46,9 @@ } } // namespace +namespace tidy { +namespace misc { + void UndelegatedConstructorCheck::registerMatchers(MatchFinder *Finder) { // We look for calls to constructors of the same type in constructors. To do // this we have to look through a variety of nodes that occur in the path, Index: clang-tidy/misc/UniqueptrResetReleaseCheck.cpp =================================================================== --- clang-tidy/misc/UniqueptrResetReleaseCheck.cpp +++ clang-tidy/misc/UniqueptrResetReleaseCheck.cpp @@ -30,13 +30,13 @@ cxxMethodDecl(hasName("reset"), ofClass(cxxRecordDecl(hasName("::std::unique_ptr"), decl().bind("left_class"))))), - has(ignoringParenImpCasts(cxxMemberCallExpr( + has(cxxMemberCallExpr( on(expr().bind("right")), callee(memberExpr().bind("release_member")), callee(cxxMethodDecl( hasName("release"), ofClass(cxxRecordDecl(hasName("::std::unique_ptr"), - decl().bind("right_class"))))))))) + decl().bind("right_class")))))))) .bind("reset_call"), this); } Index: clang-tidy/misc/UnusedAliasDeclsCheck.h =================================================================== --- clang-tidy/misc/UnusedAliasDeclsCheck.h +++ clang-tidy/misc/UnusedAliasDeclsCheck.h @@ -15,7 +15,6 @@ namespace clang { namespace tidy { -namespace misc { /// Finds unused namespace alias declarations. class UnusedAliasDeclsCheck : public ClangTidyCheck { @@ -30,7 +29,6 @@ llvm::DenseMap FoundDecls; }; -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/UnusedAliasDeclsCheck.cpp =================================================================== --- clang-tidy/misc/UnusedAliasDeclsCheck.cpp +++ clang-tidy/misc/UnusedAliasDeclsCheck.cpp @@ -16,7 +16,6 @@ namespace clang { namespace tidy { -namespace misc { void UnusedAliasDeclsCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++11; the functionality currently does not @@ -59,6 +58,5 @@ } } -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/UnusedParametersCheck.h =================================================================== --- clang-tidy/misc/UnusedParametersCheck.h +++ clang-tidy/misc/UnusedParametersCheck.h @@ -14,7 +14,6 @@ namespace clang { namespace tidy { -namespace misc { /// Finds unused parameters and fixes them, so that `-Wunused-parameter` can be /// turned on. @@ -31,7 +30,6 @@ const FunctionDecl *Function, unsigned ParamIndex); }; -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/UnusedParametersCheck.cpp =================================================================== --- clang-tidy/misc/UnusedParametersCheck.cpp +++ clang-tidy/misc/UnusedParametersCheck.cpp @@ -16,8 +16,6 @@ namespace clang { namespace tidy { -namespace misc { - namespace { bool isOverrideMethod(const FunctionDecl *Function) { if (const auto *MD = dyn_cast(Function)) @@ -122,6 +120,5 @@ } } -} // namespace misc } // namespace tidy } // namespace clang Index: clang-tidy/misc/UnusedRAIICheck.cpp =================================================================== --- clang-tidy/misc/UnusedRAIICheck.cpp +++ clang-tidy/misc/UnusedRAIICheck.cpp @@ -14,9 +14,6 @@ using namespace clang::ast_matchers; namespace clang { -namespace tidy { -namespace misc { - namespace { AST_MATCHER(CXXRecordDecl, hasNonTrivialDestructor) { // TODO: If the dtor is there but empty we don't want to warn either. @@ -24,6 +21,9 @@ } } // namespace +namespace tidy { +namespace misc { + void UnusedRAIICheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not // provide any benefit to other languages, despite being benign. @@ -33,16 +33,13 @@ // Look for temporaries that are constructed in-place and immediately // destroyed. Look for temporaries created by a functional cast but not for // those returned from a call. - auto BindTemp = - cxxBindTemporaryExpr(unless(has(ignoringParenImpCasts(callExpr())))) - .bind("temp"); + auto BindTemp = cxxBindTemporaryExpr(unless(has(callExpr()))).bind("temp"); Finder->addMatcher( - exprWithCleanups(unless(isInTemplateInstantiation()), - hasParent(compoundStmt().bind("compound")), - hasType(cxxRecordDecl(hasNonTrivialDestructor())), - anyOf(has(ignoringParenImpCasts(BindTemp)), - has(ignoringParenImpCasts(cxxFunctionalCastExpr( - has(ignoringParenImpCasts(BindTemp))))))) + exprWithCleanups( + unless(isInTemplateInstantiation()), + hasParent(compoundStmt().bind("compound")), + hasType(cxxRecordDecl(hasNonTrivialDestructor())), + anyOf(has(BindTemp), has(cxxFunctionalCastExpr(has(BindTemp))))) .bind("expr"), this); } Index: clang-tidy/misc/UnusedUsingDeclsCheck.h =================================================================== --- clang-tidy/misc/UnusedUsingDeclsCheck.h +++ clang-tidy/misc/UnusedUsingDeclsCheck.h @@ -11,8 +11,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNUSED_USING_DECLS_H #include "../ClangTidy.h" -#include "llvm/ADT/SmallPtrSet.h" -#include +#include "llvm/ADT/DenseMap.h" namespace clang { namespace tidy { @@ -31,24 +30,8 @@ void onEndOfTranslationUnit() override; private: - void removeFromFoundDecls(const Decl *D); - - struct UsingDeclContext { - explicit UsingDeclContext(const UsingDecl *FoundUsingDecl) - : FoundUsingDecl(FoundUsingDecl), IsUsed(false) {} - // A set saves all UsingShadowDecls introduced by a UsingDecl. A UsingDecl - // can introduce multiple UsingShadowDecls in some cases (such as - // overloaded functions). - llvm::SmallPtrSet UsingTargetDecls; - // The original UsingDecl. - const UsingDecl *FoundUsingDecl; - // The source range of the UsingDecl. - CharSourceRange UsingDeclRange; - // Whether the UsingDecl is used. - bool IsUsed; - }; - - std::vector Contexts; + llvm::DenseMap FoundDecls; + llvm::DenseMap FoundRanges; }; } // namespace misc Index: clang-tidy/misc/UnusedUsingDeclsCheck.cpp =================================================================== --- clang-tidy/misc/UnusedUsingDeclsCheck.cpp +++ clang-tidy/misc/UnusedUsingDeclsCheck.cpp @@ -18,57 +18,33 @@ namespace tidy { namespace misc { -// A function that helps to tell whether a TargetDecl in a UsingDecl will be -// checked. Only variable, function, function template, class template, class, -// enum declaration and enum constant declaration are considered. -static bool ShouldCheckDecl(const Decl *TargetDecl) { - return isa(TargetDecl) || isa(TargetDecl) || - isa(TargetDecl) || isa(TargetDecl) || - isa(TargetDecl) || isa(TargetDecl) || - isa(TargetDecl); -} - void UnusedUsingDeclsCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher(usingDecl(isExpansionInMainFile()).bind("using"), this); auto DeclMatcher = hasDeclaration(namedDecl().bind("used")); - Finder->addMatcher(loc(enumType(DeclMatcher)), this); Finder->addMatcher(loc(recordType(DeclMatcher)), this); Finder->addMatcher(loc(templateSpecializationType(DeclMatcher)), this); - Finder->addMatcher(declRefExpr().bind("used"), this); - Finder->addMatcher(callExpr(callee(unresolvedLookupExpr().bind("used"))), - this); } void UnusedUsingDeclsCheck::check(const MatchFinder::MatchResult &Result) { if (const auto *Using = Result.Nodes.getNodeAs("using")) { - // Ignores using-declarations defined in macros. - if (Using->getLocation().isMacroID()) - return; - - // Ignores using-declarations defined in class definition. - if (isa(Using->getDeclContext())) + // FIXME: Implement the correct behavior for using declarations with more + // than one shadow. + if (Using->shadow_size() != 1) return; + const auto *TargetDecl = + Using->shadow_begin()->getTargetDecl()->getCanonicalDecl(); - // FIXME: We ignore using-decls defined in function definitions at the - // moment because of false positives caused by ADL and different function - // scopes. - if (isa(Using->getDeclContext())) + // FIXME: Handle other target types. + if (!isa(TargetDecl) && !isa(TargetDecl)) return; - UsingDeclContext Context(Using); - Context.UsingDeclRange = CharSourceRange::getCharRange( + FoundDecls[TargetDecl] = Using; + FoundRanges[TargetDecl] = CharSourceRange::getCharRange( Using->getLocStart(), Lexer::findLocationAfterToken( Using->getLocEnd(), tok::semi, *Result.SourceManager, Result.Context->getLangOpts(), /*SkipTrailingWhitespaceAndNewLine=*/true)); - for (const auto *UsingShadow : Using->shadows()) { - const auto *TargetDecl = UsingShadow->getTargetDecl()->getCanonicalDecl(); - if (ShouldCheckDecl(TargetDecl)) - Context.UsingTargetDecls.insert(TargetDecl); - } - if (!Context.UsingTargetDecls.empty()) - Contexts.push_back(Context); return; } @@ -81,54 +57,21 @@ if (const auto *Specialization = dyn_cast(Used)) Used = Specialization->getSpecializedTemplate(); - removeFromFoundDecls(Used); - return; - } - - if (const auto *DRE = Result.Nodes.getNodeAs("used")) { - if (const auto *FD = dyn_cast(DRE->getDecl())) { - if (const auto *FDT = FD->getPrimaryTemplate()) - removeFromFoundDecls(FDT); - else - removeFromFoundDecls(FD); - } else if (const auto *VD = dyn_cast(DRE->getDecl())) { - removeFromFoundDecls(VD); - } else if (const auto *ECD = dyn_cast(DRE->getDecl())) { - removeFromFoundDecls(ECD); - if (const auto *ET = ECD->getType()->getAs()) - removeFromFoundDecls(ET->getDecl()); - } - } - // Check the uninstantiated template function usage. - if (const auto *ULE = Result.Nodes.getNodeAs("used")) { - for (const NamedDecl* ND : ULE->decls()) { - if (const auto *USD = dyn_cast(ND)) - removeFromFoundDecls(USD->getTargetDecl()->getCanonicalDecl()); - } - } -} - -void UnusedUsingDeclsCheck::removeFromFoundDecls(const Decl *D) { - // FIXME: Currently, we don't handle the using-decls being used in different - // scopes (such as different namespaces, different functions). Instead of - // giving an incorrect message, we mark all of them as used. - // - // FIXME: Use a more efficient way to find a matching context. - for (auto &Context : Contexts) { - if (Context.UsingTargetDecls.count(D->getCanonicalDecl()) > 0) - Context.IsUsed = true; + auto I = FoundDecls.find(Used->getCanonicalDecl()); + if (I != FoundDecls.end()) + I->second = nullptr; } } void UnusedUsingDeclsCheck::onEndOfTranslationUnit() { - for (const auto &Context : Contexts) { - if (!Context.IsUsed) { - diag(Context.FoundUsingDecl->getLocation(), "using decl %0 is unused") - << Context.FoundUsingDecl - << FixItHint::CreateRemoval(Context.UsingDeclRange); - } + for (const auto &FoundDecl : FoundDecls) { + if (FoundDecl.second == nullptr) + continue; + diag(FoundDecl.second->getLocation(), "using decl %0 is unused") + << FoundDecl.second + << FixItHint::CreateRemoval(FoundRanges[FoundDecl.first]); } - Contexts.clear(); + FoundDecls.clear(); } } // namespace misc Index: clang-tidy/modernize/AvoidBindCheck.h =================================================================== --- clang-tidy/modernize/AvoidBindCheck.h +++ /dev/null @@ -1,36 +0,0 @@ -//===--- AvoidBindCheck.h - clang-tidy---------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_AVOID_BIND_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_AVOID_BIND_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace modernize { - -/// Replace simple uses of std::bind with a lambda. -/// -/// FIXME: Add support for function references and member function references. -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-avoid-std-bind.html -class AvoidBindCheck : public ClangTidyCheck { -public: - AvoidBindCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -}; -} // namespace modernize -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_AVOID_BIND_H Index: clang-tidy/modernize/AvoidBindCheck.cpp =================================================================== --- clang-tidy/modernize/AvoidBindCheck.cpp +++ /dev/null @@ -1,163 +0,0 @@ -//===--- AvoidBindCheck.cpp - clang-tidy--------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#include "AvoidBindCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Lex/Lexer.h" -#include -#include - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace modernize { - -namespace { -enum BindArgumentKind { BK_Temporary, BK_Placeholder, BK_CallExpr, BK_Other }; - -struct BindArgument { - StringRef Tokens; - BindArgumentKind Kind = BK_Other; - size_t PlaceHolderIndex = 0; -}; - -} // end namespace - -static SmallVector -buildBindArguments(const MatchFinder::MatchResult &Result, const CallExpr *C) { - SmallVector BindArguments; - llvm::Regex MatchPlaceholder("^_([0-9]+)$"); - - // Start at index 1 as first argument to bind is the function name. - for (size_t I = 1, ArgCount = C->getNumArgs(); I < ArgCount; ++I) { - const Expr *E = C->getArg(I); - BindArgument B; - if (const auto *M = dyn_cast(E)) { - const auto *TE = M->GetTemporaryExpr(); - B.Kind = isa(TE) ? BK_CallExpr : BK_Temporary; - } - - B.Tokens = Lexer::getSourceText( - CharSourceRange::getTokenRange(E->getLocStart(), E->getLocEnd()), - *Result.SourceManager, Result.Context->getLangOpts()); - - SmallVector Matches; - if (B.Kind == BK_Other && MatchPlaceholder.match(B.Tokens, &Matches)) { - B.Kind = BK_Placeholder; - B.PlaceHolderIndex = std::stoi(Matches[1]); - } - BindArguments.push_back(B); - } - return BindArguments; -} - -static void addPlaceholderArgs(const ArrayRef Args, - llvm::raw_ostream &Stream) { - auto MaxPlaceholderIt = - std::max_element(Args.begin(), Args.end(), - [](const BindArgument &B1, const BindArgument &B2) { - return B1.PlaceHolderIndex < B2.PlaceHolderIndex; - }); - - // Placeholders (if present) have index 1 or greater. - if (MaxPlaceholderIt == Args.end() || MaxPlaceholderIt->PlaceHolderIndex == 0) - return; - - size_t PlaceholderCount = MaxPlaceholderIt->PlaceHolderIndex; - Stream << "("; - StringRef Delimiter = ""; - for (size_t I = 1; I <= PlaceholderCount; ++I) { - Stream << Delimiter << "auto && arg" << I; - Delimiter = ", "; - } - Stream << ")"; -} - -static void addFunctionCallArgs(const ArrayRef Args, - llvm::raw_ostream &Stream) { - StringRef Delimiter = ""; - for (const auto &B : Args) { - if (B.PlaceHolderIndex) - Stream << Delimiter << "arg" << B.PlaceHolderIndex; - else - Stream << Delimiter << B.Tokens; - Delimiter = ", "; - } -} - -static bool isPlaceHolderIndexRepeated(const ArrayRef Args) { - llvm::SmallSet PlaceHolderIndices; - for (const BindArgument &B : Args) { - if (B.PlaceHolderIndex) { - if (!PlaceHolderIndices.insert(B.PlaceHolderIndex).second) - return true; - } - } - return false; -} - -void AvoidBindCheck::registerMatchers(MatchFinder *Finder) { - if (!getLangOpts().CPlusPlus14) // Need C++14 for generic lambdas. - return; - - Finder->addMatcher( - callExpr(callee(namedDecl(hasName("::std::bind"))), - hasArgument(0, declRefExpr(to(functionDecl().bind("f"))))) - .bind("bind"), - this); -} - -void AvoidBindCheck::check(const MatchFinder::MatchResult &Result) { - const auto *MatchedDecl = Result.Nodes.getNodeAs("bind"); - auto Diag = diag(MatchedDecl->getLocStart(), "prefer a lambda to std::bind"); - - const auto Args = buildBindArguments(Result, MatchedDecl); - - // Do not attempt to create fixits for nested call expressions. - // FIXME: Create lambda capture variables to capture output of calls. - // NOTE: Supporting nested std::bind will be more difficult due to placeholder - // sharing between outer and inner std:bind invocations. - if (llvm::any_of(Args, - [](const BindArgument &B) { return B.Kind == BK_CallExpr; })) - return; - - // Do not attempt to create fixits when placeholders are reused. - // Unused placeholders are supported by requiring C++14 generic lambdas. - // FIXME: Support this case by deducing the common type. - if (isPlaceHolderIndexRepeated(Args)) - return; - - const auto *F = Result.Nodes.getNodeAs("f"); - - // std::bind can support argument count mismatch between its arguments and the - // bound function's arguments. Do not attempt to generate a fixit for such - // cases. - // FIXME: Support this case by creating unused lambda capture variables. - if (F->getNumParams() != Args.size()) - return; - - std::string Buffer; - llvm::raw_string_ostream Stream(Buffer); - - bool HasCapturedArgument = llvm::any_of( - Args, [](const BindArgument &B) { return B.Kind == BK_Other; }); - - Stream << "[" << (HasCapturedArgument ? "=" : "") << "]"; - addPlaceholderArgs(Args, Stream); - Stream << " { return " << F->getName() << "("; - addFunctionCallArgs(Args, Stream); - Stream << "); };"; - - Diag << FixItHint::CreateReplacement(MatchedDecl->getSourceRange(), Stream.str()); -} - -} // namespace modernize -} // namespace tidy -} // namespace clang Index: clang-tidy/modernize/CMakeLists.txt =================================================================== --- clang-tidy/modernize/CMakeLists.txt +++ clang-tidy/modernize/CMakeLists.txt @@ -1,12 +1,9 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(clangTidyModernizeModule - AvoidBindCheck.cpp DeprecatedHeadersCheck.cpp LoopConvertCheck.cpp LoopConvertUtils.cpp - MakeSmartPtrCheck.cpp - MakeSharedCheck.cpp MakeUniqueCheck.cpp ModernizeTidyModule.cpp PassByValueCheck.cpp @@ -15,12 +12,9 @@ ReplaceAutoPtrCheck.cpp ShrinkToFitCheck.cpp UseAutoCheck.cpp - UseBoolLiteralsCheck.cpp UseDefaultCheck.cpp - UseEmplaceCheck.cpp UseNullptrCheck.cpp UseOverrideCheck.cpp - UseUsingCheck.cpp LINK_LIBS clangAST Index: clang-tidy/modernize/DeprecatedHeadersCheck.h =================================================================== --- clang-tidy/modernize/DeprecatedHeadersCheck.h +++ clang-tidy/modernize/DeprecatedHeadersCheck.h @@ -20,16 +20,11 @@ /// alternatives. /// /// Before: -/// ~~~{.cpp} -/// #include -/// ~~~ -/// +/// #include /// After: -/// ~~~{.cpp} -/// #include -/// ~~~ +/// #include /// -/// Example: `` => `` +/// Example: => /// /// For the user-facing documentation see: /// http://clang.llvm.org/extra/clang-tidy/checks/modernize-deprecated-headers.html Index: clang-tidy/modernize/LoopConvertCheck.cpp =================================================================== --- clang-tidy/modernize/LoopConvertCheck.cpp +++ clang-tidy/modernize/LoopConvertCheck.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "LoopConvertCheck.h" -#include "../utils/Matchers.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" @@ -142,10 +141,10 @@ StatementMatcher IteratorComparisonMatcher = expr( ignoringParenImpCasts(declRefExpr(to(varDecl().bind(ConditionVarName))))); - auto OverloadedNEQMatcher = ignoringImplicit( + StatementMatcher OverloadedNEQMatcher = cxxOperatorCallExpr(hasOverloadedOperatorName("!="), argumentCountIs(2), hasArgument(0, IteratorComparisonMatcher), - hasArgument(1, IteratorBoundMatcher))); + hasArgument(1, IteratorBoundMatcher)); // This matcher tests that a declaration is a CXXRecordDecl that has an // overloaded operator*(). If the operator*() returns by value instead of by Index: clang-tidy/modernize/LoopConvertUtils.h =================================================================== --- clang-tidy/modernize/LoopConvertUtils.h +++ clang-tidy/modernize/LoopConvertUtils.h @@ -450,6 +450,9 @@ // Determine whether or not a declaration that would conflict with Symbol // exists in an outer context or in any statement contained in SourceStmt. bool declarationExists(llvm::StringRef Symbol); + + // Concatenates two identifiers following the current naming style. + std::string AppendWithStyle(StringRef Str, StringRef Suffix) const; }; } // namespace modernize Index: clang-tidy/modernize/LoopConvertUtils.cpp =================================================================== --- clang-tidy/modernize/LoopConvertUtils.cpp +++ clang-tidy/modernize/LoopConvertUtils.cpp @@ -156,7 +156,7 @@ const Expr *digThroughConstructors(const Expr *E) { if (!E) return nullptr; - E = E->IgnoreImplicit(); + E = E->IgnoreParenImpCasts(); if (const auto *ConstructExpr = dyn_cast(E)) { // The initial constructor must take exactly one parameter, but base class // and deferred constructors can take more. @@ -878,6 +878,20 @@ return DeclFinder.findUsages(SourceStmt); } +std::string VariableNamer::AppendWithStyle(StringRef Str, + StringRef Suffix) const { + std::string Name = Str; + if (!Suffix.empty()) { + if (Style == NS_LowerCase || Style == NS_UpperCase) + Name += "_"; + int SuffixStart = Name.size(); + Name += Suffix; + if (Style == NS_CamelBack) + Name[SuffixStart] = toupper(Name[SuffixStart]); + } + return Name; +} + } // namespace modernize } // namespace tidy } // namespace clang Index: clang-tidy/modernize/MakeSharedCheck.h =================================================================== --- clang-tidy/modernize/MakeSharedCheck.h +++ /dev/null @@ -1,43 +0,0 @@ -//===--- MakeSharedCheck.h - clang-tidy--------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_SHARED_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_SHARED_H - -#include "MakeSmartPtrCheck.h" - -namespace clang { -namespace tidy { -namespace modernize { - -/// Replace the pattern: -/// \code -/// std::shared_ptr(new type(args...)) -/// \endcode -/// -/// With the safer version: -/// \code -/// std::make_shared(args...) -/// \endcode -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-make-shared.html -class MakeSharedCheck : public MakeSmartPtrCheck { -public: - MakeSharedCheck(StringRef Name, ClangTidyContext *Context); - -protected: - SmartPtrTypeMatcher getSmartPointerTypeMatcher() const override; -}; - -} // namespace modernize -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_SHARED_H Index: clang-tidy/modernize/MakeSharedCheck.cpp =================================================================== --- clang-tidy/modernize/MakeSharedCheck.cpp +++ /dev/null @@ -1,31 +0,0 @@ -//===--- MakeSharedCheck.cpp - clang-tidy----------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "MakeSharedCheck.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace modernize { - -MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context) - : MakeSmartPtrCheck(Name, Context, "std::make_shared") {} - -MakeSharedCheck::SmartPtrTypeMatcher -MakeSharedCheck::getSmartPointerTypeMatcher() const { - return qualType(hasDeclaration(classTemplateSpecializationDecl( - matchesName("::std::shared_ptr"), templateArgumentCountIs(1), - hasTemplateArgument( - 0, templateArgument(refersToType(qualType().bind(PointerType))))))); -} - -} // namespace modernize -} // namespace tidy -} // namespace clang Index: clang-tidy/modernize/MakeSmartPtrCheck.h =================================================================== --- clang-tidy/modernize/MakeSmartPtrCheck.h +++ /dev/null @@ -1,52 +0,0 @@ -//===--- MakeSmartPtrCheck.h - clang-tidy------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_SMART_PTR_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_SMART_PTR_H - -#include "../ClangTidy.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/ASTMatchers/ASTMatchersInternal.h" -#include "llvm/ADT/StringRef.h" -#include - -namespace clang { -namespace tidy { -namespace modernize { - -/// Base class for MakeSharedCheck and MakeUniqueCheck. -class MakeSmartPtrCheck : public ClangTidyCheck { -public: - MakeSmartPtrCheck(StringRef Name, ClangTidyContext *Context, - std::string makeSmartPtrFunctionName); - void registerMatchers(ast_matchers::MatchFinder *Finder) final; - void check(const ast_matchers::MatchFinder::MatchResult &Result) final; - -protected: - using SmartPtrTypeMatcher = ast_matchers::internal::BindableMatcher; - - /// Returns matcher that match with different smart pointer types. - /// - /// Requires to bind pointer type (qualType) with PointerType string declared - /// in this class. - virtual SmartPtrTypeMatcher getSmartPointerTypeMatcher() const = 0; - - static const char PointerType[]; - static const char ConstructorCall[]; - static const char NewExpression[]; - -private: - std::string makeSmartPtrFunctionName; -}; - -} // namespace modernize -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_SMART_PTR_H Index: clang-tidy/modernize/MakeSmartPtrCheck.cpp =================================================================== --- clang-tidy/modernize/MakeSmartPtrCheck.cpp +++ /dev/null @@ -1,150 +0,0 @@ -//===--- MakeSmartPtrCheck.cpp - clang-tidy--------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "MakeSharedCheck.h" -#include "clang/Lex/Lexer.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace modernize { - -const char MakeSmartPtrCheck::PointerType[] = "pointerType"; -const char MakeSmartPtrCheck::ConstructorCall[] = "constructorCall"; -const char MakeSmartPtrCheck::NewExpression[] = "newExpression"; - -MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, ClangTidyContext *Context, - std::string makeSmartPtrFunctionName) - : ClangTidyCheck(Name, Context), - makeSmartPtrFunctionName(std::move(makeSmartPtrFunctionName)) {} - -void MakeSmartPtrCheck::registerMatchers(ast_matchers::MatchFinder *Finder) { - if (!getLangOpts().CPlusPlus11) - return; - - Finder->addMatcher( - cxxBindTemporaryExpr(has(ignoringParenImpCasts( - cxxConstructExpr( - hasType(getSmartPointerTypeMatcher()), argumentCountIs(1), - hasArgument(0, - cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType( - equalsBoundNode(PointerType)))))) - .bind(NewExpression))) - .bind(ConstructorCall)))), - this); -} - -void MakeSmartPtrCheck::check(const MatchFinder::MatchResult &Result) { - // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other - // pointer, 'make_smart_ptr' refers to 'std::make_shared' or - // 'std::make_unique' or other function that creates smart_ptr. - - SourceManager &SM = *Result.SourceManager; - const auto *Construct = - Result.Nodes.getNodeAs(ConstructorCall); - const auto *Type = Result.Nodes.getNodeAs(PointerType); - const auto *New = Result.Nodes.getNodeAs(NewExpression); - - if (New->getNumPlacementArgs() != 0) - return; - - SourceLocation ConstructCallStart = Construct->getExprLoc(); - - bool Invalid = false; - StringRef ExprStr = Lexer::getSourceText( - CharSourceRange::getCharRange( - ConstructCallStart, Construct->getParenOrBraceRange().getBegin()), - SM, LangOptions(), &Invalid); - if (Invalid) - return; - - auto Diag = diag(ConstructCallStart, "use %0 instead") - << makeSmartPtrFunctionName; - - // Find the location of the template's left angle. - size_t LAngle = ExprStr.find("<"); - SourceLocation ConstructCallEnd; - if (LAngle == StringRef::npos) { - // If the template argument is missing (because it is part of the alias) - // we have to add it back. - ConstructCallEnd = ConstructCallStart.getLocWithOffset(ExprStr.size()); - Diag << FixItHint::CreateInsertion( - ConstructCallEnd, "<" + Type->getAsString(getLangOpts()) + ">"); - } else { - ConstructCallEnd = ConstructCallStart.getLocWithOffset(LAngle); - } - - Diag << FixItHint::CreateReplacement( - CharSourceRange::getCharRange(ConstructCallStart, ConstructCallEnd), - makeSmartPtrFunctionName); - - // If the smart_ptr is built with brace enclosed direct initialization, use - // parenthesis instead. - if (Construct->isListInitialization()) { - SourceRange BraceRange = Construct->getParenOrBraceRange(); - Diag << FixItHint::CreateReplacement( - CharSourceRange::getCharRange( - BraceRange.getBegin(), BraceRange.getBegin().getLocWithOffset(1)), - "("); - Diag << FixItHint::CreateReplacement( - CharSourceRange::getCharRange(BraceRange.getEnd(), - BraceRange.getEnd().getLocWithOffset(1)), - ")"); - } - - SourceLocation NewStart = New->getSourceRange().getBegin(); - SourceLocation NewEnd = New->getSourceRange().getEnd(); - switch (New->getInitializationStyle()) { - case CXXNewExpr::NoInit: { - Diag << FixItHint::CreateRemoval(SourceRange(NewStart, NewEnd)); - break; - } - case CXXNewExpr::CallInit: { - SourceRange InitRange = New->getDirectInitRange(); - Diag << FixItHint::CreateRemoval( - SourceRange(NewStart, InitRange.getBegin())); - Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), NewEnd)); - break; - } - case CXXNewExpr::ListInit: { - // Range of the substring that we do not want to remove. - SourceRange InitRange; - if (const auto *NewConstruct = New->getConstructExpr()) { - // Direct initialization with initialization list. - // struct S { S(int x) {} }; - // smart_ptr(new S{5}); - // The arguments in the initialization list are going to be forwarded to - // the constructor, so this has to be replaced with: - // struct S { S(int x) {} }; - // std::make_smart_ptr(5); - InitRange = SourceRange( - NewConstruct->getParenOrBraceRange().getBegin().getLocWithOffset(1), - NewConstruct->getParenOrBraceRange().getEnd().getLocWithOffset(-1)); - } else { - // Aggregate initialization. - // smart_ptr(new Pair{first, second}); - // Has to be replaced with: - // smart_ptr(Pair{first, second}); - InitRange = SourceRange( - New->getAllocatedTypeSourceInfo()->getTypeLoc().getLocStart(), - New->getInitializer()->getSourceRange().getEnd()); - } - Diag << FixItHint::CreateRemoval( - CharSourceRange::getCharRange(NewStart, InitRange.getBegin())); - Diag << FixItHint::CreateRemoval( - SourceRange(InitRange.getEnd().getLocWithOffset(1), NewEnd)); - break; - } - } -} - -} // namespace modernize -} // namespace tidy -} // namespace clang Index: clang-tidy/modernize/MakeUniqueCheck.h =================================================================== --- clang-tidy/modernize/MakeUniqueCheck.h +++ clang-tidy/modernize/MakeUniqueCheck.h @@ -10,7 +10,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_UNIQUE_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_UNIQUE_H -#include "MakeSmartPtrCheck.h" +#include "../ClangTidy.h" namespace clang { namespace tidy { @@ -25,12 +25,12 @@ /// \code /// std::make_unique(args...) /// \endcode -class MakeUniqueCheck : public MakeSmartPtrCheck { +class MakeUniqueCheck : public ClangTidyCheck { public: - MakeUniqueCheck(StringRef Name, ClangTidyContext *Context); - -protected: - SmartPtrTypeMatcher getSmartPointerTypeMatcher() const override; + MakeUniqueCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; }; } // namespace modernize Index: clang-tidy/modernize/MakeUniqueCheck.cpp =================================================================== --- clang-tidy/modernize/MakeUniqueCheck.cpp +++ clang-tidy/modernize/MakeUniqueCheck.cpp @@ -8,6 +8,9 @@ //===----------------------------------------------------------------------===// #include "MakeUniqueCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" using namespace clang::ast_matchers; @@ -15,24 +18,136 @@ namespace tidy { namespace modernize { -MakeUniqueCheck::MakeUniqueCheck(StringRef Name, - clang::tidy::ClangTidyContext *Context) - : MakeSmartPtrCheck(Name, Context, "std::make_unique") {} - -MakeUniqueCheck::SmartPtrTypeMatcher -MakeUniqueCheck::getSmartPointerTypeMatcher() const { - return qualType(hasDeclaration(classTemplateSpecializationDecl( - matchesName("::std::unique_ptr"), templateArgumentCountIs(2), - hasTemplateArgument( - 0, templateArgument(refersToType(qualType().bind(PointerType)))), - hasTemplateArgument( - 1, templateArgument(refersToType( - qualType(hasDeclaration(classTemplateSpecializationDecl( - matchesName("::std::default_delete"), - templateArgumentCountIs(1), - hasTemplateArgument( - 0, templateArgument(refersToType(qualType( - equalsBoundNode(PointerType)))))))))))))); +static const char PointerType[] = "pointerType"; +static const char ConstructorCall[] = "constructorCall"; +static const char NewExpression[] = "newExpression"; + +void MakeUniqueCheck::registerMatchers(MatchFinder *Finder) { + if (getLangOpts().CPlusPlus11) { + Finder->addMatcher( + cxxBindTemporaryExpr(has( + cxxConstructExpr( + hasType(qualType(hasDeclaration(classTemplateSpecializationDecl( + matchesName("::std::unique_ptr"), + templateArgumentCountIs(2), + hasTemplateArgument(0, templateArgument(refersToType( + qualType().bind(PointerType)))), + hasTemplateArgument( + 1, templateArgument(refersToType(qualType( + hasDeclaration(classTemplateSpecializationDecl( + matchesName("::std::default_delete"), + templateArgumentCountIs(1), + hasTemplateArgument( + 0, templateArgument(refersToType( + qualType(equalsBoundNode( + PointerType))))))))))))))), + argumentCountIs(1), + hasArgument( + 0, cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType( + equalsBoundNode(PointerType)))))) + .bind(NewExpression))) + .bind(ConstructorCall))), + this); + } +} + +void MakeUniqueCheck::check(const MatchFinder::MatchResult &Result) { + SourceManager &SM = *Result.SourceManager; + const auto *Construct = + Result.Nodes.getNodeAs(ConstructorCall); + const auto *Type = Result.Nodes.getNodeAs(PointerType); + const auto *New = Result.Nodes.getNodeAs(NewExpression); + + if (New->getNumPlacementArgs() != 0) + return; + + SourceLocation ConstructCallStart = Construct->getExprLoc(); + + bool Invalid = false; + StringRef ExprStr = Lexer::getSourceText( + CharSourceRange::getCharRange( + ConstructCallStart, Construct->getParenOrBraceRange().getBegin()), + SM, LangOptions(), &Invalid); + if (Invalid) + return; + + auto Diag = diag(ConstructCallStart, "use std::make_unique instead"); + + // Find the location of the template's left angle. + size_t LAngle = ExprStr.find("<"); + SourceLocation ConstructCallEnd; + if (LAngle == StringRef::npos) { + // If the template argument is missing (because it is part of the alias) + // we have to add it back. + ConstructCallEnd = ConstructCallStart.getLocWithOffset(ExprStr.size()); + Diag << FixItHint::CreateInsertion( + ConstructCallEnd, "<" + Type->getAsString(getLangOpts()) + ">"); + } else { + ConstructCallEnd = ConstructCallStart.getLocWithOffset(LAngle); + } + + Diag << FixItHint::CreateReplacement( + CharSourceRange::getCharRange(ConstructCallStart, ConstructCallEnd), + "std::make_unique"); + + // If the unique_ptr is built with brace enclosed direct initialization, use + // parenthesis instead. + if (Construct->isListInitialization()) { + SourceRange BraceRange = Construct->getParenOrBraceRange(); + Diag << FixItHint::CreateReplacement( + CharSourceRange::getCharRange( + BraceRange.getBegin(), BraceRange.getBegin().getLocWithOffset(1)), + "("); + Diag << FixItHint::CreateReplacement( + CharSourceRange::getCharRange(BraceRange.getEnd(), + BraceRange.getEnd().getLocWithOffset(1)), + ")"); + } + + SourceLocation NewStart = New->getSourceRange().getBegin(); + SourceLocation NewEnd = New->getSourceRange().getEnd(); + switch (New->getInitializationStyle()) { + case CXXNewExpr::NoInit: { + Diag << FixItHint::CreateRemoval(SourceRange(NewStart, NewEnd)); + break; + } + case CXXNewExpr::CallInit: { + SourceRange InitRange = New->getDirectInitRange(); + Diag << FixItHint::CreateRemoval( + SourceRange(NewStart, InitRange.getBegin())); + Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), NewEnd)); + break; + } + case CXXNewExpr::ListInit: { + // Range of the substring that we do not want to remove. + SourceRange InitRange; + if (const auto *NewConstruct = New->getConstructExpr()) { + // Direct initialization with initialization list. + // struct S { S(int x) {} }; + // std::unique_ptr(new S{5}); + // The arguments in the initialization list are going to be forwarded to + // the constructor, so this has to be replaced with: + // struct S { S(int x) {} }; + // std::make_unique(5); + InitRange = SourceRange( + NewConstruct->getParenOrBraceRange().getBegin().getLocWithOffset(1), + NewConstruct->getParenOrBraceRange().getEnd().getLocWithOffset(-1)); + } else { + // Aggregate initialization. + // std::unique_ptr(new Pair{first, second}); + // Has to be replaced with: + // std::make_unique(Pair{first, second}); + InitRange = SourceRange( + New->getAllocatedTypeSourceInfo()->getTypeLoc().getLocStart(), + New->getInitializer()->getSourceRange().getEnd()); + } + Diag << FixItHint::CreateRemoval( + CharSourceRange::getCharRange(NewStart, InitRange.getBegin())); + Diag << FixItHint::CreateRemoval( + SourceRange(InitRange.getEnd().getLocWithOffset(1), NewEnd)); + break; + } + } } } // namespace modernize Index: clang-tidy/modernize/ModernizeTidyModule.cpp =================================================================== --- clang-tidy/modernize/ModernizeTidyModule.cpp +++ clang-tidy/modernize/ModernizeTidyModule.cpp @@ -10,10 +10,8 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" -#include "AvoidBindCheck.h" #include "DeprecatedHeadersCheck.h" #include "LoopConvertCheck.h" -#include "MakeSharedCheck.h" #include "MakeUniqueCheck.h" #include "PassByValueCheck.h" #include "RawStringLiteralCheck.h" @@ -21,12 +19,9 @@ #include "ReplaceAutoPtrCheck.h" #include "ShrinkToFitCheck.h" #include "UseAutoCheck.h" -#include "UseBoolLiteralsCheck.h" #include "UseDefaultCheck.h" -#include "UseEmplaceCheck.h" #include "UseNullptrCheck.h" #include "UseOverrideCheck.h" -#include "UseUsingCheck.h" using namespace clang::ast_matchers; @@ -37,12 +32,9 @@ class ModernizeModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { - CheckFactories.registerCheck( - "modernize-avoid-bind"); CheckFactories.registerCheck( "modernize-deprecated-headers"); CheckFactories.registerCheck("modernize-loop-convert"); - CheckFactories.registerCheck("modernize-make-shared"); CheckFactories.registerCheck("modernize-make-unique"); CheckFactories.registerCheck("modernize-pass-by-value"); CheckFactories.registerCheck( @@ -53,13 +45,9 @@ "modernize-replace-auto-ptr"); CheckFactories.registerCheck("modernize-shrink-to-fit"); CheckFactories.registerCheck("modernize-use-auto"); - CheckFactories.registerCheck( - "modernize-use-bool-literals"); CheckFactories.registerCheck("modernize-use-default"); - CheckFactories.registerCheck("modernize-use-emplace"); CheckFactories.registerCheck("modernize-use-nullptr"); CheckFactories.registerCheck("modernize-use-override"); - CheckFactories.registerCheck("modernize-use-using"); } ClangTidyOptions getModuleOptions() override { Index: clang-tidy/modernize/PassByValueCheck.h =================================================================== --- clang-tidy/modernize/PassByValueCheck.h +++ clang-tidy/modernize/PassByValueCheck.h @@ -28,8 +28,8 @@ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; private: - std::unique_ptr Inserter; - const utils::IncludeSorter::IncludeStyle IncludeStyle; + std::unique_ptr Inserter; + const IncludeSorter::IncludeStyle IncludeStyle; }; } // namespace modernize Index: clang-tidy/modernize/PassByValueCheck.cpp =================================================================== --- clang-tidy/modernize/PassByValueCheck.cpp +++ clang-tidy/modernize/PassByValueCheck.cpp @@ -118,44 +118,43 @@ PassByValueCheck::PassByValueCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), - IncludeStyle(utils::IncludeSorter::parseIncludeStyle( + IncludeStyle(IncludeSorter::parseIncludeStyle( Options.get("IncludeStyle", "llvm"))) {} void PassByValueCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { - Options.store(Opts, "IncludeStyle", - utils::IncludeSorter::toString(IncludeStyle)); + Options.store(Opts, "IncludeStyle", IncludeSorter::toString(IncludeStyle)); } void PassByValueCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not // provide any benefit to other languages, despite being benign. - if (!getLangOpts().CPlusPlus) - return; - - Finder->addMatcher( - cxxConstructorDecl( - forEachConstructorInitializer( - cxxCtorInitializer( - // Clang builds a CXXConstructExpr only whin it knows which - // constructor will be called. In dependent contexts a - // ParenListExpr is generated instead of a CXXConstructExpr, - // filtering out templates automatically for us. - withInitializer(cxxConstructExpr( - has(ignoringParenImpCasts(declRefExpr(to( - parmVarDecl( - hasType(qualType( - // Match only const-ref or a non-const value - // parameters. Rvalues and const-values - // shouldn't be modified. - anyOf(constRefType(), nonConstValueType())))) - .bind("Param"))))), - hasDeclaration(cxxConstructorDecl( - isCopyConstructor(), unless(isDeleted()), - hasDeclContext( - cxxRecordDecl(isMoveConstructible()))))))) - .bind("Initializer"))) - .bind("Ctor"), - this); + if (getLangOpts().CPlusPlus) { + Finder->addMatcher( + cxxConstructorDecl( + forEachConstructorInitializer( + cxxCtorInitializer( + // Clang builds a CXXConstructExpr only whin it knows which + // constructor will be called. In dependent contexts a + // ParenListExpr is generated instead of a CXXConstructExpr, + // filtering out templates automatically for us. + withInitializer(cxxConstructExpr( + has(declRefExpr(to( + parmVarDecl( + hasType(qualType( + // Match only const-ref or a non-const value + // parameters. Rvalues and const-values + // shouldn't be modified. + anyOf(constRefType(), + nonConstValueType())))) + .bind("Param")))), + hasDeclaration(cxxConstructorDecl( + isCopyConstructor(), unless(isDeleted()), + hasDeclContext( + cxxRecordDecl(isMoveConstructible()))))))) + .bind("Initializer"))) + .bind("Ctor"), + this); + } } void PassByValueCheck::registerPPCallbacks(CompilerInstance &Compiler) { @@ -163,8 +162,8 @@ // currently does not provide any benefit to other languages, despite being // benign. if (getLangOpts().CPlusPlus) { - Inserter.reset(new utils::IncludeInserter( - Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle)); + Inserter.reset(new IncludeInserter(Compiler.getSourceManager(), + Compiler.getLangOpts(), IncludeStyle)); Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks()); } } @@ -181,11 +180,6 @@ if (!paramReferredExactlyOnce(Ctor, ParamDecl)) return; - // If the parameter is trivial to copy, don't move it. Moving a trivivally - // copyable type will cause a problem with misc-move-const-arg - if (ParamDecl->getType().isTriviallyCopyableType(*Result.Context)) - return; - auto Diag = diag(ParamDecl->getLocStart(), "pass by value and use std::move"); // Iterate over all declarations of the constructor. Index: clang-tidy/modernize/RawStringLiteralCheck.h =================================================================== --- clang-tidy/modernize/RawStringLiteralCheck.h +++ clang-tidy/modernize/RawStringLiteralCheck.h @@ -11,6 +11,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_RAW_STRING_LITERAL_H #include "../ClangTidy.h" +//#include namespace clang { namespace tidy { Index: clang-tidy/modernize/RedundantVoidArgCheck.cpp =================================================================== --- clang-tidy/modernize/RedundantVoidArgCheck.cpp +++ clang-tidy/modernize/RedundantVoidArgCheck.cpp @@ -14,8 +14,6 @@ using namespace clang::ast_matchers; namespace clang { -namespace tidy { -namespace modernize { namespace { @@ -44,6 +42,9 @@ } // namespace +namespace tidy { +namespace modernize { + void RedundantVoidArgCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher(functionDecl(parameterCountIs(0), unless(isImplicit()), unless(isExternC())) Index: clang-tidy/modernize/ReplaceAutoPtrCheck.h =================================================================== --- clang-tidy/modernize/ReplaceAutoPtrCheck.h +++ clang-tidy/modernize/ReplaceAutoPtrCheck.h @@ -50,8 +50,8 @@ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; private: - std::unique_ptr Inserter; - const utils::IncludeSorter::IncludeStyle IncludeStyle; + std::unique_ptr Inserter; + const IncludeSorter::IncludeStyle IncludeStyle; }; } // namespace modernize Index: clang-tidy/modernize/ReplaceAutoPtrCheck.cpp =================================================================== --- clang-tidy/modernize/ReplaceAutoPtrCheck.cpp +++ clang-tidy/modernize/ReplaceAutoPtrCheck.cpp @@ -189,12 +189,11 @@ ReplaceAutoPtrCheck::ReplaceAutoPtrCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), - IncludeStyle(utils::IncludeSorter::parseIncludeStyle( + IncludeStyle(IncludeSorter::parseIncludeStyle( Options.get("IncludeStyle", "llvm"))) {} void ReplaceAutoPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { - Options.store(Opts, "IncludeStyle", - utils::IncludeSorter::toString(IncludeStyle)); + Options.store(Opts, "IncludeStyle", IncludeSorter::toString(IncludeStyle)); } void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) { @@ -212,8 +211,8 @@ // currently does not provide any benefit to other languages, despite being // benign. if (getLangOpts().CPlusPlus) { - Inserter.reset(new utils::IncludeInserter( - Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle)); + Inserter.reset(new IncludeInserter(Compiler.getSourceManager(), + Compiler.getLangOpts(), IncludeStyle)); Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks()); } } Index: clang-tidy/modernize/ShrinkToFitCheck.cpp =================================================================== --- clang-tidy/modernize/ShrinkToFitCheck.cpp +++ clang-tidy/modernize/ShrinkToFitCheck.cpp @@ -26,26 +26,24 @@ memberExpr(member(valueDecl().bind("ContainerDecl"))); const auto ShrinkableAsDecl = declRefExpr(hasDeclaration(valueDecl().bind("ContainerDecl"))); - const auto CopyCtorCall = cxxConstructExpr(hasArgument( - 0, anyOf(ShrinkableAsMember, ShrinkableAsDecl, - unaryOperator(has(ignoringParenImpCasts(ShrinkableAsMember))), - unaryOperator(has(ignoringParenImpCasts(ShrinkableAsDecl)))))); - const auto SwapParam = - expr(anyOf(memberExpr(member(equalsBoundNode("ContainerDecl"))), - declRefExpr(hasDeclaration(equalsBoundNode("ContainerDecl"))), - unaryOperator(has(ignoringParenImpCasts( - memberExpr(member(equalsBoundNode("ContainerDecl")))))), - unaryOperator(has(ignoringParenImpCasts(declRefExpr( - hasDeclaration(equalsBoundNode("ContainerDecl")))))))); + const auto CopyCtorCall = cxxConstructExpr( + hasArgument(0, anyOf(ShrinkableAsMember, ShrinkableAsDecl, + unaryOperator(has(ShrinkableAsMember)), + unaryOperator(has(ShrinkableAsDecl))))); + const auto SwapParam = expr(anyOf( + memberExpr(member(equalsBoundNode("ContainerDecl"))), + declRefExpr(hasDeclaration(equalsBoundNode("ContainerDecl"))), + unaryOperator(has(memberExpr(member(equalsBoundNode("ContainerDecl"))))), + unaryOperator( + has(declRefExpr(hasDeclaration(equalsBoundNode("ContainerDecl"))))))); Finder->addMatcher( - cxxMemberCallExpr( - on(hasType(namedDecl( - hasAnyName("std::basic_string", "std::deque", "std::vector")))), - callee(cxxMethodDecl(hasName("swap"))), - has(ignoringParenImpCasts(memberExpr(hasDescendant(CopyCtorCall)))), - hasArgument(0, SwapParam.bind("ContainerToShrink")), - unless(isInTemplateInstantiation())) + cxxMemberCallExpr(on(hasType(namedDecl( + hasAnyName("std::basic_string", "std::deque", "std::vector")))), + callee(cxxMethodDecl(hasName("swap"))), + has(memberExpr(hasDescendant(CopyCtorCall))), + hasArgument(0, SwapParam.bind("ContainerToShrink")), + unless(isInTemplateInstantiation())) .bind("CopyAndSwapTrick"), this); } Index: clang-tidy/modernize/UseAutoCheck.h =================================================================== --- clang-tidy/modernize/UseAutoCheck.h +++ clang-tidy/modernize/UseAutoCheck.h @@ -18,16 +18,15 @@ class UseAutoCheck : public ClangTidyCheck { public: - UseAutoCheck(StringRef Name, ClangTidyContext *Context); - void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + UseAutoCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; private: void replaceIterators(const DeclStmt *D, ASTContext *Context); void replaceNew(const DeclStmt *D, ASTContext *Context); - - const bool RemoveStars; }; } // namespace modernize Index: clang-tidy/modernize/UseAutoCheck.cpp =================================================================== --- clang-tidy/modernize/UseAutoCheck.cpp +++ clang-tidy/modernize/UseAutoCheck.cpp @@ -42,8 +42,6 @@ if (!Init) return false; - Init = Init->IgnoreImplicit(); - // The following test is based on DeclPrinter::VisitVarDecl() to find if an // initializer is implicit or not. if (const auto *Construct = dyn_cast(Init)) { @@ -245,14 +243,6 @@ } // namespace -UseAutoCheck::UseAutoCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context), - RemoveStars(Options.get("RemoveStars", 0)) {} - -void UseAutoCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { - Options.store(Opts, "RemoveStars", RemoveStars ? 1 : 0); -} - void UseAutoCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not // provide any benefit to other languages, despite being benign. @@ -321,7 +311,7 @@ const QualType FirstDeclType = FirstDecl->getType().getCanonicalType(); - std::vector StarRemovals; + std::vector StarLocations; for (const auto *Dec : D->decls()) { const auto *V = cast(Dec); // Ensure that every DeclStmt child is a VarDecl. @@ -337,23 +327,19 @@ if (!Context->hasSameUnqualifiedType(V->getType(), NewExpr->getType())) return; - // All subsequent variables in this declaration should have the same - // canonical type. For example, we don't want to use `auto` in - // `T *p = new T, **pp = new T*;`. + // Remove explicitly written '*' from declarations where there's more than + // one declaration in the declaration list. + if (Dec == *D->decl_begin()) + continue; + + // All subsequent declarations should match the same non-decorated type. if (FirstDeclType != V->getType().getCanonicalType()) return; - if (RemoveStars) { - // Remove explicitly written '*' from declarations where there's more than - // one declaration in the declaration list. - if (Dec == *D->decl_begin()) - continue; - - auto Q = V->getTypeSourceInfo()->getTypeLoc().getAs(); - while (!Q.isNull()) { - StarRemovals.push_back(FixItHint::CreateRemoval(Q.getStarLoc())); - Q = Q.getNextTypeLoc().getAs(); - } + auto Q = V->getTypeSourceInfo()->getTypeLoc().getAs(); + while (!Q.isNull()) { + StarLocations.push_back(Q.getStarLoc()); + Q = Q.getNextTypeLoc().getAs(); } } @@ -361,20 +347,19 @@ // is the same as the initializer, just more CV-qualified. However, TypeLoc // information is not reliable where CV qualifiers are concerned so we can't // do anything about this case for now. - TypeLoc Loc = FirstDecl->getTypeSourceInfo()->getTypeLoc(); - if (!RemoveStars) { - while (Loc.getTypeLocClass() == TypeLoc::Pointer || - Loc.getTypeLocClass() == TypeLoc::Qualified) - Loc = Loc.getNextTypeLoc(); - } - SourceRange Range(Loc.getSourceRange()); + SourceRange Range( + FirstDecl->getTypeSourceInfo()->getTypeLoc().getSourceRange()); auto Diag = diag(Range.getBegin(), "use auto when initializing with new" " to avoid duplicating the type name"); // Space after 'auto' to handle cases where the '*' in the pointer type is // next to the identifier. This avoids changing 'int *p' into 'autop'. - Diag << FixItHint::CreateReplacement(Range, RemoveStars ? "auto " : "auto") - << StarRemovals; + Diag << FixItHint::CreateReplacement(Range, "auto "); + + // Remove '*' from declarations using the saved star locations. + for (const auto &Loc : StarLocations) { + Diag << FixItHint::CreateReplacement(Loc, ""); + } } void UseAutoCheck::check(const MatchFinder::MatchResult &Result) { Index: clang-tidy/modernize/UseBoolLiteralsCheck.h =================================================================== --- clang-tidy/modernize/UseBoolLiteralsCheck.h +++ /dev/null @@ -1,35 +0,0 @@ -//===--- UseBoolLiteralsCheck.h - clang-tidy---------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_BOOL_LITERALS_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_BOOL_LITERALS_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace modernize { - -/// Finds integer literals which are cast to bool. -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-bool-literals.html -class UseBoolLiteralsCheck : public ClangTidyCheck { -public: - UseBoolLiteralsCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -}; - -} // namespace modernize -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_BOOL_LITERALS_H Index: clang-tidy/modernize/UseBoolLiteralsCheck.cpp =================================================================== --- clang-tidy/modernize/UseBoolLiteralsCheck.cpp +++ /dev/null @@ -1,55 +0,0 @@ -//===--- UseBoolLiteralsCheck.cpp - clang-tidy-----------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "UseBoolLiteralsCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Lex/Lexer.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace modernize { - -void UseBoolLiteralsCheck::registerMatchers(MatchFinder *Finder) { - if (!getLangOpts().CPlusPlus) - return; - - Finder->addMatcher( - implicitCastExpr( - has(ignoringParenImpCasts(integerLiteral().bind("literal"))), - hasImplicitDestinationType(qualType(booleanType())), - unless(isInTemplateInstantiation()), - anyOf(hasParent(explicitCastExpr().bind("cast")), anything())), - this); -} - -void UseBoolLiteralsCheck::check(const MatchFinder::MatchResult &Result) { - const auto *Literal = Result.Nodes.getNodeAs("literal"); - const auto *Cast = Result.Nodes.getNodeAs("cast"); - bool LiteralBooleanValue = Literal->getValue().getBoolValue(); - - if (Literal->isInstantiationDependent()) - return; - - const Expr *Expression = Cast ? Cast : Literal; - - auto Diag = - diag(Expression->getExprLoc(), - "converting integer literal to bool, use bool literal instead"); - - if (!Expression->getLocStart().isMacroID()) - Diag << FixItHint::CreateReplacement( - Expression->getSourceRange(), LiteralBooleanValue ? "true" : "false"); -} - -} // namespace modernize -} // namespace tidy -} // namespace clang Index: clang-tidy/modernize/UseDefaultCheck.cpp =================================================================== --- clang-tidy/modernize/UseDefaultCheck.cpp +++ clang-tidy/modernize/UseDefaultCheck.cpp @@ -160,8 +160,8 @@ // statement: // return *this; if (Compound->body_empty() || - match(returnStmt(has(ignoringParenImpCasts(unaryOperator( - hasOperatorName("*"), hasUnaryOperand(cxxThisExpr()))))), + match(returnStmt(has(unaryOperator(hasOperatorName("*"), + hasUnaryOperand(cxxThisExpr())))), *Compound->body_back(), *Context) .empty()) return false; @@ -175,21 +175,21 @@ // ((Base*)this)->operator=((Base)Other); // // So we are looking for a member call that fulfills: - if (match(compoundStmt(has(ignoringParenImpCasts(cxxMemberCallExpr(allOf( - // - The object is an implicit cast of 'this' to a pointer to - // a base class. - onImplicitObjectArgument( - implicitCastExpr(hasImplicitDestinationType( - pointsTo(type(equalsNode(Base)))), - hasSourceExpression(cxxThisExpr()))), - // - The called method is the operator=. - callee(cxxMethodDecl(isCopyAssignmentOperator())), - // - The argument is (an implicit cast to a Base of) the - // argument taken by "Operator". - argumentCountIs(1), - hasArgument(0, - declRefExpr(to(varDecl(equalsNode(Param)))))))))), - *Compound, *Context) + if (match( + compoundStmt(has(cxxMemberCallExpr(allOf( + // - The object is an implicit cast of 'this' to a pointer to + // a base class. + onImplicitObjectArgument( + implicitCastExpr(hasImplicitDestinationType( + pointsTo(type(equalsNode(Base)))), + hasSourceExpression(cxxThisExpr()))), + // - The called method is the operator=. + callee(cxxMethodDecl(isCopyAssignmentOperator())), + // - The argument is (an implicit cast to a Base of) the + // argument taken by "Operator". + argumentCountIs(1), + hasArgument(0, declRefExpr(to(varDecl(equalsNode(Param))))))))), + *Compound, *Context) .empty()) return false; } @@ -204,11 +204,11 @@ member(fieldDecl(equalsNode(Field)))); auto RHS = accessToFieldInVar(Field, Param); if (match( - compoundStmt(has(ignoringParenImpCasts(stmt(anyOf( + compoundStmt(has(stmt(anyOf( binaryOperator(hasOperatorName("="), hasLHS(LHS), hasRHS(RHS)), cxxOperatorCallExpr(hasOverloadedOperatorName("="), argumentCountIs(2), hasArgument(0, LHS), - hasArgument(1, RHS))))))), + hasArgument(1, RHS)))))), *Compound, *Context) .empty()) return false; Index: clang-tidy/modernize/UseEmplaceCheck.h =================================================================== --- clang-tidy/modernize/UseEmplaceCheck.h +++ /dev/null @@ -1,38 +0,0 @@ -//===--- UseEmplaceCheck.h - clang-tidy--------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EMPLACE_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EMPLACE_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace modernize { - -/// This check looks for cases when inserting new element into std::vector but -/// the element is constructed temporarily. -/// It replaces those calls for emplace_back of arguments passed to -/// constructor of temporary object. -///` -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-emplace.html -class UseEmplaceCheck : public ClangTidyCheck { -public: - UseEmplaceCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -}; - -} // namespace modernize -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EMPLACE_H Index: clang-tidy/modernize/UseEmplaceCheck.cpp =================================================================== --- clang-tidy/modernize/UseEmplaceCheck.cpp +++ /dev/null @@ -1,104 +0,0 @@ -//===--- UseEmplaceCheck.cpp - clang-tidy----------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "UseEmplaceCheck.h" -#include "../utils/Matchers.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace modernize { - -void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) { - if (!getLangOpts().CPlusPlus11) - return; - - // FIXME: Bunch of functionality that could be easily added: - // + add handling of `push_front` for std::forward_list, std::list - // and std::deque. - // + add handling of `push` for std::stack, std::queue, std::priority_queue - // + add handling of `insert` for stl associative container, but be careful - // because this requires special treatment (it could cause performance - // regression) - // + match for emplace calls that should be replaced with insertion - // + match for make_pair calls. - auto callPushBack = cxxMemberCallExpr( - hasDeclaration(functionDecl(hasName("push_back"))), - on(hasType(cxxRecordDecl(hasAnyName("std::vector", "llvm::SmallVector", - "std::list", "std::deque"))))); - - // We can't replace push_backs of smart pointer because - // if emplacement fails (f.e. bad_alloc in vector) we will have leak of - // passed pointer because smart pointer won't be constructed - // (and destructed) as in push_back case. - auto isCtorOfSmartPtr = hasDeclaration(cxxConstructorDecl( - ofClass(hasAnyName("std::shared_ptr", "std::unique_ptr", "std::auto_ptr", - "std::weak_ptr")))); - - // Bitfields binds only to consts and emplace_back take it by universal ref. - auto bitFieldAsArgument = hasAnyArgument(ignoringParenImpCasts( - memberExpr(hasDeclaration(fieldDecl(matchers::isBitfield()))))); - - // We could have leak of resource. - auto newExprAsArgument = hasAnyArgument(ignoringParenImpCasts(cxxNewExpr())); - auto constructingDerived = - hasParent(implicitCastExpr(hasCastKind(CastKind::CK_DerivedToBase))); - - auto hasInitList = has(ignoringParenImpCasts(initListExpr())); - auto soughtConstructExpr = - cxxConstructExpr( - unless(anyOf(isCtorOfSmartPtr, hasInitList, bitFieldAsArgument, - newExprAsArgument, constructingDerived, - has(materializeTemporaryExpr(hasInitList))))) - .bind("ctor"); - auto hasConstructExpr = has(ignoringParenImpCasts(soughtConstructExpr)); - - auto ctorAsArgument = materializeTemporaryExpr( - anyOf(hasConstructExpr, has(cxxFunctionalCastExpr(hasConstructExpr)))); - - Finder->addMatcher( - cxxMemberCallExpr(callPushBack, has(ctorAsArgument)).bind("call"), this); -} - -void UseEmplaceCheck::check(const MatchFinder::MatchResult &Result) { - const auto *Call = Result.Nodes.getNodeAs("call"); - const auto *InnerCtorCall = Result.Nodes.getNodeAs("ctor"); - - auto FunctionNameSourceRange = CharSourceRange::getCharRange( - Call->getExprLoc(), Call->getArg(0)->getExprLoc()); - - auto Diag = diag(Call->getExprLoc(), "use emplace_back instead of push_back"); - - if (FunctionNameSourceRange.getBegin().isMacroID()) - return; - - Diag << FixItHint::CreateReplacement(FunctionNameSourceRange, - "emplace_back("); - - auto CallParensRange = InnerCtorCall->getParenOrBraceRange(); - - // Finish if there is no explicit constructor call. - if (CallParensRange.getBegin().isInvalid()) - return; - - // Range for constructor name and opening brace. - auto CtorCallSourceRange = CharSourceRange::getCharRange( - InnerCtorCall->getExprLoc(), - CallParensRange.getBegin().getLocWithOffset(1)); - - Diag << FixItHint::CreateRemoval(CtorCallSourceRange) - << FixItHint::CreateRemoval(CharSourceRange::getCharRange( - CallParensRange.getEnd(), - CallParensRange.getEnd().getLocWithOffset(1))); -} - -} // namespace modernize -} // namespace tidy -} // namespace clang Index: clang-tidy/modernize/UseNullptrCheck.cpp =================================================================== --- clang-tidy/modernize/UseNullptrCheck.cpp +++ clang-tidy/modernize/UseNullptrCheck.cpp @@ -24,6 +24,20 @@ const char CastSequence[] = "sequence"; +/// \brief Matches cast expressions that have a cast kind of CK_NullToPointer +/// or CK_NullToMemberPointer. +/// +/// Given +/// \code +/// int *p = 0; +/// \endcode +/// implicitCastExpr(isNullToPointer()) matches the implicit cast clang adds +/// around \c 0. +AST_MATCHER(CastExpr, isNullToPointer) { + return Node.getCastKind() == CK_NullToPointer || + Node.getCastKind() == CK_NullToMemberPointer; +} + AST_MATCHER(Type, sugaredNullptrType) { const Type *DesugaredType = Node.getUnqualifiedDesugaredType(); if (const BuiltinType *BT = dyn_cast(DesugaredType)) @@ -38,8 +52,7 @@ /// can be replaced instead of just the inner-most implicit cast. StatementMatcher makeCastSequenceMatcher() { StatementMatcher ImplicitCastToNull = implicitCastExpr( - anyOf(hasCastKind(CK_NullToPointer), - hasCastKind(CK_NullToMemberPointer)), + isNullToPointer(), unless(hasSourceExpression(hasType(sugaredNullptrType())))); return castExpr(anyOf(ImplicitCastToNull, Index: clang-tidy/modernize/UseUsingCheck.h =================================================================== --- clang-tidy/modernize/UseUsingCheck.h +++ /dev/null @@ -1,35 +0,0 @@ -//===--- UseUsingCheck.h - clang-tidy----------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_USING_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_USING_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace modernize { - -/// Check finds typedefs and replaces it with usings. -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-using.html -class UseUsingCheck : public ClangTidyCheck { -public: - UseUsingCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -}; - -} // namespace modernize -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_USING_H Index: clang-tidy/modernize/UseUsingCheck.cpp =================================================================== --- clang-tidy/modernize/UseUsingCheck.cpp +++ /dev/null @@ -1,93 +0,0 @@ -//===--- UseUsingCheck.cpp - clang-tidy------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "UseUsingCheck.h" -#include "../utils/LexerUtils.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace modernize { - -void UseUsingCheck::registerMatchers(MatchFinder *Finder) { - if (!getLangOpts().CPlusPlus11) - return; - Finder->addMatcher(typedefDecl().bind("typedef"), this); -} - -// Checks if 'typedef' keyword can be removed - we do it only if -// it is the only declaration in a declaration chain. -static bool CheckRemoval(SourceManager &SM, const SourceLocation &LocStart, - const SourceLocation &LocEnd, ASTContext &Context, - SourceRange &ResultRange) { - FileID FID = SM.getFileID(LocEnd); - llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, LocEnd); - Lexer DeclLexer(SM.getLocForStartOfFile(FID), Context.getLangOpts(), - Buffer->getBufferStart(), SM.getCharacterData(LocStart), - Buffer->getBufferEnd()); - Token DeclToken; - bool result = false; - int parenthesisLevel = 0; - - while (!DeclLexer.LexFromRawLexer(DeclToken)) { - if (DeclToken.getKind() == tok::TokenKind::l_paren) - parenthesisLevel++; - if (DeclToken.getKind() == tok::TokenKind::r_paren) - parenthesisLevel--; - if (DeclToken.getKind() == tok::TokenKind::semi) - break; - // if there is comma and we are not between open parenthesis then it is - // two or more declatarions in this chain - if (parenthesisLevel == 0 && DeclToken.getKind() == tok::TokenKind::comma) - return false; - - if (DeclToken.isOneOf(tok::TokenKind::identifier, - tok::TokenKind::raw_identifier)) { - auto TokenStr = DeclToken.getRawIdentifier().str(); - - if (TokenStr == "typedef") { - ResultRange = - SourceRange(DeclToken.getLocation(), DeclToken.getEndLoc()); - result = true; - } - } - } - // assert if there was keyword 'typedef' in declaration - assert(result && "No typedef found"); - - return result; -} - -void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { - const auto *MatchedDecl = Result.Nodes.getNodeAs("typedef"); - if (MatchedDecl->getLocation().isInvalid()) - return; - - auto &Context = *Result.Context; - auto &SM = *Result.SourceManager; - - auto Diag = - diag(MatchedDecl->getLocStart(), "use 'using' instead of 'typedef'"); - if (MatchedDecl->getLocStart().isMacroID()) { - return; - } - SourceRange RemovalRange; - if (CheckRemoval(SM, MatchedDecl->getLocStart(), MatchedDecl->getLocEnd(), - Context, RemovalRange)) { - Diag << FixItHint::CreateReplacement( - MatchedDecl->getSourceRange(), - "using " + MatchedDecl->getNameAsString() + " = " + - MatchedDecl->getUnderlyingType().getAsString(getLangOpts())); - } -} - -} // namespace modernize -} // namespace tidy -} // namespace clang Index: clang-tidy/performance/FasterStringFindCheck.cpp =================================================================== --- clang-tidy/performance/FasterStringFindCheck.cpp +++ clang-tidy/performance/FasterStringFindCheck.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "FasterStringFindCheck.h" -#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "llvm/ADT/Optional.h" @@ -22,6 +21,20 @@ namespace { +static const char StringLikeClassesDelimiter[] = ";"; + +std::vector ParseClasses(StringRef Option) { + SmallVector Classes; + Option.split(Classes, StringLikeClassesDelimiter); + std::vector Result; + for (StringRef &Class : Classes) { + Class = Class.trim(); + if (!Class.empty()) + Result.push_back(Class); + } + return Result; +} + llvm::Optional MakeCharacterLiteral(const StringLiteral *Literal) { std::string Result; { @@ -38,6 +51,8 @@ return Result; } +AST_MATCHER(StringLiteral, lengthIsOne) { return Node.getLength() == 1; } + AST_MATCHER_FUNCTION(ast_matchers::internal::Matcher, hasSubstitutedType) { return hasType(qualType(anyOf(substTemplateTypeParmType(), @@ -49,13 +64,14 @@ FasterStringFindCheck::FasterStringFindCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), - StringLikeClasses(utils::options::parseStringList( - Options.get("StringLikeClasses", "std::basic_string"))) { + StringLikeClasses( + ParseClasses(Options.get("StringLikeClasses", "std::basic_string"))) { } void FasterStringFindCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "StringLikeClasses", - utils::options::serializeStringList(StringLikeClasses)); + llvm::join(StringLikeClasses.begin(), StringLikeClasses.end(), + StringLikeClassesDelimiter)); } void FasterStringFindCheck::registerMatchers(MatchFinder *Finder) { @@ -63,7 +79,7 @@ return; const auto SingleChar = - expr(ignoringParenCasts(stringLiteral(hasSize(1)).bind("literal"))); + expr(ignoringParenCasts(stringLiteral(lengthIsOne()).bind("literal"))); const auto StringFindFunctions = anyOf(hasName("find"), hasName("rfind"), hasName("find_first_of"), Index: clang-tidy/performance/ForRangeCopyCheck.cpp =================================================================== --- clang-tidy/performance/ForRangeCopyCheck.cpp +++ clang-tidy/performance/ForRangeCopyCheck.cpp @@ -12,12 +12,12 @@ #include "../utils/FixItHintUtils.h" #include "../utils/TypeTraits.h" -using namespace clang::ast_matchers; - namespace clang { namespace tidy { namespace performance { +using namespace ::clang::ast_matchers; + ForRangeCopyCheck::ForRangeCopyCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), WarnOnAllAutoCopies(Options.get("WarnOnAllAutoCopies", 0)) {} @@ -59,16 +59,16 @@ return false; } llvm::Optional Expensive = - utils::type_traits::isExpensiveToCopy(LoopVar.getType(), Context); + type_traits::isExpensiveToCopy(LoopVar.getType(), Context); if (!Expensive || !*Expensive) return false; auto Diagnostic = diag(LoopVar.getLocation(), "the loop variable's type is not a reference type; this creates a " "copy in each iteration; consider making this a reference") - << utils::fixit::changeVarDeclToReference(LoopVar, Context); + << utils::create_fix_it::changeVarDeclToReference(LoopVar, Context); if (!LoopVar.getType().isConstQualified()) - Diagnostic << utils::fixit::changeVarDeclToConst(LoopVar); + Diagnostic << utils::create_fix_it::changeVarDeclToConst(LoopVar); return true; } @@ -76,17 +76,16 @@ const VarDecl &LoopVar, const CXXForRangeStmt &ForRange, ASTContext &Context) { llvm::Optional Expensive = - utils::type_traits::isExpensiveToCopy(LoopVar.getType(), Context); + type_traits::isExpensiveToCopy(LoopVar.getType(), Context); if (LoopVar.getType().isConstQualified() || !Expensive || !*Expensive) return false; - if (!utils::decl_ref_expr::isOnlyUsedAsConst(LoopVar, *ForRange.getBody(), - Context)) + if (!decl_ref_expr_utils::isOnlyUsedAsConst(LoopVar, *ForRange.getBody(), Context)) return false; diag(LoopVar.getLocation(), "loop variable is copied but only used as const reference; consider " "making it a const reference") - << utils::fixit::changeVarDeclToConst(LoopVar) - << utils::fixit::changeVarDeclToReference(LoopVar, Context); + << utils::create_fix_it::changeVarDeclToConst(LoopVar) + << utils::create_fix_it::changeVarDeclToReference(LoopVar, Context); return true; } Index: clang-tidy/performance/ImplicitCastInLoopCheck.cpp =================================================================== --- clang-tidy/performance/ImplicitCastInLoopCheck.cpp +++ clang-tidy/performance/ImplicitCastInLoopCheck.cpp @@ -15,9 +15,10 @@ #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Lex/Lexer.h" -using namespace clang::ast_matchers; - namespace clang { + +using namespace ast_matchers; + namespace tidy { namespace performance { Index: clang-tidy/performance/UnnecessaryCopyInitialization.h =================================================================== --- clang-tidy/performance/UnnecessaryCopyInitialization.h +++ clang-tidy/performance/UnnecessaryCopyInitialization.h @@ -33,11 +33,9 @@ private: void handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt, - bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context); void handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar, - const Stmt &BlockStmt, bool IssueFix, - ASTContext &Context); + const Stmt &BlockStmt, ASTContext &Context); }; } // namespace performance Index: clang-tidy/performance/UnnecessaryCopyInitialization.cpp =================================================================== --- clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -20,16 +20,20 @@ void recordFixes(const VarDecl &Var, ASTContext &Context, DiagnosticBuilder &Diagnostic) { - Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context); + // Do not propose fixes in macros since we cannot place them correctly. + if (Var.getLocation().isMacroID()) + return; + + Diagnostic << utils::create_fix_it::changeVarDeclToReference(Var, Context); if (!Var.getType().isLocalConstQualified()) - Diagnostic << utils::fixit::changeVarDeclToConst(Var); + Diagnostic << utils::create_fix_it::changeVarDeclToConst(Var); } } // namespace using namespace ::clang::ast_matchers; -using utils::decl_ref_expr::isOnlyUsedAsConst; +using decl_ref_expr_utils::isOnlyUsedAsConst; void UnnecessaryCopyInitialization::registerMatchers(MatchFinder *Finder) { auto ConstReference = referenceType(pointee(qualType(isConstQualified()))); @@ -38,15 +42,14 @@ unless(allOf(pointerType(), unless(pointerType(pointee( qualType(isConstQualified()))))))); - // Match method call expressions where the `this` argument is only used as - // const, this will be checked in `check()` part. This returned const - // reference is highly likely to outlive the local const reference of the - // variable being declared. The assumption is that the const reference being - // returned either points to a global static variable or to a member of the - // called object. - auto ConstRefReturningMethodCall = cxxMemberCallExpr( + // Match method call expressions where the this argument is a const + // type or const reference. This returned const reference is highly likely to + // outlive the local const reference of the variable being declared. + // The assumption is that the const reference being returned either points + // to a global static variable or to a member of the called object. + auto ConstRefReturningMethodCallOfConstParam = cxxMemberCallExpr( callee(cxxMethodDecl(returns(ConstReference))), - on(declRefExpr(to(varDecl().bind("objectArg"))))); + on(declRefExpr(to(varDecl(hasType(qualType(ConstOrConstReference))))))); auto ConstRefReturningFunctionCall = callExpr(callee(functionDecl(returns(ConstReference))), unless(callee(cxxMethodDecl()))); @@ -54,22 +57,20 @@ auto localVarCopiedFrom = [](const internal::Matcher &CopyCtorArg) { return compoundStmt( forEachDescendant( - declStmt( - has(varDecl(hasLocalStorage(), - hasType(matchers::isExpensiveToCopy()), - hasInitializer( - cxxConstructExpr( - hasDeclaration(cxxConstructorDecl( - isCopyConstructor())), - hasArgument(0, CopyCtorArg)) - .bind("ctorCall"))) - .bind("newVarDecl"))).bind("declStmt"))) + varDecl(hasLocalStorage(), + hasType(matchers::isExpensiveToCopy()), + hasInitializer(cxxConstructExpr( + hasDeclaration(cxxConstructorDecl( + isCopyConstructor())), + hasArgument(0, CopyCtorArg)) + .bind("ctorCall"))) + .bind("newVarDecl"))) .bind("blockStmt"); }; Finder->addMatcher( localVarCopiedFrom(anyOf(ConstRefReturningFunctionCall, - ConstRefReturningMethodCall)), + ConstRefReturningMethodCallOfConstParam)), this); Finder->addMatcher(localVarCopiedFrom(declRefExpr( @@ -81,14 +82,8 @@ const MatchFinder::MatchResult &Result) { const auto *NewVar = Result.Nodes.getNodeAs("newVarDecl"); const auto *OldVar = Result.Nodes.getNodeAs("oldVarDecl"); - const auto *ObjectArg = Result.Nodes.getNodeAs("objectArg"); const auto *BlockStmt = Result.Nodes.getNodeAs("blockStmt"); const auto *CtorCall = Result.Nodes.getNodeAs("ctorCall"); - // Do not propose fixes if the DeclStmt has multiple VarDecls or in macros - // since we cannot place them correctly. - bool IssueFix = - Result.Nodes.getNodeAs("declStmt")->isSingleDecl() && - !NewVar->getLocation().isMacroID(); // A constructor that looks like T(const T& t, bool arg = false) counts as a // copy only when it is called with default arguments for the arguments after @@ -98,23 +93,17 @@ return; if (OldVar == nullptr) { - handleCopyFromMethodReturn(*NewVar, *BlockStmt, IssueFix, ObjectArg, - *Result.Context); + handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Result.Context); } else { - handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, IssueFix, - *Result.Context); + handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Result.Context); } } void UnnecessaryCopyInitialization::handleCopyFromMethodReturn( - const VarDecl &Var, const Stmt &BlockStmt, bool IssueFix, - const VarDecl *ObjectArg, ASTContext &Context) { + const VarDecl &Var, const Stmt &BlockStmt, ASTContext &Context) { bool IsConstQualified = Var.getType().isConstQualified(); if (!IsConstQualified && !isOnlyUsedAsConst(Var, BlockStmt, Context)) return; - if (ObjectArg != nullptr && - !isOnlyUsedAsConst(*ObjectArg, BlockStmt, Context)) - return; auto Diagnostic = diag(Var.getLocation(), @@ -125,13 +114,12 @@ "const reference but is only used as const " "reference; consider making it a const reference") << &Var; - if (IssueFix) - recordFixes(Var, Context, Diagnostic); + recordFixes(Var, Context, Diagnostic); } void UnnecessaryCopyInitialization::handleCopyFromLocalVar( const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt, - bool IssueFix, ASTContext &Context) { + ASTContext &Context) { if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) || !isOnlyUsedAsConst(OldVar, BlockStmt, Context)) return; @@ -140,8 +128,7 @@ "local copy %0 of the variable %1 is never modified; " "consider avoiding the copy") << &NewVar << &OldVar; - if (IssueFix) - recordFixes(NewVar, Context, Diagnostic); + recordFixes(NewVar, Context, Diagnostic); } } // namespace performance Index: clang-tidy/performance/UnnecessaryValueParamCheck.h =================================================================== --- clang-tidy/performance/UnnecessaryValueParamCheck.h +++ clang-tidy/performance/UnnecessaryValueParamCheck.h @@ -11,7 +11,6 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_UNNECESSARY_VALUE_PARAM_H #include "../ClangTidy.h" -#include "../utils/IncludeInserter.h" namespace clang { namespace tidy { @@ -24,18 +23,10 @@ /// http://clang.llvm.org/extra/clang-tidy/checks/performance-unnecessary-value-param.html class UnnecessaryValueParamCheck : public ClangTidyCheck { public: - UnnecessaryValueParamCheck(StringRef Name, ClangTidyContext *Context); + UnnecessaryValueParamCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; - void registerPPCallbacks(CompilerInstance &Compiler) override; - void storeOptions(ClangTidyOptions::OptionMap &Opts) override; - -private: - void handleMoveFix(const ParmVarDecl &Var, const DeclRefExpr &CopyArgument, - const ASTContext &Context); - - std::unique_ptr Inserter; - const utils::IncludeSorter::IncludeStyle IncludeStyle; }; } // namespace performance Index: clang-tidy/performance/UnnecessaryValueParamCheck.cpp =================================================================== --- clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -12,10 +12,6 @@ #include "../utils/DeclRefExprUtils.h" #include "../utils/FixItHintUtils.h" #include "../utils/Matchers.h" -#include "../utils/TypeTraits.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Lex/Lexer.h" -#include "clang/Lex/Preprocessor.h" using namespace clang::ast_matchers; @@ -31,22 +27,8 @@ .str(); } -template -bool isSubset(const S &SubsetCandidate, const S &SupersetCandidate) { - for (const auto &E : SubsetCandidate) - if (SupersetCandidate.count(E) == 0) - return false; - return true; -} - } // namespace -UnnecessaryValueParamCheck::UnnecessaryValueParamCheck( - StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context), - IncludeStyle(utils::IncludeSorter::parseIncludeStyle( - Options.get("IncludeStyle", "llvm"))) {} - void UnnecessaryValueParamCheck::registerMatchers(MatchFinder *Finder) { const auto ExpensiveValueParamDecl = parmVarDecl(hasType(hasCanonicalType(allOf(matchers::isExpensiveToCopy(), @@ -76,39 +58,12 @@ // Do not trigger on non-const value parameters when: // 1. they are in a constructor definition since they can likely trigger // misc-move-constructor-init which will suggest to move the argument. - if (!IsConstQualified && (llvm::isa(Function) || - !Function->doesThisDeclarationHaveABody())) - return; - - auto AllDeclRefExprs = utils::decl_ref_expr::allDeclRefExprs( - *Param, *Function->getBody(), *Result.Context); - auto ConstDeclRefExprs = utils::decl_ref_expr::constReferenceDeclRefExprs( - *Param, *Function->getBody(), *Result.Context); // 2. they are not only used as const. - if (!isSubset(AllDeclRefExprs, ConstDeclRefExprs)) + if (!IsConstQualified && (llvm::isa(Function) || + !Function->doesThisDeclarationHaveABody() || + !decl_ref_expr_utils::isOnlyUsedAsConst( + *Param, *Function->getBody(), *Result.Context))) return; - - // If the parameter is non-const, check if it has a move constructor and is - // only referenced once to copy-construct another object or whether it has a - // move assignment operator and is only referenced once when copy-assigned. - // In this case wrap DeclRefExpr with std::move() to avoid the unnecessary - // copy. - if (!IsConstQualified) { - auto CanonicalType = Param->getType().getCanonicalType(); - if (AllDeclRefExprs.size() == 1 && - ((utils::type_traits::hasNonTrivialMoveConstructor(CanonicalType) && - utils::decl_ref_expr::isCopyConstructorArgument( - **AllDeclRefExprs.begin(), *Function->getBody(), - *Result.Context)) || - (utils::type_traits::hasNonTrivialMoveAssignment(CanonicalType) && - utils::decl_ref_expr::isCopyAssignmentArgument( - **AllDeclRefExprs.begin(), *Function->getBody(), - *Result.Context)))) { - handleMoveFix(*Param, **AllDeclRefExprs.begin(), *Result.Context); - return; - } - } - auto Diag = diag(Param->getLocation(), IsConstQualified ? "the const qualified parameter %0 is " @@ -118,55 +73,19 @@ "invocation but only used as a const reference; " "consider making it a const reference") << paramNameOrIndex(Param->getName(), Index); - // Do not propose fixes in macros since we cannot place them correctly, or if - // function is virtual as it might break overrides. - const auto *Method = llvm::dyn_cast(Function); - if (Param->getLocStart().isMacroID() || (Method && Method->isVirtual())) + // Do not propose fixes in macros since we cannot place them correctly. + if (Param->getLocStart().isMacroID()) return; for (const auto *FunctionDecl = Function; FunctionDecl != nullptr; FunctionDecl = FunctionDecl->getPreviousDecl()) { const auto &CurrentParam = *FunctionDecl->getParamDecl(Index); - Diag << utils::fixit::changeVarDeclToReference(CurrentParam, + Diag << utils::create_fix_it::changeVarDeclToReference(CurrentParam, *Result.Context); if (!IsConstQualified) - Diag << utils::fixit::changeVarDeclToConst(CurrentParam); + Diag << utils::create_fix_it::changeVarDeclToConst(CurrentParam); } } -void UnnecessaryValueParamCheck::registerPPCallbacks( - CompilerInstance &Compiler) { - Inserter.reset(new utils::IncludeInserter( - Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle)); - Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks()); -} - -void UnnecessaryValueParamCheck::storeOptions( - ClangTidyOptions::OptionMap &Opts) { - Options.store(Opts, "IncludeStyle", - utils::IncludeSorter::toString(IncludeStyle)); -} - -void UnnecessaryValueParamCheck::handleMoveFix(const ParmVarDecl &Var, - const DeclRefExpr &CopyArgument, - const ASTContext &Context) { - auto Diag = diag(CopyArgument.getLocStart(), - "parameter %0 is passed by value and only copied once; " - "consider moving it to avoid unnecessary copies") - << &Var; - // Do not propose fixes in macros since we cannot place them correctly. - if (CopyArgument.getLocStart().isMacroID()) - return; - const auto &SM = Context.getSourceManager(); - auto EndLoc = Lexer::getLocForEndOfToken(CopyArgument.getLocation(), 0, SM, - Context.getLangOpts()); - Diag << FixItHint::CreateInsertion(CopyArgument.getLocStart(), "std::move(") - << FixItHint::CreateInsertion(EndLoc, ")"); - if (auto IncludeFixit = Inserter->CreateIncludeInsertion( - SM.getFileID(CopyArgument.getLocStart()), "utility", - /*IsAngled=*/true)) - Diag << *IncludeFixit; -} - } // namespace performance } // namespace tidy } // namespace clang Index: clang-tidy/plugin/CMakeLists.txt =================================================================== --- clang-tidy/plugin/CMakeLists.txt +++ clang-tidy/plugin/CMakeLists.txt @@ -8,7 +8,6 @@ clangFrontend clangSema clangTidy - clangTidyBoostModule clangTidyCERTModule clangTidyCppCoreGuidelinesModule clangTidyGoogleModule Index: clang-tidy/readability/AvoidConstParamsInDecls.cpp =================================================================== --- clang-tidy/readability/AvoidConstParamsInDecls.cpp +++ clang-tidy/readability/AvoidConstParamsInDecls.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "AvoidConstParamsInDecls.h" -#include "llvm/ADT/Optional.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Lex/Lexer.h" @@ -32,19 +31,15 @@ void AvoidConstParamsInDecls::registerMatchers(MatchFinder *Finder) { const auto ConstParamDecl = parmVarDecl(hasType(qualType(isConstQualified()))).bind("param"); - Finder->addMatcher( - functionDecl(unless(isDefinition()), - // Lambdas are always their own definition, but they - // generate a non-definition FunctionDecl too. Ignore those. - unless(cxxMethodDecl(ofClass(cxxRecordDecl(isLambda())))), - has(typeLoc(forEach(ConstParamDecl)))) - .bind("func"), - this); + Finder->addMatcher(functionDecl(unless(isDefinition()), + has(typeLoc(forEach(ConstParamDecl)))) + .bind("func"), + this); } // Re-lex the tokens to get precise location of last 'const' -static llvm::Optional ConstTok(CharSourceRange Range, - const MatchFinder::MatchResult &Result) { +static Token ConstTok(CharSourceRange Range, + const MatchFinder::MatchResult &Result) { const SourceManager &Sources = *Result.SourceManager; std::pair LocInfo = Sources.getDecomposedLoc(Range.getBegin()); @@ -54,7 +49,7 @@ Result.Context->getLangOpts(), File.begin(), TokenBegin, File.end()); Token Tok; - llvm::Optional ConstTok; + Token ConstTok; while (!RawLexer.LexFromRawLexer(Tok)) { if (Sources.isBeforeInTranslationUnit(Range.getEnd(), Tok.getLocation())) break; @@ -92,12 +87,6 @@ Diag << Param; } - if (Param->getLocStart().isMacroID() != Param->getLocEnd().isMacroID()) { - // Do not offer a suggestion if the part of the variable declaration comes - // from a macro. - return; - } - CharSourceRange FileRange = Lexer::makeFileCharRange( CharSourceRange::getTokenRange(getTypeRange(*Param)), *Result.SourceManager, Result.Context->getLangOpts()); @@ -105,11 +94,9 @@ if (!FileRange.isValid()) return; - auto Tok = ConstTok(FileRange, Result); - if (!Tok) - return; + Token Tok = ConstTok(FileRange, Result); Diag << FixItHint::CreateRemoval( - CharSourceRange::getTokenRange(Tok->getLocation(), Tok->getLocation())); + CharSourceRange::getTokenRange(Tok.getLocation(), Tok.getLocation())); } } // namespace readability Index: clang-tidy/readability/ElseAfterReturnCheck.cpp =================================================================== --- clang-tidy/readability/ElseAfterReturnCheck.cpp +++ clang-tidy/readability/ElseAfterReturnCheck.cpp @@ -10,7 +10,6 @@ #include "ElseAfterReturnCheck.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Tooling/FixIt.h" using namespace clang::ast_matchers; @@ -29,17 +28,20 @@ this); } +static FixItHint removeToken(SourceLocation Loc) { + return FixItHint::CreateRemoval(CharSourceRange::getTokenRange(Loc, Loc)); +} + void ElseAfterReturnCheck::check(const MatchFinder::MatchResult &Result) { const auto *If = Result.Nodes.getNodeAs("if"); SourceLocation ElseLoc = If->getElseLoc(); DiagnosticBuilder Diag = diag(ElseLoc, "don't use else after return"); - Diag << tooling::fixit::createRemoval(ElseLoc); + Diag << removeToken(ElseLoc); // FIXME: Removing the braces isn't always safe. Do a more careful analysis. // FIXME: Change clang-format to correctly un-indent the code. if (const auto *CS = Result.Nodes.getNodeAs("else")) - Diag << tooling::fixit::createRemoval(CS->getLBracLoc()) - << tooling::fixit::createRemoval(CS->getRBracLoc()); + Diag << removeToken(CS->getLBracLoc()) << removeToken(CS->getRBracLoc()); } } // namespace readability Index: clang-tidy/readability/FunctionSizeCheck.h =================================================================== --- clang-tidy/readability/FunctionSizeCheck.h +++ clang-tidy/readability/FunctionSizeCheck.h @@ -34,11 +34,21 @@ void storeOptions(ClangTidyOptions::OptionMap &Opts) override; void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void onEndOfTranslationUnit() override; private: + struct FunctionInfo { + FunctionInfo() : Lines(0), Statements(0), Branches(0) {} + unsigned Lines; + unsigned Statements; + unsigned Branches; + }; + const unsigned LineThreshold; const unsigned StatementThreshold; const unsigned BranchThreshold; + + llvm::DenseMap FunctionInfos; }; } // namespace readability Index: clang-tidy/readability/FunctionSizeCheck.cpp =================================================================== --- clang-tidy/readability/FunctionSizeCheck.cpp +++ clang-tidy/readability/FunctionSizeCheck.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "FunctionSizeCheck.h" -#include "clang/AST/RecursiveASTVisitor.h" #include "clang/ASTMatchers/ASTMatchFinder.h" using namespace clang::ast_matchers; @@ -17,57 +16,6 @@ namespace tidy { namespace readability { -class FunctionASTVisitor : public RecursiveASTVisitor { - using Base = RecursiveASTVisitor; - -public: - bool TraverseStmt(Stmt *Node) { - if (!Node) - return Base::TraverseStmt(Node); - - if (TrackedParent.back() && !isa(Node)) - ++Info.Statements; - - switch (Node->getStmtClass()) { - case Stmt::IfStmtClass: - case Stmt::WhileStmtClass: - case Stmt::DoStmtClass: - case Stmt::CXXForRangeStmtClass: - case Stmt::ForStmtClass: - case Stmt::SwitchStmtClass: - ++Info.Branches; - // fallthrough - case Stmt::CompoundStmtClass: - TrackedParent.push_back(true); - break; - default: - TrackedParent.push_back(false); - break; - } - - Base::TraverseStmt(Node); - - TrackedParent.pop_back(); - return true; - } - - bool TraverseDecl(Decl *Node) { - TrackedParent.push_back(false); - Base::TraverseDecl(Node); - TrackedParent.pop_back(); - return true; - } - - struct FunctionInfo { - FunctionInfo() : Lines(0), Statements(0), Branches(0) {} - unsigned Lines; - unsigned Statements; - unsigned Branches; - }; - FunctionInfo Info; - std::vector TrackedParent; -}; - FunctionSizeCheck::FunctionSizeCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), LineThreshold(Options.get("LineThreshold", -1U)), @@ -81,52 +29,76 @@ } void FunctionSizeCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher(functionDecl(unless(isInstantiated())).bind("func"), this); + Finder->addMatcher( + functionDecl( + unless(isInstantiated()), + forEachDescendant( + stmt(unless(compoundStmt()), + hasParent(stmt(anyOf(compoundStmt(), ifStmt(), + anyOf(whileStmt(), doStmt(), + cxxForRangeStmt(), forStmt()))))) + .bind("stmt"))).bind("func"), + this); } void FunctionSizeCheck::check(const MatchFinder::MatchResult &Result) { const auto *Func = Result.Nodes.getNodeAs("func"); - FunctionASTVisitor Visitor; - Visitor.TraverseDecl(const_cast(Func)); - auto &FI = Visitor.Info; - - if (FI.Statements == 0) - return; + FunctionInfo &FI = FunctionInfos[Func]; // Count the lines including whitespace and comments. Really simple. - if (const Stmt *Body = Func->getBody()) { - SourceManager *SM = Result.SourceManager; - if (SM->isWrittenInSameFile(Body->getLocStart(), Body->getLocEnd())) { - FI.Lines = SM->getSpellingLineNumber(Body->getLocEnd()) - - SM->getSpellingLineNumber(Body->getLocStart()); + if (!FI.Lines) { + if (const Stmt *Body = Func->getBody()) { + SourceManager *SM = Result.SourceManager; + if (SM->isWrittenInSameFile(Body->getLocStart(), Body->getLocEnd())) { + FI.Lines = SM->getSpellingLineNumber(Body->getLocEnd()) - + SM->getSpellingLineNumber(Body->getLocStart()); + } } } - if (FI.Lines > LineThreshold || FI.Statements > StatementThreshold || - FI.Branches > BranchThreshold) { - diag(Func->getLocation(), - "function %0 exceeds recommended size/complexity thresholds") - << Func; - } + const auto *Statement = Result.Nodes.getNodeAs("stmt"); + ++FI.Statements; - if (FI.Lines > LineThreshold) { - diag(Func->getLocation(), - "%0 lines including whitespace and comments (threshold %1)", - DiagnosticIDs::Note) - << FI.Lines << LineThreshold; - } + // TODO: switch cases, gotos + if (isa(Statement) || isa(Statement) || + isa(Statement) || isa(Statement) || + isa(Statement) || isa(Statement)) + ++FI.Branches; +} - if (FI.Statements > StatementThreshold) { - diag(Func->getLocation(), "%0 statements (threshold %1)", - DiagnosticIDs::Note) - << FI.Statements << StatementThreshold; - } +void FunctionSizeCheck::onEndOfTranslationUnit() { + // If we're above the limit emit a warning. + for (const auto &P : FunctionInfos) { + const FunctionInfo &FI = P.second; + if (FI.Lines > LineThreshold || FI.Statements > StatementThreshold || + FI.Branches > BranchThreshold) { + diag(P.first->getLocation(), + "function %0 exceeds recommended size/complexity thresholds") + << P.first; + } + + if (FI.Lines > LineThreshold) { + diag(P.first->getLocation(), + "%0 lines including whitespace and comments (threshold %1)", + DiagnosticIDs::Note) + << FI.Lines << LineThreshold; + } + + if (FI.Statements > StatementThreshold) { + diag(P.first->getLocation(), "%0 statements (threshold %1)", + DiagnosticIDs::Note) + << FI.Statements << StatementThreshold; + } - if (FI.Branches > BranchThreshold) { - diag(Func->getLocation(), "%0 branches (threshold %1)", DiagnosticIDs::Note) - << FI.Branches << BranchThreshold; + if (FI.Branches > BranchThreshold) { + diag(P.first->getLocation(), "%0 branches (threshold %1)", + DiagnosticIDs::Note) + << FI.Branches << BranchThreshold; + } } + + FunctionInfos.clear(); } } // namespace readability Index: clang-tidy/readability/IdentifierNamingCheck.h =================================================================== --- clang-tidy/readability/IdentifierNamingCheck.h +++ clang-tidy/readability/IdentifierNamingCheck.h @@ -13,9 +13,6 @@ #include "../ClangTidy.h" namespace clang { - -class MacroInfo; - namespace tidy { namespace readability { @@ -39,7 +36,6 @@ void storeOptions(ClangTidyOptions::OptionMap &Opts) override; void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; - void registerPPCallbacks(CompilerInstance &Compiler) override; void onEndOfTranslationUnit() override; enum CaseType { @@ -68,7 +64,7 @@ /// \brief Holds an identifier name check failure, tracking the kind of the /// identifer, its possible fixup and the starting locations of all the - /// identifier usages. + /// idenfiier usages. struct NamingCheckFailure { std::string KindName; std::string Fixup; @@ -85,19 +81,9 @@ NamingCheckFailure() : ShouldFix(true) {} }; - - typedef std::pair NamingCheckId; - - typedef llvm::DenseMap + typedef llvm::DenseMap NamingCheckFailureMap; - /// Check Macros for style violations. - void checkMacro(SourceManager &sourceMgr, const Token &MacroNameTok, - const MacroInfo *MI); - - /// Add a usage of a macro if it already has a violation. - void expandMacro(const Token &MacroNameTok, const MacroInfo *MI); - private: std::vector NamingStyles; bool IgnoreFailedSplit; Index: clang-tidy/readability/IdentifierNamingCheck.cpp =================================================================== --- clang-tidy/readability/IdentifierNamingCheck.cpp +++ clang-tidy/readability/IdentifierNamingCheck.cpp @@ -12,53 +12,11 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" #include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Lex/PPCallbacks.h" -#include "clang/Lex/Preprocessor.h" -#include "llvm/ADT/DenseMapInfo.h" #define DEBUG_TYPE "clang-tidy" using namespace clang::ast_matchers; -namespace llvm { -/// Specialisation of DenseMapInfo to allow NamingCheckId objects in DenseMaps -template <> -struct DenseMapInfo< - clang::tidy::readability::IdentifierNamingCheck::NamingCheckId> { - using NamingCheckId = - clang::tidy::readability::IdentifierNamingCheck::NamingCheckId; - - static inline NamingCheckId getEmptyKey() { - return NamingCheckId( - clang::SourceLocation::getFromRawEncoding(static_cast(-1)), - "EMPTY"); - } - - static inline NamingCheckId getTombstoneKey() { - return NamingCheckId( - clang::SourceLocation::getFromRawEncoding(static_cast(-2)), - "TOMBSTONE"); - } - - static unsigned getHashValue(NamingCheckId Val) { - assert(Val != getEmptyKey() && "Cannot hash the empty key!"); - assert(Val != getTombstoneKey() && "Cannot hash the tombstone key!"); - - std::hash SecondHash; - return Val.first.getRawEncoding() + SecondHash(Val.second); - } - - static bool isEqual(NamingCheckId LHS, NamingCheckId RHS) { - if (RHS == getEmptyKey()) - return LHS == getEmptyKey(); - if (RHS == getTombstoneKey()) - return LHS == getTombstoneKey(); - return LHS == RHS; - } -}; -} // namespace llvm - namespace clang { namespace tidy { namespace readability { @@ -107,8 +65,6 @@ m(ValueTemplateParameter) \ m(TemplateTemplateParameter) \ m(TemplateParameter) \ - m(TypeAlias) \ - m(MacroDefinition) \ enum StyleKind { #define ENUMERATE(v) SK_ ## v, @@ -127,33 +83,6 @@ #undef NAMING_KEYS // clang-format on -namespace { -/// Callback supplies macros to IdentifierNamingCheck::checkMacro -class IdentifierNamingCheckPPCallbacks : public PPCallbacks { -public: - IdentifierNamingCheckPPCallbacks(Preprocessor *PP, - IdentifierNamingCheck *Check) - : PP(PP), Check(Check) {} - - /// MacroDefined calls checkMacro for macros in the main file - void MacroDefined(const Token &MacroNameTok, - const MacroDirective *MD) override { - Check->checkMacro(PP->getSourceManager(), MacroNameTok, MD->getMacroInfo()); - } - - /// MacroExpands calls expandMacro for macros in the main file - void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, - SourceRange /*Range*/, - const MacroArgs * /*Args*/) override { - Check->expandMacro(MacroNameTok, MD.getMacroInfo()); - } - -private: - Preprocessor *PP; - IdentifierNamingCheck *Check; -}; -} // namespace - IdentifierNamingCheck::IdentifierNamingCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context) { @@ -216,12 +145,6 @@ Finder->addMatcher(nestedNameSpecifierLoc().bind("nestedNameLoc"), this); } -void IdentifierNamingCheck::registerPPCallbacks(CompilerInstance &Compiler) { - Compiler.getPreprocessor().addPPCallbacks( - llvm::make_unique( - &Compiler.getPreprocessor(), this)); -} - static bool matchesStyle(StringRef Name, IdentifierNamingCheck::NamingStyle Style) { static llvm::Regex Matchers[] = { @@ -335,9 +258,6 @@ if (isa(D) && NamingStyles[SK_Typedef].isSet()) return SK_Typedef; - if (isa(D) && NamingStyles[SK_TypeAlias].isSet()) - return SK_TypeAlias; - if (const auto *Decl = dyn_cast(D)) { if (Decl->isAnonymousNamespace()) return SK_Invalid; @@ -582,8 +502,8 @@ } static void addUsage(IdentifierNamingCheck::NamingCheckFailureMap &Failures, - const IdentifierNamingCheck::NamingCheckId &Decl, - SourceRange Range) { + const NamedDecl *Decl, SourceRange Range, + const SourceManager *SM) { // Do nothing if the provided range is invalid. if (Range.getBegin().isInvalid() || Range.getEnd().isInvalid()) return; @@ -598,14 +518,6 @@ !Range.getEnd().isMacroID(); } -/// Convenience method when the usage to be added is a NamedDecl -static void addUsage(IdentifierNamingCheck::NamingCheckFailureMap &Failures, - const NamedDecl *Decl, SourceRange Range) { - return addUsage(Failures, IdentifierNamingCheck::NamingCheckId( - Decl->getLocation(), Decl->getNameAsString()), - Range); -} - void IdentifierNamingCheck::check(const MatchFinder::MatchResult &Result) { if (const auto *Decl = Result.Nodes.getNodeAs("classRef")) { @@ -613,7 +525,7 @@ return; addUsage(NamingCheckFailures, Decl->getParent(), - Decl->getNameInfo().getSourceRange()); + Decl->getNameInfo().getSourceRange(), Result.SourceManager); return; } @@ -629,7 +541,8 @@ // we want instead to replace the next token, that will be the identifier. Range.setBegin(CharSourceRange::getTokenRange(Range).getEnd()); - addUsage(NamingCheckFailures, Decl->getParent(), Range); + addUsage(NamingCheckFailures, Decl->getParent(), Range, + Result.SourceManager); return; } @@ -646,7 +559,8 @@ } if (Decl) { - addUsage(NamingCheckFailures, Decl, Loc->getSourceRange()); + addUsage(NamingCheckFailures, Decl, Loc->getSourceRange(), + Result.SourceManager); return; } @@ -656,16 +570,16 @@ SourceRange Range(Ref.getTemplateNameLoc(), Ref.getTemplateNameLoc()); if (const auto *ClassDecl = dyn_cast(Decl)) { - if (const auto *TemplDecl = ClassDecl->getTemplatedDecl()) - addUsage(NamingCheckFailures, TemplDecl, Range); + addUsage(NamingCheckFailures, ClassDecl->getTemplatedDecl(), Range, + Result.SourceManager); return; } } if (const auto &Ref = Loc->getAs()) { - if (const auto *Decl = Ref.getTypePtr()->getAsTagDecl()) - addUsage(NamingCheckFailures, Decl, Loc->getSourceRange()); + addUsage(NamingCheckFailures, Ref.getTypePtr()->getAsTagDecl(), + Loc->getSourceRange(), Result.SourceManager); return; } } @@ -674,7 +588,8 @@ Result.Nodes.getNodeAs("nestedNameLoc")) { if (NestedNameSpecifier *Spec = Loc->getNestedNameSpecifier()) { if (NamespaceDecl *Decl = Spec->getAsNamespace()) { - addUsage(NamingCheckFailures, Decl, Loc->getLocalSourceRange()); + addUsage(NamingCheckFailures, Decl, Loc->getLocalSourceRange(), + Result.SourceManager); return; } } @@ -683,14 +598,15 @@ if (const auto *Decl = Result.Nodes.getNodeAs("using")) { for (const auto &Shadow : Decl->shadows()) { addUsage(NamingCheckFailures, Shadow->getTargetDecl(), - Decl->getNameInfo().getSourceRange()); + Decl->getNameInfo().getSourceRange(), Result.SourceManager); } return; } if (const auto *DeclRef = Result.Nodes.getNodeAs("declRef")) { SourceRange Range = DeclRef->getNameInfo().getSourceRange(); - addUsage(NamingCheckFailures, DeclRef->getDecl(), Range); + addUsage(NamingCheckFailures, DeclRef->getDecl(), Range, + Result.SourceManager); return; } @@ -698,33 +614,6 @@ if (!Decl->getIdentifier() || Decl->getName().empty() || Decl->isImplicit()) return; - // Fix type aliases in value declarations - if (const auto *Value = Result.Nodes.getNodeAs("decl")) { - if (const auto *Typedef = - Value->getType().getTypePtr()->getAs()) { - addUsage(NamingCheckFailures, Typedef->getDecl(), - Value->getSourceRange()); - } - } - - // Fix type aliases in function declarations - if (const auto *Value = Result.Nodes.getNodeAs("decl")) { - if (const auto *Typedef = - Value->getReturnType().getTypePtr()->getAs()) { - addUsage(NamingCheckFailures, Typedef->getDecl(), - Value->getSourceRange()); - } - for (unsigned i = 0; i < Value->getNumParams(); ++i) { - if (const auto *Typedef = Value->parameters()[i] - ->getType() - .getTypePtr() - ->getAs()) { - addUsage(NamingCheckFailures, Typedef->getDecl(), - Value->getSourceRange()); - } - } - } - // Ignore ClassTemplateSpecializationDecl which are creating duplicate // replacements with CXXRecordDecl if (isa(Decl)) @@ -751,74 +640,29 @@ KindName.c_str(), Name)); } } else { - NamingCheckFailure &Failure = NamingCheckFailures[NamingCheckId( - Decl->getLocation(), Decl->getNameAsString())]; + NamingCheckFailure &Failure = NamingCheckFailures[Decl]; SourceRange Range = DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation()) .getSourceRange(); Failure.Fixup = std::move(Fixup); Failure.KindName = std::move(KindName); - addUsage(NamingCheckFailures, Decl, Range); - } - } -} - -void IdentifierNamingCheck::checkMacro(SourceManager &SourceMgr, - const Token &MacroNameTok, - const MacroInfo *MI) { - StringRef Name = MacroNameTok.getIdentifierInfo()->getName(); - NamingStyle Style = NamingStyles[SK_MacroDefinition]; - if (matchesStyle(Name, Style)) - return; - - std::string KindName = - fixupWithCase(StyleNames[SK_MacroDefinition], CT_LowerCase); - std::replace(KindName.begin(), KindName.end(), '_', ' '); - - std::string Fixup = fixupWithStyle(Name, Style); - if (StringRef(Fixup).equals(Name)) { - if (!IgnoreFailedSplit) { - DEBUG( - llvm::dbgs() << MacroNameTok.getLocation().printToString(SourceMgr) - << llvm::format(": unable to split words for %s '%s'\n", - KindName.c_str(), Name)); + addUsage(NamingCheckFailures, Decl, Range, Result.SourceManager); } - } else { - NamingCheckId ID(MI->getDefinitionLoc(), Name); - NamingCheckFailure &Failure = NamingCheckFailures[ID]; - SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc()); - - Failure.Fixup = std::move(Fixup); - Failure.KindName = std::move(KindName); - addUsage(NamingCheckFailures, ID, Range); } } -void IdentifierNamingCheck::expandMacro(const Token &MacroNameTok, - const MacroInfo *MI) { - StringRef Name = MacroNameTok.getIdentifierInfo()->getName(); - NamingCheckId ID(MI->getDefinitionLoc(), Name); - - auto Failure = NamingCheckFailures.find(ID); - if (Failure == NamingCheckFailures.end()) - return; - - SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc()); - addUsage(NamingCheckFailures, ID, Range); -} - void IdentifierNamingCheck::onEndOfTranslationUnit() { for (const auto &Pair : NamingCheckFailures) { - const NamingCheckId &Decl = Pair.first; + const NamedDecl &Decl = *Pair.first; const NamingCheckFailure &Failure = Pair.second; if (Failure.KindName.empty()) continue; if (Failure.ShouldFix) { - auto Diag = diag(Decl.first, "invalid case style for %0 '%1'") - << Failure.KindName << Decl.second; + auto Diag = diag(Decl.getLocation(), "invalid case style for %0 '%1'") + << Failure.KindName << Decl.getName(); for (const auto &Loc : Failure.RawUsageLocs) { // We assume that the identifier name is made of one token only. This is Index: clang-tidy/readability/ImplicitBoolCastCheck.h =================================================================== --- clang-tidy/readability/ImplicitBoolCastCheck.h +++ clang-tidy/readability/ImplicitBoolCastCheck.h @@ -14,7 +14,6 @@ namespace clang { namespace tidy { -namespace readability { /// \brief Checks for use of implicit bool casts in expressions. /// @@ -42,7 +41,6 @@ bool AllowConditionalPointerCasts; }; -} // namespace readability } // namespace tidy } // namespace clang Index: clang-tidy/readability/ImplicitBoolCastCheck.cpp =================================================================== --- clang-tidy/readability/ImplicitBoolCastCheck.cpp +++ clang-tidy/readability/ImplicitBoolCastCheck.cpp @@ -16,10 +16,13 @@ namespace clang { namespace tidy { -namespace readability { namespace { +AST_MATCHER_P(CastExpr, hasCastKind, CastKind, Kind) { + return Node.getCastKind() == Kind; +} + AST_MATCHER(Stmt, isMacroExpansion) { SourceManager &SM = Finder->getASTContext().getSourceManager(); SourceLocation Loc = Node.getLocStart(); @@ -412,6 +415,5 @@ } } -} // namespace readability } // namespace tidy } // namespace clang Index: clang-tidy/readability/InconsistentDeclarationParameterNameCheck.cpp =================================================================== --- clang-tidy/readability/InconsistentDeclarationParameterNameCheck.cpp +++ clang-tidy/readability/InconsistentDeclarationParameterNameCheck.cpp @@ -15,12 +15,12 @@ #include #include -using namespace clang::ast_matchers; - namespace clang { namespace tidy { namespace readability { +using namespace ast_matchers; + namespace { AST_MATCHER(FunctionDecl, hasOtherDeclarations) { @@ -186,7 +186,7 @@ std::string joinParameterNames( const DifferingParamsContainer &DifferingParams, - llvm::function_ref ChooseParamName) { + std::function ChooseParamName) { llvm::SmallVector Buffer; llvm::raw_svector_ostream Str(Buffer); bool First = true; Index: clang-tidy/readability/RedundantSmartptrGetCheck.cpp =================================================================== --- clang-tidy/readability/RedundantSmartptrGetCheck.cpp +++ clang-tidy/readability/RedundantSmartptrGetCheck.cpp @@ -18,7 +18,7 @@ namespace readability { namespace { -internal::Matcher callToGet(const internal::Matcher &OnClass) { +internal::Matcher callToGet(internal::Matcher OnClass) { return cxxMemberCallExpr( on(expr(anyOf(hasType(OnClass), hasType(qualType( Index: clang-tidy/readability/RedundantStringCStrCheck.cpp =================================================================== --- clang-tidy/readability/RedundantStringCStrCheck.cpp +++ clang-tidy/readability/RedundantStringCStrCheck.cpp @@ -14,11 +14,9 @@ #include "RedundantStringCStrCheck.h" #include "clang/Lex/Lexer.h" -using namespace clang::ast_matchers; - namespace clang { -namespace tidy { -namespace readability { + +using namespace ast_matchers; namespace { @@ -69,6 +67,9 @@ } // end namespace +namespace tidy { +namespace readability { + void RedundantStringCStrCheck::registerMatchers( ast_matchers::MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not Index: clang-tidy/readability/RedundantStringInitCheck.cpp =================================================================== --- clang-tidy/readability/RedundantStringInitCheck.cpp +++ clang-tidy/readability/RedundantStringInitCheck.cpp @@ -8,16 +8,25 @@ //===----------------------------------------------------------------------===// #include "RedundantStringInitCheck.h" -#include "../utils/Matchers.h" #include "clang/ASTMatchers/ASTMatchers.h" using namespace clang::ast_matchers; -using namespace clang::tidy::matchers; namespace clang { namespace tidy { namespace readability { +namespace { + +AST_MATCHER(StringLiteral, lengthIsZero) { return Node.getLength() == 0; } + +AST_MATCHER_P(Expr, ignoringImplicit, + ast_matchers::internal::Matcher, InnerMatcher) { + return InnerMatcher.matches(*Node.IgnoreImplicit(), Finder, Builder); +} + +} // namespace + void RedundantStringInitCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; @@ -36,24 +45,24 @@ const auto EmptyStringCtorExpr = cxxConstructExpr(StringConstructorExpr, hasArgument(0, ignoringParenImpCasts( - stringLiteral(hasSize(0))))); + stringLiteral(lengthIsZero())))); const auto EmptyStringCtorExprWithTemporaries = - cxxConstructExpr(StringConstructorExpr, - hasArgument(0, ignoringImplicit(EmptyStringCtorExpr))); + expr(ignoringImplicit( + cxxConstructExpr(StringConstructorExpr, + hasArgument(0, ignoringImplicit(EmptyStringCtorExpr))))); // Match a variable declaration with an empty string literal as initializer. // Examples: // string foo = ""; // string bar(""); Finder->addMatcher( - namedDecl( - varDecl(hasType(cxxRecordDecl(hasName("basic_string"))), - hasInitializer(expr(ignoringImplicit(anyOf( - EmptyStringCtorExpr, - EmptyStringCtorExprWithTemporaries))) - .bind("expr"))), - unless(parmVarDecl())) + namedDecl(varDecl(hasType(cxxRecordDecl(hasName("basic_string"))), + hasInitializer( + expr(anyOf(EmptyStringCtorExpr, + EmptyStringCtorExprWithTemporaries)) + .bind("expr"))), + unless(parmVarDecl())) .bind("decl"), this); } Index: clang-tidy/readability/SimplifyBooleanExprCheck.cpp =================================================================== --- clang-tidy/readability/SimplifyBooleanExprCheck.cpp +++ clang-tidy/readability/SimplifyBooleanExprCheck.cpp @@ -461,8 +461,7 @@ compoundStmt(allOf(hasAnySubstatement(ifStmt(hasThen(returnsBool(Value)), unless(hasElse(stmt())))), hasAnySubstatement( - returnStmt(has(ignoringParenImpCasts( - cxxBoolLiteral(equals(!Value))))) + returnStmt(has(cxxBoolLiteral(equals(!Value)))) .bind(CompoundReturnId)))) .bind(Id), this); Index: clang-tidy/readability/UniqueptrDeleteReleaseCheck.h =================================================================== --- clang-tidy/readability/UniqueptrDeleteReleaseCheck.h +++ clang-tidy/readability/UniqueptrDeleteReleaseCheck.h @@ -14,10 +14,9 @@ namespace clang { namespace tidy { -namespace readability { -/// Flags statements of the form ``delete .release();`` and -/// replaces them with: `` = nullptr;`` +/// Flag statements of the form: delete .release() +/// and replace them with: = nullptr /// /// For the user-facing documentation see: /// http://clang.llvm.org/extra/clang-tidy/checks/readability-uniqueptr-delete-release.html @@ -29,7 +28,6 @@ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; }; -} // namespace readability } // namespace tidy } // namespace clang Index: clang-tidy/readability/UniqueptrDeleteReleaseCheck.cpp =================================================================== --- clang-tidy/readability/UniqueptrDeleteReleaseCheck.cpp +++ clang-tidy/readability/UniqueptrDeleteReleaseCheck.cpp @@ -16,7 +16,6 @@ namespace clang { namespace tidy { -namespace readability { void UniqueptrDeleteReleaseCheck::registerMatchers(MatchFinder *Finder) { auto IsSusbstituted = qualType(anyOf( @@ -28,11 +27,11 @@ hasName("std::default_delete"))))))); Finder->addMatcher( - cxxDeleteExpr(has(ignoringParenImpCasts(cxxMemberCallExpr( - on(expr(hasType(UniquePtrWithDefaultDelete), - unless(hasType(IsSusbstituted))) - .bind("uptr")), - callee(cxxMethodDecl(hasName("release"))))))) + cxxDeleteExpr( + has(cxxMemberCallExpr(on(expr(hasType(UniquePtrWithDefaultDelete), + unless(hasType(IsSusbstituted))) + .bind("uptr")), + callee(cxxMethodDecl(hasName("release")))))) .bind("delete"), this); } @@ -65,7 +64,6 @@ " = nullptr"); } -} // namespace readability } // namespace tidy } // namespace clang Index: clang-tidy/tool/CMakeLists.txt =================================================================== --- clang-tidy/tool/CMakeLists.txt +++ clang-tidy/tool/CMakeLists.txt @@ -5,15 +5,11 @@ add_clang_executable(clang-tidy ClangTidyMain.cpp ) -add_dependencies(clang-tidy - clang-headers - ) target_link_libraries(clang-tidy clangAST clangASTMatchers clangBasic clangTidy - clangTidyBoostModule clangTidyCERTModule clangTidyCppCoreGuidelinesModule clangTidyGoogleModule Index: clang-tidy/tool/ClangTidyMain.cpp =================================================================== --- clang-tidy/tool/ClangTidyMain.cpp +++ clang-tidy/tool/ClangTidyMain.cpp @@ -313,19 +313,13 @@ if (!PathList.empty()) { FileName = PathList.front(); } - - SmallString<256> FilePath(FileName); - if (std::error_code EC = llvm::sys::fs::make_absolute(FilePath)) { - llvm::errs() << "Can't make absolute path from " << FileName << ": " - << EC.message() << "\n"; - } - ClangTidyOptions EffectiveOptions = OptionsProvider->getOptions(FilePath); + ClangTidyOptions EffectiveOptions = OptionsProvider->getOptions(FileName); std::vector EnabledChecks = getCheckNames(EffectiveOptions); if (ExplainConfig) { //FIXME: Show other ClangTidyOptions' fields, like ExtraArg. std::vector - RawOptions = OptionsProvider->getRawOptions(FilePath); + RawOptions = OptionsProvider->getRawOptions(FileName); for (const std::string &Check : EnabledChecks) { for (auto It = RawOptions.rbegin(); It != RawOptions.rend(); ++It) { if (It->first.Checks && GlobList(*It->first.Checks).contains(Check)) { @@ -344,7 +338,7 @@ return 1; } llvm::outs() << "Enabled checks:"; - for (const auto &CheckName : EnabledChecks) + for (auto CheckName : EnabledChecks) llvm::outs() << "\n " << CheckName; llvm::outs() << "\n\n"; return 0; @@ -424,11 +418,6 @@ static int LLVM_ATTRIBUTE_UNUSED CERTModuleAnchorDestination = CERTModuleAnchorSource; -// This anchor is used to force the linker to link the BoostModule. -extern volatile int BoostModuleAnchorSource; -static int LLVM_ATTRIBUTE_UNUSED BoostModuleAnchorDestination = - BoostModuleAnchorSource; - // This anchor is used to force the linker to link the LLVMModule. extern volatile int LLVMModuleAnchorSource; static int LLVM_ATTRIBUTE_UNUSED LLVMModuleAnchorDestination = Index: clang-tidy/tool/clang-tidy-diff.py =================================================================== --- clang-tidy/tool/clang-tidy-diff.py +++ clang-tidy/tool/clang-tidy-diff.py @@ -33,20 +33,20 @@ def main(): parser = argparse.ArgumentParser(description= - 'Run clang-tidy against changed files, and ' - 'output diagnostics only for modified ' - 'lines.') + 'Reformat changed lines in diff. Without -i ' + 'option just output the diff that would be ' + 'introduced.') parser.add_argument('-clang-tidy-binary', metavar='PATH', default='clang-tidy', help='path to clang-tidy binary') parser.add_argument('-p', metavar='NUM', default=0, help='strip the smallest prefix containing P slashes') parser.add_argument('-regex', metavar='PATTERN', default=None, - help='custom pattern selecting file paths to check ' + help='custom pattern selecting file paths to reformat ' '(case sensitive, overrides -iregex)') parser.add_argument('-iregex', metavar='PATTERN', default= r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc)', - help='custom pattern selecting file paths to check ' + help='custom pattern selecting file paths to reformat ' '(case insensitive, overridden by -regex)') parser.add_argument('-fix', action='store_true', default=False, Index: clang-tidy/utils/CMakeLists.txt =================================================================== --- clang-tidy/utils/CMakeLists.txt +++ clang-tidy/utils/CMakeLists.txt @@ -3,12 +3,11 @@ add_clang_library(clangTidyUtils DeclRefExprUtils.cpp FixItHintUtils.cpp - HeaderFileExtensionsUtils.cpp HeaderGuard.cpp + HeaderFileExtensionsUtils.cpp IncludeInserter.cpp IncludeSorter.cpp LexerUtils.cpp - OptionsUtils.cpp TypeTraits.cpp LINK_LIBS Index: clang-tidy/utils/DeclRefExprUtils.h =================================================================== --- clang-tidy/utils/DeclRefExprUtils.h +++ clang-tidy/utils/DeclRefExprUtils.h @@ -12,43 +12,20 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Type.h" -#include "llvm/ADT/SmallPtrSet.h" namespace clang { namespace tidy { -namespace utils { -namespace decl_ref_expr { +namespace decl_ref_expr_utils { -/// \brief Returns true if all ``DeclRefExpr`` to the variable within ``Stmt`` -/// do not modify it. +/// \brief Returns true if all DeclRefExpr to the variable within Stmt do not +/// modify it. /// -/// Returns ``true`` if only const methods or operators are called on the -/// variable or the variable is a const reference or value argument to a -/// ``callExpr()``. +/// Returns true if only const methods or operators are called on the variable +/// or the variable is a const reference or value argument to a callExpr(). bool isOnlyUsedAsConst(const VarDecl &Var, const Stmt &Stmt, ASTContext &Context); -// Returns set of all DeclRefExprs to VarDecl in Stmt. -llvm::SmallPtrSet -allDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context); - -// Returns set of all DeclRefExprs where VarDecl is guaranteed to be accessed in -// a const fashion. -llvm::SmallPtrSet -constReferenceDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, - ASTContext &Context); - -// Returns true if DeclRefExpr is the argument of a copy-constructor call expr. -bool isCopyConstructorArgument(const DeclRefExpr &DeclRef, const Stmt &Stmt, - ASTContext &Context); - -// Returns true if DeclRefExpr is the argument of a copy-assignment operator -// call expr. -bool isCopyAssignmentArgument(const DeclRefExpr &DeclRef, const Stmt &Stmt, - ASTContext &Context); - -} // namespace decl_ref_expr -} // namespace utils +} // namespace decl_ref_expr_utils } // namespace tidy } // namespace clang Index: clang-tidy/utils/DeclRefExprUtils.cpp =================================================================== --- clang-tidy/utils/DeclRefExprUtils.cpp +++ clang-tidy/utils/DeclRefExprUtils.cpp @@ -8,15 +8,14 @@ //===----------------------------------------------------------------------===// #include "DeclRefExprUtils.h" -#include "Matchers.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "llvm/ADT/SmallPtrSet.h" namespace clang { namespace tidy { -namespace utils { -namespace decl_ref_expr { +namespace decl_ref_expr_utils { using namespace ::clang::ast_matchers; using llvm::SmallPtrSet; @@ -38,7 +37,16 @@ Nodes.insert(Match.getNodeAs(ID)); } -} // namespace +// Finds all DeclRefExprs to VarDecl in Stmt. +SmallPtrSet +declRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context) { + auto Matches = match( + findAll(declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind("declRef")), + Stmt, Context); + SmallPtrSet DeclRefs; + extractNodesByIdTo(Matches, "declRef", DeclRefs); + return DeclRefs; +} // Finds all DeclRefExprs where a const method is called on VarDecl or VarDecl // is the a const reference or value argument to a CallExpr or CXXConstructExpr. @@ -71,6 +79,8 @@ return DeclRefs; } +} // namespace + bool isOnlyUsedAsConst(const VarDecl &Var, const Stmt &Stmt, ASTContext &Context) { // Collect all DeclRefExprs to the loop variable and all CallExprs and @@ -78,49 +88,11 @@ // reference parameter. // If the difference is empty it is safe for the loop variable to be a const // reference. - auto AllDeclRefs = allDeclRefExprs(Var, Stmt, Context); + auto AllDeclRefs = declRefExprs(Var, Stmt, Context); auto ConstReferenceDeclRefs = constReferenceDeclRefExprs(Var, Stmt, Context); return isSetDifferenceEmpty(AllDeclRefs, ConstReferenceDeclRefs); } -SmallPtrSet -allDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context) { - auto Matches = match( - findAll(declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind("declRef")), - Stmt, Context); - SmallPtrSet DeclRefs; - extractNodesByIdTo(Matches, "declRef", DeclRefs); - return DeclRefs; -} - -bool isCopyConstructorArgument(const DeclRefExpr &DeclRef, const Stmt &Stmt, - ASTContext &Context) { - auto UsedAsConstRefArg = forEachArgumentWithParam( - declRefExpr(equalsNode(&DeclRef)), - parmVarDecl(hasType(matchers::isReferenceToConst()))); - auto Matches = match( - stmt(hasDescendant( - cxxConstructExpr(UsedAsConstRefArg, hasDeclaration(cxxConstructorDecl( - isCopyConstructor()))) - .bind("constructExpr"))), - Stmt, Context); - return !Matches.empty(); -} - -bool isCopyAssignmentArgument(const DeclRefExpr &DeclRef, const Stmt &Stmt, - ASTContext &Context) { - auto UsedAsConstRefArg = forEachArgumentWithParam( - declRefExpr(equalsNode(&DeclRef)), - parmVarDecl(hasType(matchers::isReferenceToConst()))); - auto Matches = match( - stmt(hasDescendant( - cxxOperatorCallExpr(UsedAsConstRefArg, hasOverloadedOperatorName("=")) - .bind("operatorCallExpr"))), - Stmt, Context); - return !Matches.empty(); -} - -} // namespace decl_ref_expr -} // namespace utils +} // namespace decl_ref_expr_utils } // namespace tidy } // namespace clang Index: clang-tidy/utils/FixItHintUtils.h =================================================================== --- clang-tidy/utils/FixItHintUtils.h +++ clang-tidy/utils/FixItHintUtils.h @@ -16,16 +16,16 @@ namespace clang { namespace tidy { namespace utils { -namespace fixit { +namespace create_fix_it { -/// \brief Creates fix to make ``VarDecl`` a reference by adding ``&``. +/// \brief Creates fix to make VarDecl a reference by adding '&'. FixItHint changeVarDeclToReference(const VarDecl &Var, ASTContext &Context); -/// \brief Creates fix to make ``VarDecl`` const qualified. +/// \brief Creates fix to make VarDecl const qualified. FixItHint changeVarDeclToConst(const VarDecl &Var); -} // namespace fixit -} // namespace utils +} // namespace create_fix_it +} // utils } // namespace tidy } // namespace clang Index: clang-tidy/utils/FixItHintUtils.cpp =================================================================== --- clang-tidy/utils/FixItHintUtils.cpp +++ clang-tidy/utils/FixItHintUtils.cpp @@ -14,11 +14,11 @@ namespace clang { namespace tidy { namespace utils { -namespace fixit { +namespace create_fix_it { FixItHint changeVarDeclToReference(const VarDecl &Var, ASTContext &Context) { SourceLocation AmpLocation = Var.getLocation(); - auto Token = utils::lexer::getPreviousNonCommentToken(Context, AmpLocation); + auto Token = lexer_utils::getPreviousNonCommentToken(Context, AmpLocation); if (!Token.is(tok::unknown)) AmpLocation = Lexer::getLocForEndOfToken(Token.getLocation(), 0, Context.getSourceManager(), @@ -30,7 +30,7 @@ return FixItHint::CreateInsertion(Var.getTypeSpecStartLoc(), "const "); } -} // namespace fixit +} // namespace create_fix_it } // namespace utils } // namespace tidy } // namespace clang Index: clang-tidy/utils/HeaderFileExtensionsUtils.h =================================================================== --- clang-tidy/utils/HeaderFileExtensionsUtils.h +++ clang-tidy/utils/HeaderFileExtensionsUtils.h @@ -10,10 +10,13 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_HEADER_FILE_EXTENSIONS_UTILS_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_HEADER_FILE_EXTENSIONS_UTILS_H +#include + #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/Support/Path.h" namespace clang { namespace tidy { @@ -21,17 +24,17 @@ typedef llvm::SmallSet HeaderFileExtensionsSet; -/// \brief Checks whether expansion location of \p Loc is in header file. +/// \brief Checks whether expansion location of Loc is in header file. bool isExpansionLocInHeaderFile( SourceLocation Loc, const SourceManager &SM, const HeaderFileExtensionsSet &HeaderFileExtensions); -/// \brief Checks whether presumed location of \p Loc is in header file. +/// \brief Checks whether presumed location of Loc is in header file. bool isPresumedLocInHeaderFile( SourceLocation Loc, SourceManager &SM, const HeaderFileExtensionsSet &HeaderFileExtensions); -/// \brief Checks whether spelling location of \p Loc is in header file. +/// \brief Checks whether spelling location of Loc is in header file. bool isSpellingLocInHeaderFile( SourceLocation Loc, SourceManager &SM, const HeaderFileExtensionsSet &HeaderFileExtensions); Index: clang-tidy/utils/HeaderFileExtensionsUtils.cpp =================================================================== --- clang-tidy/utils/HeaderFileExtensionsUtils.cpp +++ clang-tidy/utils/HeaderFileExtensionsUtils.cpp @@ -9,7 +9,6 @@ #include "HeaderFileExtensionsUtils.h" #include "clang/Basic/CharInfo.h" -#include "llvm/Support/Path.h" namespace clang { namespace tidy { Index: clang-tidy/utils/HeaderGuard.h =================================================================== --- clang-tidy/utils/HeaderGuard.h +++ clang-tidy/utils/HeaderGuard.h @@ -14,7 +14,6 @@ namespace clang { namespace tidy { -namespace utils { /// Finds and fixes header guards. class HeaderGuardCheck : public ClangTidyCheck { @@ -23,25 +22,24 @@ : ClangTidyCheck(Name, Context) {} void registerPPCallbacks(CompilerInstance &Compiler) override; - /// Returns ``true`` if the check should suggest inserting a trailing comment - /// on the ``#endif`` of the header guard. It will use the same name as - /// returned by ``HeaderGuardCheck::getHeaderGuard``. + /// \brief Returns true if the checker should suggest inserting a trailing + /// comment on the #endif of the header guard. It will use the same name as + /// returned by getHeaderGuard. virtual bool shouldSuggestEndifComment(StringRef Filename); - /// Returns ``true`` if the check should suggest changing an existing header - /// guard to the string returned by ``HeaderGuardCheck::getHeaderGuard``. + /// \brief Returns true if the checker should suggest changing an existing + /// header guard to the string returned by getHeaderGuard. virtual bool shouldFixHeaderGuard(StringRef Filename); - /// Returns ``true`` if the check should add a header guard to the file + /// \brief Returns true if the checker should add a header guard to the file /// if it has none. virtual bool shouldSuggestToAddHeaderGuard(StringRef Filename); - /// Returns a replacement for the ``#endif`` line with a comment mentioning - /// \p HeaderGuard. The replacement should start with ``endif``. + /// \brief Returns a replacement for endif line with a comment mentioning + /// \p HeaderGuard. The replacement should start with "endif". virtual std::string formatEndIf(StringRef HeaderGuard); - /// Gets the canonical header guard for a file. + /// \brief Get the canonical header guard for a file. virtual std::string getHeaderGuard(StringRef Filename, StringRef OldGuard = StringRef()) = 0; }; -} // namespace utils } // namespace tidy } // namespace clang Index: clang-tidy/utils/HeaderGuard.cpp =================================================================== --- clang-tidy/utils/HeaderGuard.cpp +++ clang-tidy/utils/HeaderGuard.cpp @@ -16,19 +16,31 @@ namespace clang { namespace tidy { -namespace utils { /// \brief canonicalize a path by removing ./ and ../ components. +// FIXME: Consider moving this to llvm::sys::path. static std::string cleanPath(StringRef Path) { - SmallString<256> Result = Path; - llvm::sys::path::remove_dots(Result, true); - return Result.str(); + SmallString<256> NewPath; + for (auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path); + I != E; ++I) { + if (*I == ".") + continue; + if (*I == "..") { + // Drop the last component. + NewPath.resize(llvm::sys::path::parent_path(NewPath).size()); + } else { + if (!NewPath.empty() && !NewPath.endswith("/")) + NewPath += '/'; + NewPath += *I; + } + } + return NewPath.str(); } namespace { class HeaderGuardPPCallbacks : public PPCallbacks { public: - HeaderGuardPPCallbacks(Preprocessor *PP, HeaderGuardCheck *Check) + explicit HeaderGuardPPCallbacks(Preprocessor *PP, HeaderGuardCheck *Check) : PP(PP), Check(Check) {} void FileChanged(SourceLocation Loc, FileChangeReason Reason, @@ -287,6 +299,5 @@ return "endif // " + HeaderGuard.str(); } -} // namespace utils } // namespace tidy } // namespace clang Index: clang-tidy/utils/IncludeInserter.h =================================================================== --- clang-tidy/utils/IncludeInserter.h +++ clang-tidy/utils/IncludeInserter.h @@ -20,55 +20,47 @@ namespace clang { namespace tidy { -namespace utils { -/// \brief Produces fixes to insert specified includes to source files, if not -/// yet present. -/// -/// ``IncludeInserter`` can be used by ``ClangTidyCheck`` in the following -/// fashion: -/// \code -/// class MyCheck : public ClangTidyCheck { -/// public: -/// void registerPPCallbacks(CompilerInstance& Compiler) override { -/// Inserter.reset(new IncludeInserter(&Compiler.getSourceManager(), -/// &Compiler.getLangOpts())); -/// Compiler.getPreprocessor().addPPCallbacks( -/// Inserter->CreatePPCallback()); -/// } -/// -/// void registerMatchers(ast_matchers::MatchFinder* Finder) override { ... } -/// -/// void check( -/// const ast_matchers::MatchFinder::MatchResult& Result) override { -/// ... -/// Inserter->CreateIncludeInsertion( -/// Result.SourceManager->getMainFileID(), "path/to/Header.h", -/// /*IsAngled=*/false); -/// ... -/// } -/// -/// private: -/// std::unique_ptr Inserter; -/// }; -/// \endcode +// IncludeInserter can be used by ClangTidyChecks in the following fashion: +// class MyCheck : public ClangTidyCheck { +// public: +// void registerPPCallbacks(CompilerInstance& Compiler) override { +// Inserter.reset(new IncludeInserter(&Compiler.getSourceManager(), +// &Compiler.getLangOpts())); +// Compiler.getPreprocessor().addPPCallbacks( +// Inserter->CreatePPCallback()); +// } +// +// void registerMatchers(ast_matchers::MatchFinder* Finder) override { ... } +// +// void check(const ast_matchers::MatchFinder::MatchResult& Result) override { +// ... +// Inserter->CreateIncludeInsertion( +// Result.SourceManager->getMainFileID(), "path/to/Header.h", +// /*IsAngled=*/false); +// ... +// } +// +// private: +// std::unique_ptr Inserter; +// }; class IncludeInserter { public: IncludeInserter(const SourceManager &SourceMgr, const LangOptions &LangOpts, IncludeSorter::IncludeStyle Style); ~IncludeInserter(); - /// Create ``PPCallbacks`` for registration with the compiler's preprocessor. + // Create PPCallbacks for registration with the compiler's preprocessor. std::unique_ptr CreatePPCallbacks(); - /// Creates a \p Header inclusion directive fixit. Returns ``llvm::None`` on - /// error or if inclusion directive already exists. + // Creates a Header inclusion directive fixit. Returns None on error or + // if inclusion directive already exists. llvm::Optional CreateIncludeInsertion(FileID FileID, llvm::StringRef Header, bool IsAngled); private: - void AddInclude(StringRef FileName, bool IsAngled, - SourceLocation HashLocation, SourceLocation EndLocation); + void AddInclude(StringRef file_name, bool IsAngled, + SourceLocation hash_location, SourceLocation end_location); llvm::DenseMap> IncludeSorterByFile; llvm::DenseMap> InsertedHeaders; @@ -78,7 +70,6 @@ friend class IncludeInserterCallback; }; -} // namespace utils } // namespace tidy } // namespace clang #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_INCLUDEINSERTER_H Index: clang-tidy/utils/IncludeInserter.cpp =================================================================== --- clang-tidy/utils/IncludeInserter.cpp +++ clang-tidy/utils/IncludeInserter.cpp @@ -12,7 +12,6 @@ namespace clang { namespace tidy { -namespace utils { class IncludeInserterCallback : public PPCallbacks { public: @@ -67,9 +66,9 @@ return IncludeSorterByFile[FileID]->CreateIncludeInsertion(Header, IsAngled); } -void IncludeInserter::AddInclude(StringRef FileName, bool IsAngled, +void IncludeInserter::AddInclude(StringRef file_name, bool IsAngled, SourceLocation HashLocation, - SourceLocation EndLocation) { + SourceLocation end_location) { FileID FileID = SourceMgr.getFileID(HashLocation); if (IncludeSorterByFile.find(FileID) == IncludeSorterByFile.end()) { IncludeSorterByFile.insert(std::make_pair( @@ -77,10 +76,9 @@ &SourceMgr, &LangOpts, FileID, SourceMgr.getFilename(HashLocation), Style))); } - IncludeSorterByFile[FileID]->AddInclude(FileName, IsAngled, HashLocation, - EndLocation); + IncludeSorterByFile[FileID]->AddInclude(file_name, IsAngled, HashLocation, + end_location); } -} // namespace utils } // namespace tidy } // namespace clang Index: clang-tidy/utils/IncludeSorter.h =================================================================== --- clang-tidy/utils/IncludeSorter.h +++ clang-tidy/utils/IncludeSorter.h @@ -15,72 +15,74 @@ namespace clang { namespace tidy { -namespace utils { -/// Class used by ``IncludeInserterCallback`` to record the names of the -/// inclusions in a given source file being processed and generate the necessary -/// commands to sort the inclusions according to the precedence encoded in -/// ``IncludeKinds``. +// Class used by IncludeSorterCallback and IncludeInserterCallback to record the +// names of the inclusions in a given source file being processed and generate +// the necessary commands to sort the inclusions according to the precedence +// enocded in IncludeKinds. class IncludeSorter { public: - /// Supported include styles. + // Supported include styles. enum IncludeStyle { IS_LLVM = 0, IS_Google = 1 }; - /// Converts "llvm" to ``IS_LLVM``, otherwise returns ``IS_Google``. + // Converts "llvm" to IS_LLVM, otherwise returns IS_Google. static IncludeStyle parseIncludeStyle(const std::string &Value); - /// Converts ``IncludeStyle`` to string representation. + // Converts IncludeStyle to string representation. static StringRef toString(IncludeStyle Style); - /// The classifications of inclusions, in the order they should be sorted. + // The classifications of inclusions, in the order they should be sorted. enum IncludeKinds { - IK_MainTUInclude = 0, ///< e.g. ``#include "foo.h"`` when editing foo.cc - IK_CSystemInclude = 1, ///< e.g. ``#include `` - IK_CXXSystemInclude = 2, ///< e.g. ``#include `` - IK_NonSystemInclude = 3, ///< e.g. ``#include "bar.h"`` - IK_InvalidInclude = 4 ///< total number of valid ``IncludeKind``s + IK_MainTUInclude = 0, // e.g. #include "foo.h" when editing foo.cc + IK_CSystemInclude = 1, // e.g. #include + IK_CXXSystemInclude = 2, // e.g. #include + IK_NonSystemInclude = 3, // e.g. #include "bar.h" + IK_InvalidInclude = 4 // total number of valid IncludeKinds }; - /// ``IncludeSorter`` constructor; takes the FileID and name of the file to be - /// processed by the sorter. + // IncludeSorter constructor; takes the FileID and name of the file to be + // processed by the sorter. IncludeSorter(const SourceManager *SourceMgr, const LangOptions *LangOpts, const FileID FileID, StringRef FileName, IncludeStyle Style); - /// Returns the ``SourceManager``-specific file ID for the file being handled - /// by the sorter. + // Returns the SourceManager-specific file ID for the file being handled by + // the sorter. const FileID current_FileID() const { return CurrentFileID; } - /// Adds the given include directive to the sorter. + // Adds the given #include to the sorter. void AddInclude(StringRef FileName, bool IsAngled, SourceLocation HashLocation, SourceLocation EndLocation); - /// Returns the edits needed to sort the current set of includes and reset the - /// internal state (so that different blocks of includes are sorted separately - /// within the same file). + // Returns the edits needed to sort the current set of includes and reset the + // internal state (so that different blocks of includes are sorted separately + // within the same file). std::vector GetEdits(); - /// Creates a quoted inclusion directive in the right sort order. Returns None - /// on error or if header inclusion directive for header already exists. + // Creates a quoted inclusion directive in the right sort order. Returns None + // on error or if header inclusion directive for header already exists. Optional CreateIncludeInsertion(StringRef FileName, bool IsAngled); private: typedef SmallVector SourceRangeVector; + // Creates a fix-it for the given replacements. + // Takes the the source location that will be replaced, and the new text. + FixItHint CreateFixIt(SourceRange EditRange, const std::string &NewText); + const SourceManager *SourceMgr; const LangOptions *LangOpts; const IncludeStyle Style; FileID CurrentFileID; - /// The file name stripped of common suffixes. + // The file name stripped of common suffixes. StringRef CanonicalFile; - /// Locations of visited include directives. + // Locations of visited include directives. SourceRangeVector SourceLocations; - /// Mapping from file name to #include locations. + // Mapping from file name to #include locations. llvm::StringMap IncludeLocations; - /// Includes sorted into buckets. + // Includes sorted into buckets. SmallVector IncludeBucket[IK_InvalidInclude]; }; -} // namespace utils } // namespace tidy } // namespace clang #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_INCLUDESORTER_H Index: clang-tidy/utils/IncludeSorter.cpp =================================================================== --- clang-tidy/utils/IncludeSorter.cpp +++ clang-tidy/utils/IncludeSorter.cpp @@ -12,7 +12,6 @@ namespace clang { namespace tidy { -namespace utils { namespace { @@ -254,8 +253,7 @@ // Otherwise report the current block edit and start a new block. } else { if (CurrentEndLine) { - Fixes.push_back(FixItHint::CreateReplacement( - CharSourceRange::getCharRange(CurrentRange), CurrentText)); + Fixes.push_back(CreateFixIt(CurrentRange, CurrentText)); } CurrentEndLine = LineEdit.first; @@ -265,8 +263,7 @@ } // Finally, report the current block edit if there is one. if (CurrentEndLine) { - Fixes.push_back(FixItHint::CreateReplacement( - CharSourceRange::getCharRange(CurrentRange), CurrentText)); + Fixes.push_back(CreateFixIt(CurrentRange, CurrentText)); } // Reset the remaining internal state. @@ -275,6 +272,16 @@ return Fixes; } +// Creates a fix-it for the given replacements. +// Takes the the source location that will be replaced, and the new text. +FixItHint IncludeSorter::CreateFixIt(SourceRange EditRange, + const std::string &NewText) { + FixItHint Fix; + Fix.RemoveRange = CharSourceRange::getCharRange(EditRange); + Fix.CodeToInsert = NewText; + return Fix; +} + IncludeSorter::IncludeStyle IncludeSorter::parseIncludeStyle(const std::string &Value) { return Value == "llvm" ? IS_LLVM : IS_Google; @@ -284,6 +291,5 @@ return Style == IS_LLVM ? "llvm" : "google"; } -} // namespace utils } // namespace tidy } // namespace clang Index: clang-tidy/utils/LexerUtils.h =================================================================== --- clang-tidy/utils/LexerUtils.h +++ clang-tidy/utils/LexerUtils.h @@ -15,16 +15,14 @@ namespace clang { namespace tidy { -namespace utils { -namespace lexer { +namespace lexer_utils { -/// Returns previous non-comment token skipping over any comment text or -/// ``tok::unknown`` if not found. +// Returns previous non-comment token skipping over any comment text or +// tok::unknown if not found. Token getPreviousNonCommentToken(const ASTContext &Context, SourceLocation Location); -} // namespace lexer -} // namespace utils +} // namespace lexer_utils } // namespace tidy } // namespace clang Index: clang-tidy/utils/LexerUtils.cpp =================================================================== --- clang-tidy/utils/LexerUtils.cpp +++ clang-tidy/utils/LexerUtils.cpp @@ -11,8 +11,7 @@ namespace clang { namespace tidy { -namespace utils { -namespace lexer { +namespace lexer_utils { Token getPreviousNonCommentToken(const ASTContext &Context, SourceLocation Location) { @@ -35,7 +34,6 @@ return Token; } -} // namespace lexer -} // namespace utils +} // namespace lexer_utils } // namespace tidy } // namespace clang Index: clang-tidy/utils/Matchers.h =================================================================== --- clang-tidy/utils/Matchers.h +++ clang-tidy/utils/Matchers.h @@ -31,23 +31,15 @@ AST_MATCHER(QualType, isExpensiveToCopy) { llvm::Optional IsExpensive = - utils::type_traits::isExpensiveToCopy(Node, Finder->getASTContext()); + type_traits::isExpensiveToCopy(Node, Finder->getASTContext()); return IsExpensive && *IsExpensive; } AST_MATCHER(RecordDecl, isTriviallyDefaultConstructible) { - return utils::type_traits::recordIsTriviallyDefaultConstructible( + return type_traits::recordIsTriviallyDefaultConstructible( Node, Finder->getASTContext()); } -AST_MATCHER(FieldDecl, isBitfield) { return Node.isBitField(); } - -// Returns QualType matcher for references to const. -AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isReferenceToConst) { - using namespace ast_matchers; - return referenceType(pointee(qualType(isConstQualified()))); -} - } // namespace matchers } // namespace tidy } // namespace clang Index: clang-tidy/utils/OptionsUtils.h =================================================================== --- clang-tidy/utils/OptionsUtils.h +++ /dev/null @@ -1,32 +0,0 @@ -//===--- DanglingHandleCheck.h - clang-tidy----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_OPTIONUTILS_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_OPTIONUTILS_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace utils { -namespace options { - -/// \brief Parse a semicolon separated list of strings. -std::vector parseStringList(StringRef Option); - -/// \brief Serialize a sequence of names that can be parsed by -/// ``parseStringList``. -std::string serializeStringList(ArrayRef Strings); - -} // namespace options -} // namespace utils -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_OPTIONUTILS_H Index: clang-tidy/utils/OptionsUtils.cpp =================================================================== --- clang-tidy/utils/OptionsUtils.cpp +++ /dev/null @@ -1,38 +0,0 @@ -//===--- DanglingHandleCheck.cpp - clang-tidy------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "OptionsUtils.h" - -namespace clang { -namespace tidy { -namespace utils { -namespace options { - -static const char StringsDelimiter[] = ";"; - -std::vector parseStringList(StringRef Option) { - SmallVector Names; - Option.split(Names, StringsDelimiter); - std::vector Result; - for (StringRef &Name : Names) { - Name = Name.trim(); - if (!Name.empty()) - Result.push_back(Name); - } - return Result; -} - -std::string serializeStringList(ArrayRef Strings) { - return llvm::join(Strings.begin(), Strings.end(), StringsDelimiter); -} - -} // namespace options -} // namespace utils -} // namespace tidy -} // namespace clang Index: clang-tidy/utils/TypeTraits.h =================================================================== --- clang-tidy/utils/TypeTraits.h +++ clang-tidy/utils/TypeTraits.h @@ -15,28 +15,19 @@ namespace clang { namespace tidy { -namespace utils { namespace type_traits { -/// Returns `true` if `Type` is expensive to copy. -llvm::Optional isExpensiveToCopy(QualType Type, - const ASTContext &Context); +// \brief Returns true If \c Type is expensive to copy. +llvm::Optional isExpensiveToCopy(QualType Type, ASTContext &Context); -/// Returns `true` if `Type` is trivially default constructible. +// \brief Returns true If \c Type is trivially default constructible. bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context); -/// Returns `true` if `RecordDecl` is trivially default constructible. +// \brief Returns true If \c RecordDecl is trivially default constructible. bool recordIsTriviallyDefaultConstructible(const RecordDecl &RecordDecl, const ASTContext &Context); -/// Returns true if `Type` has a non-trivial move constructor. -bool hasNonTrivialMoveConstructor(QualType Type); - -/// Return true if `Type` has a non-trivial move assignment operator. -bool hasNonTrivialMoveAssignment(QualType Type); - } // type_traits -} // namespace utils } // namespace tidy } // namespace clang Index: clang-tidy/utils/TypeTraits.cpp =================================================================== --- clang-tidy/utils/TypeTraits.cpp +++ clang-tidy/utils/TypeTraits.cpp @@ -10,42 +10,25 @@ #include "TypeTraits.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" namespace clang { namespace tidy { -namespace utils { namespace type_traits { namespace { - bool classHasTrivialCopyAndDestroy(QualType Type) { auto *Record = Type->getAsCXXRecordDecl(); return Record && Record->hasDefinition() && !Record->hasNonTrivialCopyConstructor() && !Record->hasNonTrivialDestructor(); } - -bool hasDeletedCopyConstructor(QualType Type) { - auto *Record = Type->getAsCXXRecordDecl(); - if (!Record || !Record->hasDefinition()) - return false; - for (const auto *Constructor : Record->ctors()) { - if (Constructor->isCopyConstructor() && Constructor->isDeleted()) - return true; - } - return false; -} - } // namespace -llvm::Optional isExpensiveToCopy(QualType Type, - const ASTContext &Context) { +llvm::Optional isExpensiveToCopy(QualType Type, ASTContext &Context) { if (Type->isDependentType()) return llvm::None; return !Type.isTriviallyCopyableType(Context) && - !classHasTrivialCopyAndDestroy(Type) && - !hasDeletedCopyConstructor(Type); + !classHasTrivialCopyAndDestroy(Type); } bool recordIsTriviallyDefaultConstructible(const RecordDecl &RecordDecl, @@ -77,8 +60,7 @@ } // Based on QualType::isTrivial. -bool isTriviallyDefaultConstructible(QualType Type, - const ASTContext &Context) { +bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context) { if (Type.isNull()) return false; @@ -124,19 +106,6 @@ return false; } -bool hasNonTrivialMoveConstructor(QualType Type) { - auto *Record = Type->getAsCXXRecordDecl(); - return Record && Record->hasDefinition() && - Record->hasNonTrivialMoveConstructor(); -} - -bool hasNonTrivialMoveAssignment(QualType Type) { - auto *Record = Type->getAsCXXRecordDecl(); - return Record && Record->hasDefinition() && - Record->hasNonTrivialMoveAssignment(); -} - -} // namespace type_traits -} // namespace utils +} // type_traits } // namespace tidy } // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -44,8 +44,7 @@ Major New Features ------------------ -- :program:`clang-include-fixer`, a tool that provides an automated way of - adding ``#include`` directives for missing symbols in one translation unit. +- Feature1... Improvements to clang-query --------------------------- @@ -64,26 +63,12 @@ explain them more clearly, and provide more accurate fix-its for the issues identified. The improvements since the 3.8 release include: -- New Boost module containing checks for issues with Boost library. - -- New `boost-use-to-string - `_ check - - Finds usages of ``boost::lexical_cast`` and changes it to - ``std::to_string``. - - New `cert-env33-c `_ check Flags calls to ``system()``, ``popen()``, and ``_popen()``, which execute a command processor. -- New `cert-err34-c - `_ check - - Flags calls to string-to-number conversion functions that do not verify the - validity of the conversion. - - New `cert-flp30-c `_ check @@ -101,11 +86,6 @@ Flags user-defined constructor definitions that do not initialize all builtin and pointer fields which leaves their memory in an undefined state. -- New `google-default-arguments - `_ check - - Flags default arguments in virtual methods. - - New `misc-dangling-handle `_ check @@ -123,12 +103,6 @@ Checks if an unused forward declaration is in a wrong namespace. -- New `misc-misplaced-const - `_ check - - Checks if a ``const`` qualifier is applied to a ``typedef`` to pointer type - instead of the underlying pointee type. - - New `misc-misplaced-widening-cast `_ check @@ -182,54 +156,22 @@ Find suspicious usage of runtime string comparison functions. -- New `misc-unconventional-assign-operator - `_ - check replacing the *misc-assign-operator-signature* check. - - Does not only checks for correct signature but also for correct ``return`` - statements (returning ``*this``) - - New `misc-unused-using-decls `_ check Finds unused ``using`` declarations. -- New `modernize-avoid-bind - `_ check - - Finds uses of ``std::bind`` and replaces simple uses with lambdas. - - New `modernize-deprecated-headers `_ check Replaces C standard library headers with their C++ alternatives. -- New `modernize-make-shared - `_ check - - Replaces creation of ``std::shared_ptr`` from new expression with call to ``std::make_shared``. - - New `modernize-raw-string-literal `_ check Selectively replaces string literals containing escaped characters with raw string literals. -- New `modernize-use-bool-literals - `_ check - - Finds integer literals which are cast to ``bool``. - -- New `modernize-use-emplace - `_ check - - Finds calls that could be changed to emplace. - -- New `modernize-use-using - `_ check - - Finds typedefs and replaces it with usings. - - New `performance-faster-string-find `_ check @@ -259,11 +201,6 @@ Warns about defaulted constructors and assignment operators that are actually deleted. -- Updated `readability-identifier-naming-check - `_ - - Added support for enforcing the case of macro statements. - - New `readability-redundant-control-flow `_ check Index: docs/clang-tidy/checks/boost-use-to-string.rst =================================================================== --- docs/clang-tidy/checks/boost-use-to-string.rst +++ /dev/null @@ -1,22 +0,0 @@ -.. title:: clang-tidy - boost-use-to-string - -boost-use-to-string -=================== - -This check finds conversion from integer type like ``int`` to ``std::string`` or -``std::wstring`` using ``boost::lexical_cast``, and replace it with calls to -``std::to_string`` and ``std::to_wstring``. - -It doesn't replace conversion from floating points despite the ``to_string`` -overloads, because it would change the behaviour. - - - .. code-block:: c++ - - auto str = boost::lexical_cast(42); - auto wstr = boost::lexical_cast(2137LL); - - // Will be changed to - auto str = std::to_string(42); - auto wstr = std::to_wstring(2137LL); - Index: docs/clang-tidy/checks/cert-err34-c.rst =================================================================== --- docs/clang-tidy/checks/cert-err34-c.rst +++ /dev/null @@ -1,28 +0,0 @@ -.. title:: clang-tidy - cert-err34-c - -cert-err34-c -============ - -This check flags calls to string-to-number conversion functions that do not -verify the validity of the conversion, such as ``atoi()`` or ``scanf()``. It -does not flag calls to ``strtol()``, or other, related conversion functions that -do perform better error checking. - -.. code:: c - - #include - - void func(const char *buff) { - int si; - - if (buff) { - si = atoi(buff); /* 'atoi' used to convert a string to an integer, but function will - not report conversion errors; consider using 'strtol' instead. */ - } else { - /* Handle error */ - } - } - -This check corresponds to the CERT C Coding Standard rule -`ERR34-C. Detect errors when converting a string to a number -`_. Index: docs/clang-tidy/checks/cert-msc50-cpp.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/cert-msc50-cpp.rst @@ -0,0 +1,6 @@ +.. title:: clang-tidy - cert-msc50-cpp + +cert-msc-50 +======================= + +Pseudorandom number generators use mathematical algorithms to produce a sequence of numbers with good statistical properties, but the numbers produced are not genuinely random. This checker warns for the usage of std::rand(). Index: docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst =================================================================== --- docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst +++ docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst @@ -19,10 +19,10 @@ account but generates false positives for fields initialized in methods invoked in the constructor body. -The check also flags variables with automatic storage duration that have record -types without a user-provided constructor and are not initialized. The suggested -fix is to zero initialize the variable via ``{}`` for C++11 and beyond or ``= -{}`` for older language versions. +The check also flags variables of record types without a user-provided +constructor that are not initialized. The suggested fix is to zero +initialize the variable via {} for C++11 and beyond or = {} for older +versions. IgnoreArrays option ------------------- Index: docs/clang-tidy/checks/google-default-arguments.rst =================================================================== --- docs/clang-tidy/checks/google-default-arguments.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. title:: clang-tidy - google-default-arguments - -google-default-arguments -======================== - -Checks that default arguments are not given for virtual methods. - -See https://google.github.io/styleguide/cppguide.html#Default_Arguments Index: docs/clang-tidy/checks/google-global-names-in-headers.rst =================================================================== --- docs/clang-tidy/checks/google-global-names-in-headers.rst +++ docs/clang-tidy/checks/google-global-names-in-headers.rst @@ -5,13 +5,3 @@ Flag global namespace pollution in header files. Right now it only triggers on ``using`` declarations and directives. - -The check supports these options: - - `HeaderFileExtensions`: a comma-separated list of filename extensions - of header files (the filename extensions should not contain "." prefix). - "h" by default. - For extension-less header files, using an empty string or leaving an - empty string between "," if there are other filename extensions. - -The relevant style guide section is -https://google.github.io/styleguide/cppguide.html#Namespaces. Index: docs/clang-tidy/checks/google-readability-todo.rst =================================================================== --- docs/clang-tidy/checks/google-readability-todo.rst +++ docs/clang-tidy/checks/google-readability-todo.rst @@ -5,7 +5,4 @@ Finds TODO comments without a username or bug number. -The relevant style guide section is -https://google.github.io/styleguide/cppguide.html#TODO_Comments. - Corresponding cpplint.py check: `readability/todo` Index: docs/clang-tidy/checks/google-runtime-int.rst =================================================================== --- docs/clang-tidy/checks/google-runtime-int.rst +++ docs/clang-tidy/checks/google-runtime-int.rst @@ -7,6 +7,6 @@ with ``u?intXX(_t)?``. The corresponding style guide rule: -https://google.github.io/styleguide/cppguide.html#Integer_Types. +https://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Integer_Types. Correspondig cpplint.py check: `runtime/int`. Index: docs/clang-tidy/checks/google-runtime-references.rst =================================================================== --- docs/clang-tidy/checks/google-runtime-references.rst +++ docs/clang-tidy/checks/google-runtime-references.rst @@ -1,5 +1,3 @@ -.. title:: clang-tidy - google-runtime-references - google-runtime-references ========================= Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -3,20 +3,19 @@ Clang-Tidy Checks ========================= -.. toctree:: - boost-use-to-string +.. toctree:: cert-dcl03-c (redirects to misc-static-assert) cert-dcl50-cpp cert-dcl54-cpp (redirects to misc-new-delete-overloads) cert-dcl59-cpp (redirects to google-build-namespaces) cert-env33-c - cert-err34-c cert-err52-cpp cert-err58-cpp cert-err60-cpp cert-err61-cpp (redirects to misc-throw-by-value-catch-by-reference) cert-fio38-c (redirects to misc-non-copyable-objects) cert-flp30-c + cert-msc50-cpp cert-oop11-cpp (redirects to misc-move-constructor-init) cppcoreguidelines-interfaces-global-init cppcoreguidelines-pro-bounds-array-to-pointer-decay @@ -32,7 +31,6 @@ google-build-explicit-make-pair google-build-namespaces google-build-using-namespace - google-default-arguments google-explicit-constructor google-global-names-in-headers google-readability-braces-around-statements (redirects to readability-braces-around-statements) @@ -52,6 +50,7 @@ llvm-twine-local misc-argument-comment misc-assert-side-effect + misc-assign-operator-signature misc-bool-pointer-implicit-conversion misc-dangling-handle misc-definitions-in-headers @@ -62,7 +61,6 @@ misc-inefficient-algorithm misc-macro-parentheses misc-macro-repeated-side-effects - misc-misplaced-const misc-misplaced-widening-cast misc-move-const-arg misc-move-constructor-init @@ -83,7 +81,6 @@ misc-suspicious-string-compare misc-swapped-arguments misc-throw-by-value-catch-by-reference - misc-unconventional-assign-operator misc-undelegated-constructor misc-uniqueptr-reset-release misc-unused-alias-decls @@ -91,10 +88,8 @@ misc-unused-raii misc-unused-using-decls misc-virtual-near-miss - modernize-avoid-bind modernize-deprecated-headers modernize-loop-convert - modernize-make-shared modernize-make-unique modernize-pass-by-value modernize-raw-string-literal @@ -102,12 +97,9 @@ modernize-replace-auto-ptr modernize-shrink-to-fit modernize-use-auto - modernize-use-bool-literals modernize-use-default - modernize-use-emplace modernize-use-nullptr modernize-use-override - modernize-use-using performance-faster-string-find performance-for-range-copy performance-implicit-cast-in-loop Index: docs/clang-tidy/checks/misc-assign-operator-signature.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/misc-assign-operator-signature.rst @@ -0,0 +1,14 @@ +.. title:: clang-tidy - misc-assign-operator-signature + +misc-assign-operator-signature +============================== + + +Finds declarations of assign operators with the wrong return and/or argument +types. + + * The return type must be ``Class&``. + * Works with move-assign and assign by value. + * Private and deleted operators are ignored. + * There must be return statement in ``operator=`` method definitions. + * Return statement must be ``return *this`` Index: docs/clang-tidy/checks/misc-definitions-in-headers.rst =================================================================== --- docs/clang-tidy/checks/misc-definitions-in-headers.rst +++ docs/clang-tidy/checks/misc-definitions-in-headers.rst @@ -1,74 +1,39 @@ -.. title:: clang-tidy - misc-definitions-in-headers - misc-definitions-in-headers =========================== Finds non-extern non-inline function and variable definitions in header files, -which can lead to potential ODR violations in case these headers are included -from multiple translation units. +which can lead to potential ODR violations. .. code:: c++ // Foo.h - int a = 1; // Warning: variable definition. + int a = 1; // Warning. extern int d; // OK: extern variable. namespace N { - int e = 2; // Warning: variable definition. + int e = 2; // Warning. } - // Warning: variable definition. - const char* str = "foo"; - - // OK: internal linkage variable definitions are ignored for now. + // Internal linkage variable definitions are ignored for now. // Although these might also cause ODR violations, we can be less certain and // should try to keep the false-positive rate down. static int b = 1; const int c = 1; - const char* const str2 = "foo"; - // Warning: function definition. + // Warning. int g() { return 1; } - // OK: inline function definition is allowed to be defined multiple times. + // OK: inline function definition. inline int e() { return 1; } class A { public: - int f1() { return 1; } // OK: implicitly inline member function definition is allowed. + int f1() { return 1; } // OK: inline member function definition. int f2(); - static int d; - }; - - // Warning: not an inline member function definition. - int A::f2() { return 1; } - - // OK: class static data member declaration is allowed. - int A::d = 1; - - // OK: function template is allowed. - template - T f3() { - T a = 1; - return a; - } - - // Warning: full specialization of a function template is not allowed. - template <> - int f3() { - int a = 1; - return a; - } - - template - struct B { - void f1(); }; - // OK: member function definition of a class template is allowed. - template - void B::f1() {} + int A::f2() { return 1; } // Warning. Index: docs/clang-tidy/checks/misc-incorrect-roundings.rst =================================================================== --- docs/clang-tidy/checks/misc-incorrect-roundings.rst +++ docs/clang-tidy/checks/misc-incorrect-roundings.rst @@ -1,5 +1,3 @@ -.. title:: clang-tidy - misc-incorrect-roundings - misc-incorrect-roundings ======================== Index: docs/clang-tidy/checks/misc-misplaced-const.rst =================================================================== --- docs/clang-tidy/checks/misc-misplaced-const.rst +++ /dev/null @@ -1,22 +0,0 @@ -.. title:: clang-tidy - misc-misplaced-const - -misc-misplaced-const -==================== - -This check diagnoses when a ``const`` qualifier is applied to a ``typedef`` to a -pointer type rather than to the pointee, because such constructs are often -misleading to developers because the ``const`` applies to the pointer rather -than the pointee. - -For instance, in the following code, the resulting type is ``int *`` ``const`` -rather than ``const int *``: - -.. code:: c++ - - typedef int *int_ptr; - void f(const int_ptr ptr); - -The check does not diagnose when the underlying ``typedef`` type is a pointer to -a ``const`` type or a function pointer type. This is because the ``const`` -qualifier is less likely to be mistaken because it would be redundant (or -disallowed) on the underlying pointee type. Index: docs/clang-tidy/checks/misc-move-const-arg.rst =================================================================== --- docs/clang-tidy/checks/misc-move-const-arg.rst +++ docs/clang-tidy/checks/misc-move-const-arg.rst @@ -3,17 +3,8 @@ misc-move-const-arg =================== -The check warns - - - if ``std::move()`` is called with a constant argument, - - if ``std::move()`` is called with an argument of a trivially-copyable type, - or - - if the result of ``std::move()`` is passed as a const reference argument. - -In all three cases, the check will suggest a fix that removes the -``std::move()``. - -Here are examples of each of the three cases: +The check warns if ``std::move()`` is called with a constant argument or an +argument of a trivially-copyable type, e.g.: .. code:: c++ @@ -22,7 +13,3 @@ int x; return std::move(x); // Warning: std::move of the variable of a trivially-copyable type has no effect - - void f(const string &s); - string s; - f(std::move(s)); // Warning: passing result of std::move as a const reference argument; no move will actually happen Index: docs/clang-tidy/checks/misc-redundant-expression.rst =================================================================== --- docs/clang-tidy/checks/misc-redundant-expression.rst +++ docs/clang-tidy/checks/misc-redundant-expression.rst @@ -12,7 +12,6 @@ * always be a constant (zero or one) Example: - .. code:: c++ ((x+1) | (x+1)) // (x+1) is redundant Index: docs/clang-tidy/checks/misc-unconventional-assign-operator.rst =================================================================== --- docs/clang-tidy/checks/misc-unconventional-assign-operator.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. title:: clang-tidy - misc-unconventional-assign-operator - -misc-unconventional-assign-operator -=================================== - - -Finds declarations of assign operators with the wrong return and/or argument -types and definitions with good return type but wrong ``return`` statements. - - * The return type must be ``Class&``. - * Works with move-assign and assign by value. - * Private and deleted operators are ignored. - * The operator must always return ``*this``. Index: docs/clang-tidy/checks/misc-virtual-near-miss.rst =================================================================== --- docs/clang-tidy/checks/misc-virtual-near-miss.rst +++ docs/clang-tidy/checks/misc-virtual-near-miss.rst @@ -1,10 +1,7 @@ -.. title:: clang-tidy - misc-virtual-near-miss - misc-virtual-near-miss ====================== -Warn if a function is a near miss (ie. the name is very similar and the function -signiture is the same) to a virtual function from a base class. +Warn if a function is a near miss (ie. the name is very similar and the function signiture is the same) to a virtual function from a base class. Example: Index: docs/clang-tidy/checks/modernize-avoid-bind.rst =================================================================== --- docs/clang-tidy/checks/modernize-avoid-bind.rst +++ /dev/null @@ -1,38 +0,0 @@ -.. title:: clang-tidy - modernize-avoid-bind - -modernize-avoid-bind -==================== - -The check finds uses of ``std::bind`` and replaces simple uses with lambdas. -Lambdas will use value-capture where required. - -Right now it only handles free functions, not member functions. - -Given: - -.. code:: c++ - - int add(int x, int y) { return x + y; } - -Then: - -.. code:: c++ - - void f() { - int x = 2; - auto clj = std::bind(add, x, _1); - } - -is replaced by: - -.. code:: c++ - - void f() { - int x = 2; - auto clj = [=](auto && arg1) { return add(x, arg1); }; - } - -``std::bind`` can be hard to read and can result in larger object files and -binaries due to type information that will not be produced by equivalent -lambdas. - Index: docs/clang-tidy/checks/modernize-make-shared.rst =================================================================== --- docs/clang-tidy/checks/modernize-make-shared.rst +++ /dev/null @@ -1,16 +0,0 @@ -.. title:: clang-tidy - modernize-make-shared - -modernize-make-shared -===================== - -This check finds the creation of ``std::shared_ptr`` objects by explicitly -calling the constructor and a ``new`` expression, and replaces it with a call -to ``std::make_shared``. - -.. code-block:: c++ - - auto my_ptr = std::shared_ptr(new MyPair(1, 2)); - - // becomes - - auto my_ptr = std::make_shared(1, 2); Index: docs/clang-tidy/checks/modernize-use-auto.rst =================================================================== --- docs/clang-tidy/checks/modernize-use-auto.rst +++ docs/clang-tidy/checks/modernize-use-auto.rst @@ -124,7 +124,7 @@ // becomes - auto *my_pointer = new TypeName(my_param); + auto my_pointer = new TypeName(my_param); The check will also replace the declaration type in multiple declarations, if the following conditions are satisfied: @@ -141,7 +141,7 @@ // becomes - auto *my_first_pointer = new TypeName, *my_second_pointer = new TypeName; + auto my_first_pointer = new TypeName, my_second_pointer = new TypeName; Known Limitations ----------------- @@ -150,20 +150,3 @@ * User-defined iterators are not handled at this time. -RemoveStars option ------------------- -If the option is set to non-zero (default is `0`), the check will remove stars -from the non-typedef pointer types when replacing type names with ``auto``. -Otherwise, the check will leave stars. For example: - -.. code-block:: c++ - - TypeName *my_first_pointer = new TypeName, *my_second_pointer = new TypeName; - - // RemoveStars = 0 - - auto *my_first_pointer = new TypeName, *my_second_pointer = new TypeName; - - // RemoveStars = 1 - - auto my_first_pointer = new TypeName, my_second_pointer = new TypeName; Index: docs/clang-tidy/checks/modernize-use-bool-literals.rst =================================================================== --- docs/clang-tidy/checks/modernize-use-bool-literals.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. title:: clang-tidy - modernize-use-bool-literals - -modernize-use-bool-literals -=========================== - -Finds integer literals which are cast to ``bool``. - -.. code-block:: c++ - - bool p = 1; - bool f = static_cast(1); - std::ios_base::sync_with_stdio(0); - - // transforms to - - bool p = true; - bool f = true; - std::ios_base::sync_with_stdio(false); Index: docs/clang-tidy/checks/modernize-use-emplace.rst =================================================================== --- docs/clang-tidy/checks/modernize-use-emplace.rst +++ /dev/null @@ -1,69 +0,0 @@ -.. title:: clang-tidy - modernize-use-emplace - -modernize-use-emplace -===================== - -This check looks for cases when inserting new element into an STL -container (``std::vector``, ``std::deque``, ``std::list``) or ``llvm::SmallVector`` -but the element is constructed temporarily. - -Before: - -.. code:: c++ - - std::vector v; - v.push_back(MyClass(21, 37)); - - std::vector > w; - w.push_back(std::make_pair(21, 37)); - -After: - -.. code:: c++ - - std::vector v; - v.emplace_back(21, 37); - - std::vector > w; - v.emplace_back(21, 37); - -The other situation is when we pass arguments that will be converted to a type -inside a container. - -Before: - -.. code:: c++ - - std::vector > v; - v.push_back("abc"); - -After: - -.. code:: c++ - - std::vector > v; - v.emplace_back("abc"); - - -In this case the calls of ``push_back`` won't be replaced. - -.. code:: c++ - std::vector > v; - v.push_back(new int(5)); - auto *ptr = int; - v.push_back(ptr); - -This is because replacing it with ``emplace_back`` could cause a leak of this -pointer if ``emplace_back`` would throw exception before emplacement -(e.g. not enough memory to add new element). - -For more info read item 42 - "Consider emplacement instead of insertion." -of Scott Meyers Efective Modern C++. - -Check also fires if any argument of constructor call would be: -- bitfield (bitfields can't bind to rvalue/universal reference) -- ``new`` expression (to avoid leak) -or if the argument would be converted via derived-to-base cast. - -This check requires C++11 of higher to run. - Index: docs/clang-tidy/checks/modernize-use-using.rst =================================================================== --- docs/clang-tidy/checks/modernize-use-using.rst +++ /dev/null @@ -1,26 +0,0 @@ -.. title:: clang-tidy - modernize-use-using - -modernize-use-using -=================== - -Use C++11's ``using`` instead of ``typedef``. - -Before: - -.. code:: c++ - - typedef int variable; - - class Class{}; - typedef void (Class::* MyPtrType)() const; - -After: - -.. code:: c++ - - using variable = int; - - class Class{}; - using MyPtrType = void (Class::*)() const; - -This check requires using C++11 or higher to run. Index: docs/clang-tidy/checks/performance-implicit-cast-in-loop.rst =================================================================== --- docs/clang-tidy/checks/performance-implicit-cast-in-loop.rst +++ docs/clang-tidy/checks/performance-implicit-cast-in-loop.rst @@ -1,5 +1,3 @@ -.. title:: clang-tidy - performance-implicit-cast-in-loop - performance-implicit-cast-in-loop ================================= Index: docs/clang-tidy/checks/performance-unnecessary-value-param.rst =================================================================== --- docs/clang-tidy/checks/performance-unnecessary-value-param.rst +++ docs/clang-tidy/checks/performance-unnecessary-value-param.rst @@ -10,7 +10,7 @@ which means they are not trivially copyable or have a non-trivial copy constructor or destructor. -To ensure that it is safe to replace the value parameter with a const reference +To ensure that it is safe to replace the value paramater with a const reference the following heuristic is employed: 1. the parameter is const qualified; @@ -31,25 +31,3 @@ Value.ConstMethd(); ExpensiveToCopy Copy(Value); } - -If the parameter is not const, only copied or assigned once and has a -non-trivial move-constructor or move-assignment operator respectively the check -will suggest to move it. - -Example: - -.. code-block:: c++ - - void setValue(string Value) { - Field = Value; - } - -Will become: - -.. code-block:: c++ - - #include - - void setValue(string Value) { - Field = std::move(Value); - } Index: docs/clang-tidy/index.rst =================================================================== --- docs/clang-tidy/index.rst +++ docs/clang-tidy/index.rst @@ -67,8 +67,6 @@ * Clang static analyzer checks are named starting with ``clang-analyzer-``. -* Checks related to Boost library starts with ``boost-``. - Clang diagnostics are treated in a similar way as check diagnostics. Clang diagnostics are displayed by clang-tidy and can be filtered out using ``-checks=`` option. However, the ``-checks=`` option does not affect Index: docs/doxygen.cfg.in =================================================================== --- docs/doxygen.cfg.in +++ docs/doxygen.cfg.in @@ -819,7 +819,7 @@ # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = @abs_srcdir@/../examples # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and @@ -839,7 +839,7 @@ # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = +IMAGE_PATH = @abs_srcdir@/img # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -1913,8 +1913,7 @@ # preprocessor. # This tag requires that the tag SEARCH_INCLUDES is set to YES. -INCLUDE_PATH = @abs_srcdir@/../../../include \ - @abs_srcdir@/../../../../../include +INCLUDE_PATH = ../include # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the Index: docs/include-fixer.rst =================================================================== --- docs/include-fixer.rst +++ /dev/null @@ -1,95 +0,0 @@ -=================== -Clang-Include-Fixer -=================== - -.. contents:: - -One of the major nuisances of C++ compared to other languages is the manual -management of ``#include`` directives in any file. -:program:`clang-include-fixer` addresses one aspect of this problem by providing -an automated way of adding ``#include`` directives for missing symbols in one -translation unit. - -Setup -===== - -To use :program:`clang-include-fixer` two databases are required. Both can be -generated with existing tools. - -- Compilation database. Contains the compiler commands for any given file in a - project and can be generated by CMake, see `How To Setup Tooling For LLVM`_. -- Symbol index. Contains all symbol information in a project to match a given - identifier to a header file. - -Ideally both databases (``compile_commands.json`` and -``find_all_symbols_db.yaml``) are linked into the root of the source tree they -correspond to. Then the :program:`clang-include-fixer` can automatically pick -them up if called with a source file from that tree. Note that by default -``compile_commands.json`` as generated by CMake does not include header files, -so only implementation files can be handled by tools. - -.. _How To Setup Tooling For LLVM: http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html - -Creating a Symbol Index From a Compilation Database ------------------------------------------------------- - -The include fixer contains :program:`find-all-symbols`, a tool to create a -symbol database in YAML format from a compilation database by parsing all -source files listed in it. The following list of commands shows how to set up a -database for LLVM, any project built by CMake should follow similar steps. - -.. code-block:: console - - $ cd path/to/llvm-build - $ ninja find-all-symbols // build find-all-symbols tool. - $ ninja clang-include-fixer // build clang-include-fixer tool. - $ ls compile_commands.json # Make sure compile_commands.json exists. - compile_commands.json - $ path/to/llvm/source/tools/clang/tools/extra/include-fixer/find-all-symbols/tool/run-find-all-symbols.py - ... wait as clang indexes the code base ... - $ ln -s $PWD/find_all_symbols_db.yaml path/to/llvm/source/ # Link database into the source tree. - $ ln -s $PWD/compile_commands.json path/to/llvm/source/ # Also link compilation database if it's not there already. - $ cd path/to/llvm/source - $ /path/to/clang-include-fixer -db=yaml path/to/file/with/missing/include.cpp - Added #include "foo.h" - -Integrate with Vim -------------------- -To run `clang-include-fixer` on a potentially unsaved buffer in Vim. Add the -following key binding to your ``.vimrc``: - -.. code-block:: console - - map ,cf :pyf path/to/llvm/source/tools/clang/tools/extra/include-fixer/tool/clang-include-fixer.py - -This enables `clang-include-fixer` for NORMAL and VISUAL mode. Change ``,cf`` to -another binding if you need clang-include-fixer on a different key. - -Make sure vim can find :program:`clang-include-fixer`: - -- Add the path to :program:`clang-include-fixer` to the PATH environment variable. -- Or set ``g:clang_include_fixer_path`` in vimrc: ``let g:clang_include_fixer_path=path/to/clang-include-fixer`` - -You can customize the number of headers being shown by setting -``let g:clang_include_fixer_maximum_suggested_headers=5`` - -See ``clang-include-fixer.py`` for more details. - -How it Works -============ - -To get the most information out of clang at parse time, -:program:`clang-include-fixer` runs in tandem with the parse and receives -callbacks from Clang's semantic analysis. In particular it reuses the existing -support for typo corrections. Whenever Clang tries to correct a potential typo -it emits a callback to the include fixer which then looks for a corresponding -file. At this point rich lookup information is still available, which is not -available in the AST at a later stage. - -The identifier that should be typo corrected is then sent to the database, if a -header file is returned it is added as an include directive at the top of the -file. - -Currently :program:`clang-include-fixer` only inserts a single include at a -time to avoid getting caught in follow-up errors. If multiple `#include` -additions are desired the program can be rerun until a fix-point is reached. Index: docs/index.rst =================================================================== --- docs/index.rst +++ docs/index.rst @@ -21,7 +21,6 @@ :maxdepth: 2 clang-tidy/index - include-fixer modularize pp-trace Index: include-fixer/CMakeLists.txt =================================================================== --- include-fixer/CMakeLists.txt +++ include-fixer/CMakeLists.txt @@ -4,23 +4,17 @@ add_clang_library(clangIncludeFixer IncludeFixer.cpp - IncludeFixerContext.cpp - InMemorySymbolIndex.cpp - SymbolIndexManager.cpp - YamlSymbolIndex.cpp + InMemoryXrefsDB.cpp LINK_LIBS clangAST clangBasic - clangFormat clangFrontend clangLex clangParse clangSema clangTooling clangToolingCore - findAllSymbols ) add_subdirectory(tool) -add_subdirectory(find-all-symbols) Index: include-fixer/InMemorySymbolIndex.h =================================================================== --- include-fixer/InMemorySymbolIndex.h +++ /dev/null @@ -1,37 +0,0 @@ -//===-- InMemorySymbolIndex.h -----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INMEMORYSYMBOLINDEX_H -#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INMEMORYSYMBOLINDEX_H - -#include "SymbolIndex.h" -#include -#include -#include - -namespace clang { -namespace include_fixer { - -/// Xref database with fixed content. -class InMemorySymbolIndex : public SymbolIndex { -public: - InMemorySymbolIndex(const std::vector &Symbols); - - std::vector - search(llvm::StringRef Identifier) override; - -private: - std::map> - LookupTable; -}; - -} // namespace include_fixer -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INMEMORYSYMBOLINDEX_H Index: include-fixer/InMemorySymbolIndex.cpp =================================================================== --- include-fixer/InMemorySymbolIndex.cpp +++ /dev/null @@ -1,32 +0,0 @@ -//===-- InMemorySymbolIndex.cpp--------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "InMemorySymbolIndex.h" - -using clang::find_all_symbols::SymbolInfo; - -namespace clang { -namespace include_fixer { - -InMemorySymbolIndex::InMemorySymbolIndex( - const std::vector &Symbols) { - for (const auto &Symbol : Symbols) - LookupTable[Symbol.getName()].push_back(Symbol); -} - -std::vector -InMemorySymbolIndex::search(llvm::StringRef Identifier) { - auto I = LookupTable.find(Identifier); - if (I != LookupTable.end()) - return I->second; - return {}; -} - -} // namespace include_fixer -} // namespace clang Index: include-fixer/InMemoryXrefsDB.h =================================================================== --- /dev/null +++ include-fixer/InMemoryXrefsDB.h @@ -0,0 +1,36 @@ +//===-- InMemoryXrefsDB.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INMEMORYXREFSDB_H +#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INMEMORYXREFSDB_H + +#include "XrefsDB.h" +#include +#include +#include + +namespace clang { +namespace include_fixer { + +/// Xref database with fixed content. +class InMemoryXrefsDB : public XrefsDB { +public: + InMemoryXrefsDB(std::map> LookupTable) + : LookupTable(std::move(LookupTable)) {} + + std::vector search(llvm::StringRef Identifier) override; + +private: + std::map> LookupTable; +}; + +} // namespace include_fixer +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INMEMORYXREFSDB_H Index: include-fixer/InMemoryXrefsDB.cpp =================================================================== --- /dev/null +++ include-fixer/InMemoryXrefsDB.cpp @@ -0,0 +1,23 @@ +//===-- InMemoryXrefsDB.cpp -----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "InMemoryXrefsDB.h" + +namespace clang { +namespace include_fixer { + +std::vector InMemoryXrefsDB::search(llvm::StringRef Identifier) { + auto I = LookupTable.find(Identifier); + if (I != LookupTable.end()) + return I->second; + return {}; +} + +} // namespace include_fixer +} // namespace clang Index: include-fixer/IncludeFixer.h =================================================================== --- include-fixer/IncludeFixer.h +++ include-fixer/IncludeFixer.h @@ -10,34 +10,21 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INCLUDEFIXER_H #define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INCLUDEFIXER_H -#include "IncludeFixerContext.h" -#include "SymbolIndexManager.h" -#include "clang/Format/Format.h" +#include "XrefsDB.h" +#include "clang/Lex/PreprocessorOptions.h" #include "clang/Tooling/Core/Replacement.h" #include "clang/Tooling/Tooling.h" -#include -#include namespace clang { - -class CompilerInvocation; -class DiagnosticConsumer; -class FileManager; -class PCHContainerOperations; - namespace include_fixer { class IncludeFixerActionFactory : public clang::tooling::ToolAction { public: - /// \param SymbolIndexMgr A source for matching symbols to header files. - /// \param Context A context for the symbol being queried. - /// \param StyleName Fallback style for reformatting. - /// \param MinimizeIncludePaths whether inserted include paths are optimized. - IncludeFixerActionFactory(SymbolIndexManager &SymbolIndexMgr, - IncludeFixerContext &Context, StringRef StyleName, - bool MinimizeIncludePaths = true); - - ~IncludeFixerActionFactory() override; + /// \param Xrefs A source for matching symbols to header files. + /// \param Replacements Storage for the output of the fixer. + IncludeFixerActionFactory( + XrefsDB &Xrefs, std::vector &Replacements); + ~IncludeFixerActionFactory(); bool runInvocation(clang::CompilerInvocation *Invocation, @@ -47,33 +34,12 @@ private: /// The client to use to find cross-references. - SymbolIndexManager &SymbolIndexMgr; + XrefsDB &Xrefs; - /// The context that contains all information about the symbol being queried. - IncludeFixerContext &Context; - - /// Whether inserted include paths should be optimized. - bool MinimizeIncludePaths; - - /// The fallback format style for formatting after insertion if no - /// clang-format config file was found. - std::string FallbackStyle; + /// Replacements are written here. + std::vector &Replacements; }; -/// Create replacements, which are generated by clang-format, for the header -/// insertion. -/// -/// \param Code The source code. -/// \param FilePath The source file path. -/// \param Header The header being inserted. -/// \param Style clang-format style being used. -/// -/// \return Replacements for inserting and sorting headers on success; -/// otherwise, an llvm::Error carrying llvm::StringError is returned. -llvm::Expected createInsertHeaderReplacements( - StringRef Code, StringRef FilePath, StringRef Header, - const clang::format::FormatStyle &Style = clang::format::getLLVMStyle()); - } // namespace include_fixer } // namespace clang Index: include-fixer/IncludeFixer.cpp =================================================================== --- include-fixer/IncludeFixer.cpp +++ include-fixer/IncludeFixer.cpp @@ -8,11 +8,11 @@ //===----------------------------------------------------------------------===// #include "IncludeFixer.h" -#include "clang/Format/Format.h" #include "clang/Frontend/CompilerInstance.h" -#include "clang/Lex/HeaderSearch.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Lex/Preprocessor.h" #include "clang/Parse/ParseAST.h" +#include "clang/Rewrite/Core/Rewriter.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/Sema.h" #include "llvm/Support/Debug.h" @@ -26,18 +26,47 @@ namespace include_fixer { namespace { +class Action; + +class PreprocessorHooks : public clang::PPCallbacks { +public: + explicit PreprocessorHooks(Action *EnclosingPass) + : EnclosingPass(EnclosingPass), TrackedFile(nullptr) {} + + void FileChanged(clang::SourceLocation loc, + clang::PPCallbacks::FileChangeReason reason, + clang::SrcMgr::CharacteristicKind file_type, + clang::FileID prev_fid) override; + + void InclusionDirective(clang::SourceLocation HashLocation, + const clang::Token &IncludeToken, + llvm::StringRef FileName, bool IsAngled, + clang::CharSourceRange FileNameRange, + const clang::FileEntry *IncludeFile, + llvm::StringRef SearchPath, + llvm::StringRef relative_path, + const clang::Module *imported) override; + +private: + /// The current Action. + Action *EnclosingPass; + + /// The current FileEntry. + const clang::FileEntry *TrackedFile; +}; + /// Manages the parse, gathers include suggestions. class Action : public clang::ASTFrontendAction, public clang::ExternalSemaSource { public: - explicit Action(SymbolIndexManager &SymbolIndexMgr, bool MinimizeIncludePaths) - : SymbolIndexMgr(SymbolIndexMgr), - MinimizeIncludePaths(MinimizeIncludePaths) {} + explicit Action(XrefsDB &Xrefs) : Xrefs(Xrefs) {} std::unique_ptr CreateASTConsumer(clang::CompilerInstance &Compiler, StringRef InFile) override { Filename = InFile; + Compiler.getPreprocessor().addPPCallbacks( + llvm::make_unique(this)); return llvm::make_unique(); } @@ -65,16 +94,8 @@ /// have the fully qualified name ready. Just query that. bool MaybeDiagnoseMissingCompleteType(clang::SourceLocation Loc, clang::QualType T) override { - // Ignore spurious callbacks from SFINAE contexts. - if (getCompilerInstance().getSema().isSFINAEContext()) - return false; - clang::ASTContext &context = getCompilerInstance().getASTContext(); - std::string QueryString = - T.getUnqualifiedType().getAsString(context.getPrintingPolicy()); - DEBUG(llvm::dbgs() << "Query missing complete type '" << QueryString - << "'"); - query(QueryString, "", tooling::Range()); + query(T.getUnqualifiedType().getAsString(context.getPrintingPolicy())); return false; } @@ -86,230 +107,172 @@ DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT) override { - // Ignore spurious callbacks from SFINAE contexts. - if (getCompilerInstance().getSema().isSFINAEContext()) - return clang::TypoCorrection(); - - // We currently ignore the unidentified symbol which is not from the - // main file. - // - // However, this is not always true due to templates in a non-self contained - // header, consider the case: - // - // // header.h - // template - // class Foo { - // T t; - // }; - // - // // test.cc - // // We need to add in test.cc instead of header.h. - // class Bar; - // Foo foo; - // - // FIXME: Add the missing header to the header file where the symbol comes - // from. - if (!getCompilerInstance().getSourceManager().isWrittenInMainFile( - Typo.getLoc())) + // We don't want to look up inner parts of nested name specifies. Looking up + // the header where a namespace is defined in is rarely useful. + if (LookupKind == clang::Sema::LookupNestedNameSpecifierName) { + DEBUG(llvm::dbgs() << "ignoring " << Typo.getAsString() << "\n"); return clang::TypoCorrection(); - - std::string TypoScopeString; - if (S) { - // FIXME: Currently we only use namespace contexts. Use other context - // types for query. - for (const auto *Context = S->getEntity(); Context; - Context = Context->getParent()) { - if (const auto *ND = dyn_cast(Context)) { - if (!ND->getName().empty()) - TypoScopeString = ND->getNameAsString() + "::" + TypoScopeString; - } - } } - auto ExtendNestedNameSpecifier = [this](CharSourceRange Range) { - StringRef Source = - Lexer::getSourceText(Range, getCompilerInstance().getSourceManager(), - getCompilerInstance().getLangOpts()); - - // Skip forward until we find a character that's neither identifier nor - // colon. This is a bit of a hack around the fact that we will only get a - // single callback for a long nested name if a part of the beginning is - // unknown. For example: - // - // llvm::sys::path::parent_path(...) - // ^~~~ ^~~ - // known - // ^~~~ - // unknown, last callback - // ^~~~~~~~~~~ - // no callback - // - // With the extension we get the full nested name specifier including - // parent_path. - // FIXME: Don't rely on source text. - const char *End = Source.end(); - while (isIdentifierBody(*End) || *End == ':') - ++End; - - return std::string(Source.begin(), End); - }; - /// If we have a scope specification, use that to get more precise results. std::string QueryString; - tooling::Range SymbolRange; - const auto &SM = getCompilerInstance().getSourceManager(); - auto CreateToolingRange = [&QueryString, &SM](SourceLocation BeginLoc) { - return tooling::Range(SM.getDecomposedLoc(BeginLoc).second, - QueryString.size()); - }; if (SS && SS->getRange().isValid()) { auto Range = CharSourceRange::getTokenRange(SS->getRange().getBegin(), Typo.getLoc()); - - QueryString = ExtendNestedNameSpecifier(Range); - SymbolRange = CreateToolingRange(Range.getBegin()); - } else if (Typo.getName().isIdentifier() && !Typo.getLoc().isMacroID()) { - auto Range = - CharSourceRange::getTokenRange(Typo.getBeginLoc(), Typo.getEndLoc()); - - QueryString = ExtendNestedNameSpecifier(Range); - SymbolRange = CreateToolingRange(Range.getBegin()); + QueryString = + Lexer::getSourceText(Range, getCompilerInstance().getSourceManager(), + getCompilerInstance().getLangOpts()); } else { QueryString = Typo.getAsString(); - SymbolRange = CreateToolingRange(Typo.getLoc()); } - DEBUG(llvm::dbgs() << "TypoScopeQualifiers: " << TypoScopeString << "\n"); - query(QueryString, TypoScopeString, SymbolRange); - - // FIXME: We should just return the name we got as input here and prevent - // clang from trying to correct the typo by itself. That may change the - // identifier to something that's not wanted by the user. - return clang::TypoCorrection(); + return query(QueryString); } StringRef filename() const { return Filename; } - /// Get the minimal include for a given path. - std::string minimizeInclude(StringRef Include, - const clang::SourceManager &SourceManager, - clang::HeaderSearch &HeaderSearch) { - if (!MinimizeIncludePaths) - return Include; - - // Get the FileEntry for the include. - StringRef StrippedInclude = Include.trim("\"<>"); - const FileEntry *Entry = - SourceManager.getFileManager().getFile(StrippedInclude); + /// Called for each include file we discover is in the file. + /// \param SourceManager the active SourceManager + /// \param canonical_path the canonical path to the include file + /// \param uttered_path the path as it appeared in the program + /// \param IsAngled whether angle brackets were used + /// \param HashLocation the source location of the include's \# + /// \param EndLocation the source location following the include + void NextInclude(clang::SourceManager *SourceManager, + llvm::StringRef canonical_path, llvm::StringRef uttered_path, + bool IsAngled, clang::SourceLocation HashLocation, + clang::SourceLocation EndLocation) { + unsigned Offset = SourceManager->getFileOffset(HashLocation); + if (FirstIncludeOffset == -1U) + FirstIncludeOffset = Offset; + } - // If the file doesn't exist return the path from the database. - // FIXME: This should never happen. - if (!Entry) - return Include; + /// Generate replacements for the suggested includes. + /// \return true if changes will be made, false otherwise. + bool Rewrite(clang::SourceManager &SourceManager, + std::vector &replacements) { + for (const auto &ToTry : Untried) { + DEBUG(llvm::dbgs() << "Adding include " << ToTry << "\n"); + std::string ToAdd = "#include " + ToTry + "\n"; + + if (FirstIncludeOffset == -1U) + FirstIncludeOffset = 0; + + replacements.push_back(clang::tooling::Replacement( + SourceManager, FileBegin.getLocWithOffset(FirstIncludeOffset), 0, + ToAdd)); + + // We currently abort after the first inserted include. The more + // includes we have the less safe this becomes due to error recovery + // changing the results. + // FIXME: Handle multiple includes at once. + return true; + } + return false; + } - bool IsSystem; - std::string Suggestion = - HeaderSearch.suggestPathToFileForDiagnostics(Entry, &IsSystem); + /// Gets the location at the very top of the file. + clang::SourceLocation file_begin() const { return FileBegin; } - return IsSystem ? '<' + Suggestion + '>' : '"' + Suggestion + '"'; - } + /// Sets the location at the very top of the file. + void setFileBegin(clang::SourceLocation Location) { FileBegin = Location; } - /// Get the include fixer context for the queried symbol. - IncludeFixerContext - getIncludeFixerContext(const clang::SourceManager &SourceManager, - clang::HeaderSearch &HeaderSearch) { - std::vector SymbolCandidates; - for (const auto &Symbol : MatchedSymbols) { - std::string FilePath = Symbol.getFilePath().str(); - std::string MinimizedFilePath = minimizeInclude( - ((FilePath[0] == '"' || FilePath[0] == '<') ? FilePath - : "\"" + FilePath + "\""), - SourceManager, HeaderSearch); - SymbolCandidates.emplace_back(Symbol.getName(), Symbol.getSymbolKind(), - MinimizedFilePath, Symbol.getLineNumber(), - Symbol.getContexts(), - Symbol.getNumOccurrences()); - } - return IncludeFixerContext(QuerySymbol, SymbolScopedQualifiers, - SymbolCandidates, QuerySymbolRange); + /// Add an include to the set of includes to try. + /// \param include_path The include path to try. + void TryInclude(const std::string &query, const std::string &include_path) { + Untried.insert(include_path); } private: /// Query the database for a given identifier. - bool query(StringRef Query, StringRef ScopedQualifiers, tooling::Range Range) { + clang::TypoCorrection query(StringRef Query) { assert(!Query.empty() && "Empty query!"); - // Skip other identifiers once we have discovered an identfier successfully. - if (!MatchedSymbols.empty()) - return false; - - DEBUG(llvm::dbgs() << "Looking up '" << Query << "' at "); - DEBUG(getCompilerInstance() - .getSourceManager() - .getLocForStartOfFile( - getCompilerInstance().getSourceManager().getMainFileID()) - .getLocWithOffset(Range.getOffset()) - .print(llvm::dbgs(), getCompilerInstance().getSourceManager())); - DEBUG(llvm::dbgs() << " ..."); - - QuerySymbol = Query.str(); - QuerySymbolRange = Range; - SymbolScopedQualifiers = ScopedQualifiers; - - // Query the symbol based on C++ name Lookup rules. - // Firstly, lookup the identifier with scoped namespace contexts; - // If that fails, falls back to look up the identifier directly. - // - // For example: - // - // namespace a { - // b::foo f; - // } - // - // 1. lookup a::b::foo. - // 2. lookup b::foo. - std::string QueryString = ScopedQualifiers.str() + Query.str(); - MatchedSymbols = SymbolIndexMgr.search(QueryString); - if (MatchedSymbols.empty() && !ScopedQualifiers.empty()) - MatchedSymbols = SymbolIndexMgr.search(Query); - DEBUG(llvm::dbgs() << "Having found " << MatchedSymbols.size() - << " symbols\n"); - return !MatchedSymbols.empty(); + // Save database lookups by not looking up identifiers multiple times. + if (!SeenQueries.insert(Query).second) + return clang::TypoCorrection(); + + DEBUG(llvm::dbgs() << "Looking up " << Query << " ... "); + + std::string error_text; + auto SearchReply = Xrefs.search(Query); + DEBUG(llvm::dbgs() << SearchReply.size() << " replies\n"); + if (SearchReply.empty()) + return clang::TypoCorrection(); + + // Add those files to the set of includes to try out. + // FIXME: Rank the results and pick the best one instead of the first one. + TryInclude(Query, SearchReply[0]); + + // FIXME: We should just return the name we got as input here and prevent + // clang from trying to correct the typo by itself. That may change the + // identifier to something that's not wanted by the user. + return clang::TypoCorrection(); } /// The client to use to find cross-references. - SymbolIndexManager &SymbolIndexMgr; + XrefsDB &Xrefs; + + // Remeber things we looked up to avoid querying things twice. + llvm::StringSet<> SeenQueries; /// The absolute path to the file being processed. std::string Filename; - /// The symbol being queried. - std::string QuerySymbol; + /// The location of the beginning of the tracked file. + clang::SourceLocation FileBegin; - /// The scoped qualifiers of QuerySymbol. It is represented as a sequence of - /// names and scope resolution operatiors ::, ending with a scope resolution - /// operator (e.g. a::b::). Empty if the symbol is not in a specific scope. - std::string SymbolScopedQualifiers; + /// The offset of the last include in the original source file. This will + /// be used as the insertion point for new include directives. + unsigned FirstIncludeOffset = -1U; - /// The replacement range of the first discovered QuerySymbol. - tooling::Range QuerySymbolRange; + /// Includes we have left to try. + std::set Untried; +}; - /// All symbol candidates which match QuerySymbol. We only include the first - /// discovered identifier to avoid getting caught in results from error - /// recovery. - std::vector MatchedSymbols; +void PreprocessorHooks::FileChanged(clang::SourceLocation Loc, + clang::PPCallbacks::FileChangeReason Reason, + clang::SrcMgr::CharacteristicKind FileType, + clang::FileID PrevFID) { + // Remember where the main file starts. + if (Reason == clang::PPCallbacks::EnterFile) { + clang::SourceManager *SourceManager = + &EnclosingPass->getCompilerInstance().getSourceManager(); + clang::FileID loc_id = SourceManager->getFileID(Loc); + if (const clang::FileEntry *FileEntry = + SourceManager->getFileEntryForID(loc_id)) { + if (FileEntry->getName() == EnclosingPass->filename()) { + EnclosingPass->setFileBegin(Loc); + TrackedFile = FileEntry; + } + } + } +} - /// Whether we should use the smallest possible include path. - bool MinimizeIncludePaths = true; -}; +void PreprocessorHooks::InclusionDirective( + clang::SourceLocation HashLocation, const clang::Token &IncludeToken, + llvm::StringRef FileName, bool IsAngled, + clang::CharSourceRange FileNameRange, const clang::FileEntry *IncludeFile, + llvm::StringRef SearchPath, llvm::StringRef relative_path, + const clang::Module *imported) { + // Remember include locations so we can insert our new include at the end of + // the include block. + clang::SourceManager *SourceManager = + &EnclosingPass->getCompilerInstance().getSourceManager(); + auto IDPosition = SourceManager->getDecomposedExpansionLoc(HashLocation); + const FileEntry *SourceFile = + SourceManager->getFileEntryForID(IDPosition.first); + if (!IncludeFile || TrackedFile != SourceFile) + return; + EnclosingPass->NextInclude(SourceManager, IncludeFile->getName(), FileName, + IsAngled, HashLocation, FileNameRange.getEnd()); +} } // namespace IncludeFixerActionFactory::IncludeFixerActionFactory( - SymbolIndexManager &SymbolIndexMgr, IncludeFixerContext &Context, - StringRef StyleName, bool MinimizeIncludePaths) - : SymbolIndexMgr(SymbolIndexMgr), Context(Context), - MinimizeIncludePaths(MinimizeIncludePaths) {} + XrefsDB &Xrefs, std::vector &Replacements) + : Xrefs(Xrefs), Replacements(Replacements) {} IncludeFixerActionFactory::~IncludeFixerActionFactory() = default; @@ -330,40 +293,16 @@ /*ShouldOwnClient=*/true); Compiler.createSourceManager(*Files); - // We abort on fatal errors so don't let a large number of errors become - // fatal. A missing #include can cause thousands of errors. - Compiler.getDiagnostics().setErrorLimit(0); - // Run the parser, gather missing includes. - auto ScopedToolAction = - llvm::make_unique(SymbolIndexMgr, MinimizeIncludePaths); + auto ScopedToolAction = llvm::make_unique(Xrefs); Compiler.ExecuteAction(*ScopedToolAction); - Context = ScopedToolAction->getIncludeFixerContext( - Compiler.getSourceManager(), - Compiler.getPreprocessor().getHeaderSearchInfo()); + // Generate replacements. + ScopedToolAction->Rewrite(Compiler.getSourceManager(), Replacements); // Technically this should only return true if we're sure that we have a - // parseable file. We don't know that though. Only inform users of fatal - // errors. - return !Compiler.getDiagnostics().hasFatalErrorOccurred(); -} - -llvm::Expected -createInsertHeaderReplacements(StringRef Code, StringRef FilePath, - StringRef Header, - const clang::format::FormatStyle &Style) { - if (Header.empty()) - return tooling::Replacements(); - std::string IncludeName = "#include " + Header.str() + "\n"; - // Create replacements for the new header. - clang::tooling::Replacements Insertions = { - tooling::Replacement(FilePath, UINT_MAX, 0, IncludeName)}; - - auto CleanReplaces = cleanupAroundReplacements(Code, Insertions, Style); - if (!CleanReplaces) - return CleanReplaces; - return formatReplacements(Code, *CleanReplaces, Style); + // parseable file. We don't know that though. + return true; } } // namespace include_fixer Index: include-fixer/IncludeFixerContext.h =================================================================== --- include-fixer/IncludeFixerContext.h +++ /dev/null @@ -1,75 +0,0 @@ -//===-- IncludeFixerContext.h - Include fixer context -----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INCLUDEFIXERCONTEXT_H -#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INCLUDEFIXERCONTEXT_H - -#include "find-all-symbols/SymbolInfo.h" -#include "clang/Tooling/Core/Replacement.h" -#include -#include - -namespace clang { -namespace include_fixer { - -/// \brief A context for the symbol being queried. -class IncludeFixerContext { -public: - IncludeFixerContext() = default; - IncludeFixerContext(llvm::StringRef Name, llvm::StringRef ScopeQualifiers, - const std::vector Symbols, - tooling::Range Range); - - /// \brief Create a replacement for adding missing namespace qualifiers to the - /// symbol. - tooling::Replacement createSymbolReplacement(llvm::StringRef FilePath, - size_t Idx = 0); - - /// \brief Get symbol name. - llvm::StringRef getSymbolIdentifier() const { return SymbolIdentifier; } - - /// \brief Get replacement range of the symbol. - tooling::Range getSymbolRange() const { return SymbolRange; } - - /// \brief Get all matched symbols. - const std::vector &getMatchedSymbols() const { - return MatchedSymbols; - } - - /// \brief Get all headers. The headers are sorted in a descending order based - /// on the popularity info in SymbolInfo. - const std::vector &getHeaders() const { return Headers; } - -private: - friend struct llvm::yaml::MappingTraits; - - /// \brief The symbol name. - std::string SymbolIdentifier; - - /// \brief The qualifiers of the scope in which SymbolIdentifier lookup - /// occurs. It is represented as a sequence of names and scope resolution - /// operatiors ::, ending with a scope resolution operator (e.g. a::b::). - /// Empty if SymbolIdentifier is not in a specific scope. - std::string SymbolScopedQualifiers; - - /// \brief The headers which have SymbolIdentifier definitions. - std::vector Headers; - - /// \brief The symbol candidates which match SymbolIdentifier. The symbols are - /// sorted in a descending order based on the popularity info in SymbolInfo. - std::vector MatchedSymbols; - - /// \brief The replacement range of SymbolIdentifier. - tooling::Range SymbolRange; -}; - -} // namespace include_fixer -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INCLUDEFIXERCONTEXT_H Index: include-fixer/IncludeFixerContext.cpp =================================================================== --- include-fixer/IncludeFixerContext.cpp +++ /dev/null @@ -1,65 +0,0 @@ -//===-- IncludeFixerContext.cpp - Include fixer context ---------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "IncludeFixerContext.h" -#include - -namespace clang { -namespace include_fixer { - -IncludeFixerContext::IncludeFixerContext( - llvm::StringRef Name, llvm::StringRef ScopeQualifiers, - const std::vector Symbols, - tooling::Range Range) - : SymbolIdentifier(Name), SymbolScopedQualifiers(ScopeQualifiers), - MatchedSymbols(Symbols), SymbolRange(Range) { - // Deduplicate headers, so that we don't want to suggest the same header - // twice. - for (const auto &Symbol : MatchedSymbols) - Headers.push_back(Symbol.getFilePath()); - Headers.erase(std::unique(Headers.begin(), Headers.end(), - [](const std::string &A, const std::string &B) { - return A == B; - }), - Headers.end()); -} - -tooling::Replacement -IncludeFixerContext::createSymbolReplacement(llvm::StringRef FilePath, - size_t Idx) { - assert(Idx < MatchedSymbols.size()); - // No need to add missing qualifiers if SymbolIndentifer has a global scope - // operator "::". - if (getSymbolIdentifier().startswith("::")) - return tooling::Replacement(); - std::string QualifiedName = MatchedSymbols[Idx].getQualifiedName(); - // For nested classes, the qualified name constructed from database misses - // some stripped qualifiers, because when we search a symbol in database, - // we strip qualifiers from the end until we find a result. So append the - // missing stripped qualifiers here. - // - // Get stripped qualifiers. - llvm::SmallVector SymbolQualifiers; - getSymbolIdentifier().split(SymbolQualifiers, "::"); - std::string StrippedQualifiers; - while (!SymbolQualifiers.empty() && - !llvm::StringRef(QualifiedName).endswith(SymbolQualifiers.back())) { - StrippedQualifiers = "::" + SymbolQualifiers.back().str(); - SymbolQualifiers.pop_back(); - } - // Append the missing stripped qualifiers. - std::string FullyQualifiedName = QualifiedName + StrippedQualifiers; - auto pos = FullyQualifiedName.find(SymbolScopedQualifiers); - return {FilePath, SymbolRange.getOffset(), SymbolRange.getLength(), - FullyQualifiedName.substr( - pos == std::string::npos ? 0 : SymbolScopedQualifiers.size())}; -} - -} // include_fixer -} // clang Index: include-fixer/SymbolIndex.h =================================================================== --- include-fixer/SymbolIndex.h +++ /dev/null @@ -1,38 +0,0 @@ -//===-- SymbolIndex.h - Interface for symbol-header matching ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_SYMBOLINDEX_H -#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_SYMBOLINDEX_H - -#include "find-all-symbols/SymbolInfo.h" -#include "llvm/ADT/StringRef.h" -#include - -namespace clang { -namespace include_fixer { - -/// This class provides an interface for finding all `SymbolInfo`s corresponding -/// to a symbol name from a symbol database. -class SymbolIndex { -public: - virtual ~SymbolIndex() = default; - - /// Search for all `SymbolInfo`s corresponding to an identifier. - /// \param Identifier The unqualified identifier being searched for. - /// \returns A list of `SymbolInfo` candidates. - // FIXME: Expose the type name so we can also insert using declarations (or - // fix the usage) - virtual std::vector - search(llvm::StringRef Identifier) = 0; -}; - -} // namespace include_fixer -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_SYMBOLINDEX_H Index: include-fixer/SymbolIndexManager.h =================================================================== --- include-fixer/SymbolIndexManager.h +++ /dev/null @@ -1,45 +0,0 @@ -//===-- SymbolIndexManager.h - Managing multiple SymbolIndices --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_SYMBOLINDEXMANAGER_H -#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_SYMBOLINDEXMANAGER_H - -#include "SymbolIndex.h" -#include "find-all-symbols/SymbolInfo.h" -#include "llvm/ADT/StringRef.h" - -namespace clang { -namespace include_fixer { - -/// This class provides an interface for finding the header files corresponding -/// to an indentifier in the source code from multiple symbol databases. -class SymbolIndexManager { -public: - void addSymbolIndex(std::unique_ptr DB) { - SymbolIndices.push_back(std::move(DB)); - } - - /// Search for header files to be included for an identifier. - /// \param Identifier The identifier being searched for. May or may not be - /// fully qualified. - /// \returns A list of inclusion candidates, in a format ready for being - /// pasted after an #include token. - // FIXME: Move mapping from SymbolInfo to headers out of - // SymbolIndexManager::search and return SymbolInfos instead of header paths. - std::vector - search(llvm::StringRef Identifier) const; - -private: - std::vector> SymbolIndices; -}; - -} // namespace include_fixer -} // namespace clang - -#endif Index: include-fixer/SymbolIndexManager.cpp =================================================================== --- include-fixer/SymbolIndexManager.cpp +++ /dev/null @@ -1,126 +0,0 @@ -//===-- SymbolIndexManager.cpp - Managing multiple SymbolIndices-*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "SymbolIndexManager.h" -#include "find-all-symbols/SymbolInfo.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/Debug.h" - -#define DEBUG_TYPE "include-fixer" - -namespace clang { -namespace include_fixer { - -using clang::find_all_symbols::SymbolInfo; - -/// Sorts SymbolInfos based on the popularity info in SymbolInfo. -static void rankByPopularity(std::vector &Symbols) { - // First collect occurrences per header file. - llvm::DenseMap HeaderPopularity; - for (const SymbolInfo &Symbol : Symbols) { - unsigned &Popularity = HeaderPopularity[Symbol.getFilePath()]; - Popularity = std::max(Popularity, Symbol.getNumOccurrences()); - } - - // Sort by the gathered popularities. Use file name as a tie breaker so we can - // deduplicate. - std::sort(Symbols.begin(), Symbols.end(), - [&](const SymbolInfo &A, const SymbolInfo &B) { - auto APop = HeaderPopularity[A.getFilePath()]; - auto BPop = HeaderPopularity[B.getFilePath()]; - if (APop != BPop) - return APop > BPop; - return A.getFilePath() < B.getFilePath(); - }); -} - -std::vector -SymbolIndexManager::search(llvm::StringRef Identifier) const { - // The identifier may be fully qualified, so split it and get all the context - // names. - llvm::SmallVector Names; - Identifier.split(Names, "::"); - - bool IsFullyQualified = false; - if (Identifier.startswith("::")) { - Names.erase(Names.begin()); // Drop first (empty) element. - IsFullyQualified = true; - } - - // As long as we don't find a result keep stripping name parts from the end. - // This is to support nested classes which aren't recorded in the database. - // Eventually we will either hit a class (namespaces aren't in the database - // either) and can report that result. - bool TookPrefix = false; - std::vector MatchedSymbols; - while (MatchedSymbols.empty() && !Names.empty()) { - std::vector Symbols; - for (const auto &DB : SymbolIndices) { - auto Res = DB->search(Names.back().str()); - Symbols.insert(Symbols.end(), Res.begin(), Res.end()); - } - - DEBUG(llvm::dbgs() << "Searching " << Names.back() << "... got " - << Symbols.size() << " results...\n"); - - for (const auto &Symbol : Symbols) { - // Match the identifier name without qualifier. - if (Symbol.getName() == Names.back()) { - bool IsMatched = true; - auto SymbolContext = Symbol.getContexts().begin(); - auto IdentiferContext = Names.rbegin() + 1; // Skip identifier name. - // Match the remaining context names. - while (IdentiferContext != Names.rend() && - SymbolContext != Symbol.getContexts().end()) { - if (SymbolContext->second == *IdentiferContext) { - ++IdentiferContext; - ++SymbolContext; - } else if (SymbolContext->first == - find_all_symbols::SymbolInfo::ContextType::EnumDecl) { - // Skip non-scoped enum context. - ++SymbolContext; - } else { - IsMatched = false; - break; - } - } - - // If the name was qualified we only want to add results if we evaluated - // all contexts. - if (IsFullyQualified) - IsMatched &= (SymbolContext == Symbol.getContexts().end()); - - // FIXME: Support full match. At this point, we only find symbols in - // database which end with the same contexts with the identifier. - if (IsMatched && IdentiferContext == Names.rend()) { - // If we're in a situation where we took a prefix but the thing we - // found couldn't possibly have a nested member ignore it. - if (TookPrefix && - (Symbol.getSymbolKind() == SymbolInfo::SymbolKind::Function || - Symbol.getSymbolKind() == SymbolInfo::SymbolKind::Variable || - Symbol.getSymbolKind() == - SymbolInfo::SymbolKind::EnumConstantDecl || - Symbol.getSymbolKind() == SymbolInfo::SymbolKind::Macro)) - continue; - - MatchedSymbols.push_back(Symbol); - } - } - } - Names.pop_back(); - TookPrefix = true; - } - - rankByPopularity(MatchedSymbols); - return MatchedSymbols; -} - -} // namespace include_fixer -} // namespace clang Index: include-fixer/XrefsDB.h =================================================================== --- /dev/null +++ include-fixer/XrefsDB.h @@ -0,0 +1,38 @@ +//===-- XrefsDB.h - Interface for symbol-header matching --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_XREFSDB_H +#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_XREFSDB_H + +#include "llvm/ADT/StringRef.h" +#include + +namespace clang { +namespace include_fixer { + +/// This class provides an interface for finding the header files corresponding +/// to an indentifier in the source code. +class XrefsDB { +public: + virtual ~XrefsDB() = default; + + /// Search for header files to be included for an identifier. + /// \param Identifier The identifier being searched for. May or may not be + /// fully qualified. + /// \returns A list of inclusion candidates, in a format ready for being + /// pasted after an #include token. + // FIXME: Expose the type name so we can also insert using declarations (or + // fix the usage) + virtual std::vector search(llvm::StringRef Identifier) = 0; +}; + +} // namespace include_fixer +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_XREFSDB_H Index: include-fixer/YamlSymbolIndex.h =================================================================== --- include-fixer/YamlSymbolIndex.h +++ /dev/null @@ -1,46 +0,0 @@ -//===-- YamlSymbolIndex.h ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_YAMLSYMBOLINDEX_H -#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_YAMLSYMBOLINDEX_H - -#include "SymbolIndex.h" -#include "find-all-symbols/SymbolInfo.h" -#include "llvm/Support/ErrorOr.h" -#include -#include - -namespace clang { -namespace include_fixer { - -/// Yaml format database. -class YamlSymbolIndex : public SymbolIndex { -public: - /// Create a new Yaml db from a file. - static llvm::ErrorOr> - createFromFile(llvm::StringRef FilePath); - /// Look for a file called \c Name in \c Directory and all parent directories. - static llvm::ErrorOr> - createFromDirectory(llvm::StringRef Directory, llvm::StringRef Name); - - std::vector - search(llvm::StringRef Identifier) override; - -private: - explicit YamlSymbolIndex( - std::vector Symbols) - : Symbols(std::move(Symbols)) {} - - std::vector Symbols; -}; - -} // namespace include_fixer -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_YAMLSYMBOLINDEX_H Index: include-fixer/YamlSymbolIndex.cpp =================================================================== --- include-fixer/YamlSymbolIndex.cpp +++ /dev/null @@ -1,60 +0,0 @@ -//===-- YamlSymbolIndex.cpp -----------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "YamlSymbolIndex.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include -#include - -using clang::find_all_symbols::SymbolInfo; - -namespace clang { -namespace include_fixer { - -llvm::ErrorOr> -YamlSymbolIndex::createFromFile(llvm::StringRef FilePath) { - auto Buffer = llvm::MemoryBuffer::getFile(FilePath); - if (!Buffer) - return Buffer.getError(); - - return std::unique_ptr( - new YamlSymbolIndex(clang::find_all_symbols::ReadSymbolInfosFromYAML( - Buffer.get()->getBuffer()))); -} - -llvm::ErrorOr> -YamlSymbolIndex::createFromDirectory(llvm::StringRef Directory, - llvm::StringRef Name) { - // Walk upwards from Directory, looking for files. - for (llvm::SmallString<128> PathStorage = Directory; !Directory.empty(); - Directory = llvm::sys::path::parent_path(Directory)) { - assert(Directory.size() <= PathStorage.size()); - PathStorage.resize(Directory.size()); // Shrink to parent. - llvm::sys::path::append(PathStorage, Name); - if (auto DB = createFromFile(PathStorage)) - return DB; - } - return llvm::make_error_code(llvm::errc::no_such_file_or_directory); -} - -std::vector YamlSymbolIndex::search(llvm::StringRef Identifier) { - std::vector Results; - for (const auto &Symbol : Symbols) { - if (Symbol.getName() == Identifier) - Results.push_back(Symbol); - } - return Results; -} - -} // namespace include_fixer -} // namespace clang Index: include-fixer/find-all-symbols/CMakeLists.txt =================================================================== --- include-fixer/find-all-symbols/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -set(LLVM_LINK_COMPONENTS - Support - ) - -add_clang_library(findAllSymbols - FindAllSymbols.cpp - FindAllSymbolsAction.cpp - FindAllMacros.cpp - HeaderMapCollector.cpp - PathConfig.cpp - PragmaCommentHandler.cpp - STLPostfixHeaderMap.cpp - SymbolInfo.cpp - - LINK_LIBS - clangAST - clangASTMatchers - clangBasic - clangFrontend - clangLex - clangTooling - ) - -add_subdirectory(tool) Index: include-fixer/find-all-symbols/FindAllMacros.h =================================================================== --- include-fixer/find-all-symbols/FindAllMacros.h +++ /dev/null @@ -1,47 +0,0 @@ -//===-- FindAllMacros.h - find all macros -----------------------*- C++ -*-===// -// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_MACROS_H -#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_MACROS_H - -#include "SymbolInfo.h" -#include "SymbolReporter.h" -#include "clang/Lex/PPCallbacks.h" - -namespace clang { -namespace find_all_symbols { - -class HeaderMapCollector; - -/// \brief A preprocessor that collects all macro symbols. -/// The contexts of a macro will be ignored since they are not available during -/// preprocessing period. -class FindAllMacros : public clang::PPCallbacks { -public: - explicit FindAllMacros(SymbolReporter *Reporter, SourceManager *SM, - HeaderMapCollector *Collector = nullptr) - : Reporter(Reporter), SM(SM), Collector(Collector) {} - - void MacroDefined(const Token &MacroNameTok, - const MacroDirective *MD) override; - -private: - // Reporter for SymbolInfo. - SymbolReporter *const Reporter; - SourceManager *const SM; - // A remapping header file collector allowing clients to include a different - // header. - HeaderMapCollector *const Collector; -}; - -} // namespace find_all_symbols -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_MACROS_H Index: include-fixer/find-all-symbols/FindAllMacros.cpp =================================================================== --- include-fixer/find-all-symbols/FindAllMacros.cpp +++ /dev/null @@ -1,37 +0,0 @@ -//===-- FindAllMacros.cpp - find all macros ---------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "FindAllMacros.h" -#include "HeaderMapCollector.h" -#include "PathConfig.h" -#include "SymbolInfo.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Lex/Token.h" -#include "llvm/Support/Path.h" - -namespace clang { -namespace find_all_symbols { - -void FindAllMacros::MacroDefined(const Token &MacroNameTok, - const MacroDirective *MD) { - SourceLocation Loc = SM->getExpansionLoc(MacroNameTok.getLocation()); - std::string FilePath = getIncludePath(*SM, Loc, Collector); - if (FilePath.empty()) return; - - SymbolInfo Symbol(MacroNameTok.getIdentifierInfo()->getName(), - SymbolInfo::SymbolKind::Macro, FilePath, - SM->getSpellingLineNumber(Loc), {}); - - Reporter->reportSymbol(SM->getFileEntryForID(SM->getMainFileID())->getName(), - Symbol); -} - -} // namespace find_all_symbols -} // namespace clang Index: include-fixer/find-all-symbols/FindAllSymbols.h =================================================================== --- include-fixer/find-all-symbols/FindAllSymbols.h +++ /dev/null @@ -1,57 +0,0 @@ -//===-- FindAllSymbols.h - find all symbols----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_MATCHER_H -#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_MATCHER_H - -#include "SymbolInfo.h" -#include "SymbolReporter.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include - -namespace clang { -namespace find_all_symbols { - -class HeaderMapCollector; - -/// \brief FindAllSymbols collects all classes, free standing functions and -/// global variables with some extra information such as the path of the header -/// file, the namespaces they are contained in, the type of variables and the -/// parameter types of functions. -/// -/// NOTE: -/// - Symbols declared in main files are not collected since they can not be -/// included. -/// - Member functions are not collected because accessing them must go -/// through the class. #include fixer only needs the class name to find -/// headers. -/// -class FindAllSymbols : public clang::ast_matchers::MatchFinder::MatchCallback { -public: - explicit FindAllSymbols(SymbolReporter *Reporter, - HeaderMapCollector *Collector = nullptr) - : Reporter(Reporter), Collector(Collector) {} - - void registerMatchers(clang::ast_matchers::MatchFinder *MatchFinder); - - void - run(const clang::ast_matchers::MatchFinder::MatchResult &result) override; - -private: - // Reporter for SymbolInfo. - SymbolReporter *const Reporter; - // A remapping header file collector allowing clients include a different - // header. - HeaderMapCollector *const Collector; -}; - -} // namespace find_all_symbols -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_MATCHER_H Index: include-fixer/find-all-symbols/FindAllSymbols.cpp =================================================================== --- include-fixer/find-all-symbols/FindAllSymbols.cpp +++ /dev/null @@ -1,226 +0,0 @@ -//===-- FindAllSymbols.cpp - find all symbols--------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "FindAllSymbols.h" -#include "HeaderMapCollector.h" -#include "PathConfig.h" -#include "SymbolInfo.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/Type.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/ASTMatchers/ASTMatchers.h" -#include "clang/Tooling/Tooling.h" -#include "llvm/ADT/Optional.h" -#include "llvm/Support/FileSystem.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace find_all_symbols { -namespace { - -AST_MATCHER(EnumConstantDecl, isInScopedEnum) { - if (const auto *ED = dyn_cast(Node.getDeclContext())) - return ED->isScoped(); - return false; -} - -std::vector GetContexts(const NamedDecl *ND) { - std::vector Contexts; - for (const auto *Context = ND->getDeclContext(); Context; - Context = Context->getParent()) { - if (llvm::isa(Context) || - llvm::isa(Context)) - break; - - assert(llvm::isa(Context) && - "Expect Context to be a NamedDecl"); - if (const auto *NSD = dyn_cast(Context)) { - if (!NSD->isInlineNamespace()) - Contexts.emplace_back(SymbolInfo::ContextType::Namespace, - NSD->getName().str()); - } else if (const auto *ED = dyn_cast(Context)) { - Contexts.emplace_back(SymbolInfo::ContextType::EnumDecl, - ED->getName().str()); - } else { - const auto *RD = cast(Context); - Contexts.emplace_back(SymbolInfo::ContextType::Record, - RD->getName().str()); - } - } - return Contexts; -} - -llvm::Optional -CreateSymbolInfo(const NamedDecl *ND, const SourceManager &SM, - const HeaderMapCollector *Collector) { - SymbolInfo::SymbolKind Type; - if (llvm::isa(ND)) { - Type = SymbolInfo::SymbolKind::Variable; - } else if (llvm::isa(ND)) { - Type = SymbolInfo::SymbolKind::Function; - } else if (llvm::isa(ND)) { - Type = SymbolInfo::SymbolKind::TypedefName; - } else if (llvm::isa(ND)) { - Type = SymbolInfo::SymbolKind::EnumConstantDecl; - } else if (llvm::isa(ND)) { - Type = SymbolInfo::SymbolKind::EnumDecl; - // Ignore anonymous enum declarations. - if (ND->getName().empty()) - return llvm::None; - } else { - assert(llvm::isa(ND) && - "Matched decl must be one of VarDecl, " - "FunctionDecl, TypedefNameDecl, EnumConstantDecl, " - "EnumDecl and RecordDecl!"); - // C-style record decl can have empty name, e.g "struct { ... } var;". - if (ND->getName().empty()) - return llvm::None; - Type = SymbolInfo::SymbolKind::Class; - } - - SourceLocation Loc = SM.getExpansionLoc(ND->getLocation()); - if (!Loc.isValid()) { - llvm::errs() << "Declaration " << ND->getNameAsString() << "(" - << ND->getDeclKindName() - << ") has invalid declaration location."; - return llvm::None; - } - - std::string FilePath = getIncludePath(SM, Loc, Collector); - if (FilePath.empty()) return llvm::None; - - return SymbolInfo(ND->getNameAsString(), Type, FilePath, - SM.getExpansionLineNumber(Loc), GetContexts(ND)); -} - -} // namespace - -void FindAllSymbols::registerMatchers(MatchFinder *MatchFinder) { - // FIXME: Handle specialization. - auto IsInSpecialization = hasAncestor( - decl(anyOf(cxxRecordDecl(isExplicitTemplateSpecialization()), - functionDecl(isExplicitTemplateSpecialization())))); - - // Matchers for both C and C++. - // We only match symbols from header files, i.e. not from main files (see - // function's comment for detailed explanation). - auto CommonFilter = - allOf(unless(isImplicit()), unless(isExpansionInMainFile())); - - auto HasNSOrTUCtxMatcher = - hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl())); - - // We need seperate rules for C record types and C++ record types since some - // template related matchers are inapplicable on C record declarations. - // - // Matchers specific to C++ code. - // All declarations should be in namespace or translation unit. - auto CCMatcher = - allOf(HasNSOrTUCtxMatcher, unless(IsInSpecialization), - unless(ast_matchers::isTemplateInstantiation()), - unless(isInstantiated()), unless(classTemplateSpecializationDecl()), - unless(isExplicitTemplateSpecialization())); - - // Matchers specific to code in extern "C" {...}. - auto ExternCMatcher = hasDeclContext(linkageSpecDecl()); - - // Matchers for variable declarations. - // - // In most cases, `ParmVarDecl` is filtered out by hasDeclContext(...) - // matcher since the declaration context is usually `MethodDecl`. However, - // this assumption does not hold for parameters of a function pointer - // parameter. - // For example, consider a function declaration: - // void Func(void (*)(float), int); - // The float parameter of the function pointer has an empty name, and its - // declaration context is an anonymous namespace; therefore, it won't be - // filtered out by our matchers above. - MatchFinder->addMatcher(varDecl(CommonFilter, - anyOf(ExternCMatcher, CCMatcher), - unless(parmVarDecl())) - .bind("decl"), - this); - - // Matchers for C-style record declarations in extern "C" {...}. - MatchFinder->addMatcher( - recordDecl(CommonFilter, ExternCMatcher, isDefinition()).bind("decl"), - this); - - // Matchers for C++ record declarations. - auto CxxRecordDecl = - cxxRecordDecl(CommonFilter, CCMatcher, isDefinition(), - unless(isExplicitTemplateSpecialization())); - MatchFinder->addMatcher(CxxRecordDecl.bind("decl"), this); - - // Matchers for function declarations. - // We want to exclude friend declaration, but the `DeclContext` of a friend - // function declaration is not the class in which it is declared, so we need - // to explicitly check if the parent is a `friendDecl`. - MatchFinder->addMatcher(functionDecl(CommonFilter, - unless(hasParent(friendDecl())), - anyOf(ExternCMatcher, CCMatcher)) - .bind("decl"), - this); - - // Matcher for typedef and type alias declarations. - // - // typedef and type alias can come from C-style headers and C++ heaeders. - // For C-style header, `DeclContxet` can be either `TranslationUnitDecl` - // or `LinkageSpecDecl`. - // For C++ header, `DeclContext ` can be one of `TranslationUnitDecl`, - // `NamespaceDecl`. - // With the following context matcher, we can match `typedefNameDecl` from - // both C-style header and C++ header (except for those in classes). - // "cc_matchers" are not included since template-related matchers are not - // applicable on `TypedefNameDecl`. - MatchFinder->addMatcher( - typedefNameDecl(CommonFilter, anyOf(HasNSOrTUCtxMatcher, - hasDeclContext(linkageSpecDecl()))) - .bind("decl"), - this); - - // Matchers for enum declarations. - MatchFinder->addMatcher(enumDecl(CommonFilter, isDefinition(), - anyOf(HasNSOrTUCtxMatcher, ExternCMatcher)) - .bind("decl"), - this); - - // Matchers for enum constant declarations. - // We only match the enum constants in non-scoped enum declarations which are - // inside toplevel translation unit or a namespace. - MatchFinder->addMatcher( - enumConstantDecl( - CommonFilter, - unless(isInScopedEnum()), - anyOf(hasDeclContext(enumDecl(HasNSOrTUCtxMatcher)), ExternCMatcher)) - .bind("decl"), - this); -} - -void FindAllSymbols::run(const MatchFinder::MatchResult &Result) { - // Ignore Results in failing TUs. - if (Result.Context->getDiagnostics().hasErrorOccurred()) { - return; - } - - const NamedDecl *ND = Result.Nodes.getNodeAs("decl"); - assert(ND && "Matched declaration must be a NamedDecl!"); - const SourceManager *SM = Result.SourceManager; - - llvm::Optional Symbol = - CreateSymbolInfo(ND, *SM, Collector); - if (Symbol) - Reporter->reportSymbol( - SM->getFileEntryForID(SM->getMainFileID())->getName(), *Symbol); -} - -} // namespace find_all_symbols -} // namespace clang Index: include-fixer/find-all-symbols/FindAllSymbolsAction.h =================================================================== --- include-fixer/find-all-symbols/FindAllSymbolsAction.h +++ /dev/null @@ -1,61 +0,0 @@ -//===-- FindAllSymbolsAction.h - find all symbols action --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_SYMBOLS_ACTION_H -#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_SYMBOLS_ACTION_H - -#include "FindAllMacros.h" -#include "FindAllSymbols.h" -#include "HeaderMapCollector.h" -#include "PragmaCommentHandler.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Tooling/Tooling.h" - -namespace clang { -namespace find_all_symbols { - -class FindAllSymbolsAction : public clang::ASTFrontendAction { -public: - explicit FindAllSymbolsAction( - SymbolReporter *Reporter, - const HeaderMapCollector::RegexHeaderMap *RegexHeaderMap = nullptr); - - std::unique_ptr - CreateASTConsumer(clang::CompilerInstance &Compiler, - StringRef InFile) override; - -private: - SymbolReporter *const Reporter; - clang::ast_matchers::MatchFinder MatchFinder; - HeaderMapCollector Collector; - PragmaCommentHandler Handler; - FindAllSymbols Matcher; -}; - -class FindAllSymbolsActionFactory : public tooling::FrontendActionFactory { -public: - FindAllSymbolsActionFactory( - SymbolReporter *Reporter, - const HeaderMapCollector::RegexHeaderMap *RegexHeaderMap = nullptr) - : Reporter(Reporter), RegexHeaderMap(RegexHeaderMap) {} - - virtual clang::FrontendAction *create() override { - return new FindAllSymbolsAction(Reporter, RegexHeaderMap); - } - -private: - SymbolReporter *const Reporter; - const HeaderMapCollector::RegexHeaderMap *const RegexHeaderMap; -}; - -} // namespace find_all_symbols -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_SYMBOLS_ACTION_H Index: include-fixer/find-all-symbols/FindAllSymbolsAction.cpp =================================================================== --- include-fixer/find-all-symbols/FindAllSymbolsAction.cpp +++ /dev/null @@ -1,33 +0,0 @@ -//===-- FindAllSymbolsAction.cpp - find all symbols action --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "FindAllSymbolsAction.h" - -namespace clang { -namespace find_all_symbols { - -FindAllSymbolsAction::FindAllSymbolsAction( - SymbolReporter *Reporter, - const HeaderMapCollector::RegexHeaderMap *RegexHeaderMap) - : Reporter(Reporter), Collector(RegexHeaderMap), Handler(&Collector), - Matcher(Reporter, &Collector) { - Matcher.registerMatchers(&MatchFinder); -} - -std::unique_ptr -FindAllSymbolsAction::CreateASTConsumer(clang::CompilerInstance &Compiler, - StringRef InFile) { - Compiler.getPreprocessor().addCommentHandler(&Handler); - Compiler.getPreprocessor().addPPCallbacks(llvm::make_unique( - Reporter, &Compiler.getSourceManager(), &Collector)); - return MatchFinder.newASTConsumer(); -} - -} // namespace find_all_symbols -} // namespace clang Index: include-fixer/find-all-symbols/HeaderMapCollector.h =================================================================== --- include-fixer/find-all-symbols/HeaderMapCollector.h +++ /dev/null @@ -1,57 +0,0 @@ -//===-- HeaderMapCoolector.h - find all symbols------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_HEADER_MAP_COLLECTOR_H -#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_HEADER_MAP_COLLECTOR_H - -#include "llvm/ADT/StringMap.h" -#include "llvm/Support/Regex.h" -#include -#include - -namespace clang { -namespace find_all_symbols { - -/// \brief HeaderMappCollector collects all remapping header files. This maps -/// complete header names or header name regex patterns to header names. -class HeaderMapCollector { -public: - typedef llvm::StringMap HeaderMap; - typedef std::vector> RegexHeaderMap; - - HeaderMapCollector() : RegexHeaderMappingTable(nullptr) {} - - explicit HeaderMapCollector(const RegexHeaderMap *RegexHeaderMappingTable) - : RegexHeaderMappingTable(RegexHeaderMappingTable) {} - - void addHeaderMapping(llvm::StringRef OrignalHeaderPath, - llvm::StringRef MappingHeaderPath) { - HeaderMappingTable[OrignalHeaderPath] = MappingHeaderPath; - }; - - /// Check if there is a mapping from \p Header or a regex pattern that matches - /// it to another header name. - /// \param Header A header name. - /// \return \p Header itself if there is no mapping for it; otherwise, return - /// a mapped header name. - llvm::StringRef getMappedHeader(llvm::StringRef Header) const; - -private: - /// A string-to-string map saving the mapping relationship. - HeaderMap HeaderMappingTable; - - // A map from header patterns to header names. - // This is a reference to a hard-coded map. - const RegexHeaderMap *const RegexHeaderMappingTable; -}; - -} // namespace find_all_symbols -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_HEADER_MAP_COLLECTOR_H Index: include-fixer/find-all-symbols/HeaderMapCollector.cpp =================================================================== --- include-fixer/find-all-symbols/HeaderMapCollector.cpp +++ /dev/null @@ -1,33 +0,0 @@ -//===-- HeaderMapCoolector.h - find all symbols------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "HeaderMapCollector.h" -#include "llvm/Support/Regex.h" - -namespace clang { -namespace find_all_symbols { - -llvm::StringRef -HeaderMapCollector::getMappedHeader(llvm::StringRef Header) const { - auto Iter = HeaderMappingTable.find(Header); - if (Iter != HeaderMappingTable.end()) - return Iter->second; - // If there is no complete header name mapping for this header, check the - // regex header mapping. - if (RegexHeaderMappingTable) { - for (const auto &Entry : *RegexHeaderMappingTable) { - if (llvm::Regex(Entry.first).match(Header)) - return Entry.second; - } - } - return Header; -} - -} // namespace find_all_symbols -} // namespace clang Index: include-fixer/find-all-symbols/PathConfig.h =================================================================== --- include-fixer/find-all-symbols/PathConfig.h +++ /dev/null @@ -1,37 +0,0 @@ -//===-- PathConfig.h - Process paths of symbols -----------------*- C++ -*-===// -// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PATH_CONFIG_H -#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PATH_CONFIG_H - -#include "HeaderMapCollector.h" -#include "clang/Basic/SourceManager.h" -#include - -namespace clang { -namespace find_all_symbols { - -/// \brief This calculates the include path for \p Loc. -/// -/// \param SM SourceManager. -/// \param Loc A SourceLocation. -/// \param Collector An optional header mapping collector. -/// -/// \return The file path (or mapped file path if Collector is provided) of the -/// header that includes \p Loc. If \p Loc comes from .inc header file, \p Loc -/// is set to the location from which the .inc header file is included. If \p -/// Loc is invalid or comes from a main file, this returns an empty string. -std::string getIncludePath(const SourceManager &SM, SourceLocation Loc, - const HeaderMapCollector *Collector = nullptr); - -} // namespace find_all_symbols -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PATH_CONFIG_H Index: include-fixer/find-all-symbols/PathConfig.cpp =================================================================== --- include-fixer/find-all-symbols/PathConfig.cpp +++ /dev/null @@ -1,42 +0,0 @@ -//===-- PathConfig.cpp - Process paths of symbols ---------------*- C++ -*-===// -// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "PathConfig.h" -#include "llvm/Support/Path.h" - -namespace clang { -namespace find_all_symbols { - -std::string getIncludePath(const SourceManager &SM, SourceLocation Loc, - const HeaderMapCollector *Collector) { - llvm::StringRef FilePath; - // Walk up the include stack to skip .inc files. - while (true) { - if (!Loc.isValid() || SM.isInMainFile(Loc)) - return ""; - FilePath = SM.getFilename(Loc); - if (FilePath.empty()) - return ""; - if (!FilePath.endswith(".inc")) - break; - FileID ID = SM.getFileID(Loc); - Loc = SM.getIncludeLoc(ID); - } - - if (Collector) - FilePath = Collector->getMappedHeader(FilePath); - SmallString<256> CleanedFilePath = FilePath; - llvm::sys::path::remove_dots(CleanedFilePath, /*remove_dot_dot=*/false); - - return CleanedFilePath.str(); -} - -} // namespace find_all_symbols -} // namespace clang Index: include-fixer/find-all-symbols/PragmaCommentHandler.h =================================================================== --- include-fixer/find-all-symbols/PragmaCommentHandler.h +++ /dev/null @@ -1,41 +0,0 @@ -//===-- PragmaCommentHandler.h - find all symbols----------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PRAGMA_COMMENT_HANDLER_H -#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PRAGMA_COMMENT_HANDLER_H - -#include "clang/Basic/SourceLocation.h" -#include "clang/Lex/Preprocessor.h" -#include - -namespace clang { -namespace find_all_symbols { - -class HeaderMapCollector; - -/// \brief PragmaCommentHandler parses pragma comment on include files to -/// determine when we should include a different header from the header that -/// directly defines a symbol. -/// -/// Currently it only supports IWYU private pragma: -/// https://github.com/include-what-you-use/include-what-you-use/blob/master/docs/IWYUPragmas.md#iwyu-pragma-private -class PragmaCommentHandler : public clang::CommentHandler { -public: - PragmaCommentHandler(HeaderMapCollector *Collector) : Collector(Collector) {} - - bool HandleComment(Preprocessor &PP, SourceRange Range) override; - -private: - HeaderMapCollector *const Collector; -}; - -} // namespace find_all_symbols -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PRAGMA_COMMENT_HANDLER_H Index: include-fixer/find-all-symbols/PragmaCommentHandler.cpp =================================================================== --- include-fixer/find-all-symbols/PragmaCommentHandler.cpp +++ /dev/null @@ -1,37 +0,0 @@ -//===-- PragmaCommentHandler.cpp - find all symbols -----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "PragmaCommentHandler.h" -#include "FindAllSymbols.h" -#include "HeaderMapCollector.h" -#include "clang/Lex/Preprocessor.h" -#include "llvm/Support/Regex.h" - -namespace clang { -namespace find_all_symbols { -namespace { -const char IWYUPragma[] = "// IWYU pragma: private, include "; -} // namespace - -bool PragmaCommentHandler::HandleComment(Preprocessor &PP, SourceRange Range) { - StringRef Text = - Lexer::getSourceText(CharSourceRange::getCharRange(Range), - PP.getSourceManager(), PP.getLangOpts()); - size_t Pos = Text.find(IWYUPragma); - if (Pos == StringRef::npos) - return false; - StringRef RemappingFilePath = Text.substr(Pos + std::strlen(IWYUPragma)); - Collector->addHeaderMapping( - PP.getSourceManager().getFilename(Range.getBegin()), - RemappingFilePath.trim("\"<>")); - return false; -} - -} // namespace find_all_symbols -} // namespace clang Index: include-fixer/find-all-symbols/STLPostfixHeaderMap.h =================================================================== --- include-fixer/find-all-symbols/STLPostfixHeaderMap.h +++ /dev/null @@ -1,23 +0,0 @@ -//===-- STLPostfixHeaderMap.h - hardcoded header map for STL ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_TOOL_STL_POSTFIX_HEADER_MAP_H -#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_TOOL_STL_POSTFIX_HEADER_MAP_H - -#include "HeaderMapCollector.h" - -namespace clang { -namespace find_all_symbols { - -const HeaderMapCollector::RegexHeaderMap *getSTLPostfixHeaderMap(); - -} // namespace find_all_symbols -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_TOOL_STL_POSTFIX_HEADER_MAP_H Index: include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp =================================================================== --- include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp +++ /dev/null @@ -1,650 +0,0 @@ -//===-- STLPostfixHeaderMap.h - hardcoded STL header map --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "STLPostfixHeaderMap.h" - -namespace clang { -namespace find_all_symbols { - -const HeaderMapCollector::RegexHeaderMap *getSTLPostfixHeaderMap() { - static const HeaderMapCollector::RegexHeaderMap STLPostfixHeaderMap = { - {"include/__stddef_max_align_t.h$", ""}, - {"include/__wmmintrin_aes.h$", ""}, - {"include/__wmmintrin_pclmul.h$", ""}, - {"include/adxintrin.h$", ""}, - {"include/ammintrin.h$", ""}, - {"include/avx2intrin.h$", ""}, - {"include/avx512bwintrin.h$", ""}, - {"include/avx512cdintrin.h$", ""}, - {"include/avx512dqintrin.h$", ""}, - {"include/avx512erintrin.h$", ""}, - {"include/avx512fintrin.h$", ""}, - {"include/avx512ifmaintrin.h$", ""}, - {"include/avx512ifmavlintrin.h$", ""}, - {"include/avx512pfintrin.h$", ""}, - {"include/avx512vbmiintrin.h$", ""}, - {"include/avx512vbmivlintrin.h$", ""}, - {"include/avx512vlbwintrin.h$", ""}, - {"include/avx512vlcdintrin.h$", ""}, - {"include/avx512vldqintrin.h$", ""}, - {"include/avx512vlintrin.h$", ""}, - {"include/avxintrin.h$", ""}, - {"include/bmi2intrin.h$", ""}, - {"include/bmiintrin.h$", ""}, - {"include/emmintrin.h$", ""}, - {"include/f16cintrin.h$", ""}, - {"include/float.h$", ""}, - {"include/fma4intrin.h$", ""}, - {"include/fmaintrin.h$", ""}, - {"include/fxsrintrin.h$", ""}, - {"include/ia32intrin.h$", ""}, - {"include/immintrin.h$", ""}, - {"include/inttypes.h$", ""}, - {"include/limits.h$", ""}, - {"include/lzcntintrin.h$", ""}, - {"include/mm3dnow.h$", ""}, - {"include/mm_malloc.h$", ""}, - {"include/mmintrin.h$", ""}, - {"include/mwaitxintrin.h$", ""}, - {"include/pkuintrin.h$", ""}, - {"include/pmmintrin.h$", ""}, - {"include/popcntintrin.h$", ""}, - {"include/prfchwintrin.h$", ""}, - {"include/rdseedintrin.h$", ""}, - {"include/rtmintrin.h$", ""}, - {"include/shaintrin.h$", ""}, - {"include/smmintrin.h$", ""}, - {"include/stdalign.h$", ""}, - {"include/stdarg.h$", ""}, - {"include/stdbool.h$", ""}, - {"include/stddef.h$", ""}, - {"include/stdint.h$", ""}, - {"include/tbmintrin.h$", ""}, - {"include/tmmintrin.h$", ""}, - {"include/wmmintrin.h$", ""}, - {"include/x86intrin.h$", ""}, - {"include/xmmintrin.h$", ""}, - {"include/xopintrin.h$", ""}, - {"include/xsavecintrin.h$", ""}, - {"include/xsaveintrin.h$", ""}, - {"include/xsaveoptintrin.h$", ""}, - {"include/xsavesintrin.h$", ""}, - {"include/xtestintrin.h$", ""}, - {"include/_G_config.h$", ""}, - {"include/assert.h$", ""}, - {"algorithm$", ""}, - {"array$", ""}, - {"atomic$", ""}, - {"backward/auto_ptr.h$", ""}, - {"backward/binders.h$", ""}, - {"bits/algorithmfwd.h$", ""}, - {"bits/alloc_traits.h$", ""}, - {"bits/allocator.h$", ""}, - {"bits/atomic_base.h$", ""}, - {"bits/atomic_lockfree_defines.h$", ""}, - {"bits/basic_ios.h$", ""}, - {"bits/basic_ios.tcc$", ""}, - {"bits/basic_string.h$", ""}, - {"bits/basic_string.tcc$", ""}, - {"bits/char_traits.h$", ""}, - {"bits/codecvt.h$", ""}, - {"bits/concept_check.h$", ""}, - {"bits/cpp_type_traits.h$", ""}, - {"bits/cxxabi_forced.h$", ""}, - {"bits/deque.tcc$", ""}, - {"bits/exception_defines.h$", ""}, - {"bits/exception_ptr.h$", ""}, - {"bits/forward_list.h$", ""}, - {"bits/forward_list.tcc$", ""}, - {"bits/fstream.tcc$", ""}, - {"bits/functexcept.h$", ""}, - {"bits/functional_hash.h$", ""}, - {"bits/gslice.h$", ""}, - {"bits/gslice_array.h$", ""}, - {"bits/hash_bytes.h$", ""}, - {"bits/hashtable.h$", ""}, - {"bits/hashtable_policy.h$", ""}, - {"bits/indirect_array.h$", ""}, - {"bits/ios_base.h$", ""}, - {"bits/istream.tcc$", ""}, - {"bits/list.tcc$", ""}, - {"bits/locale_classes.h$", ""}, - {"bits/locale_classes.tcc$", ""}, - {"bits/locale_facets.h$", ""}, - {"bits/locale_facets.tcc$", ""}, - {"bits/locale_facets_nonio.h$", ""}, - {"bits/locale_facets_nonio.tcc$", ""}, - {"bits/localefwd.h$", ""}, - {"bits/mask_array.h$", ""}, - {"bits/memoryfwd.h$", ""}, - {"bits/move.h$", ""}, - {"bits/nested_exception.h$", ""}, - {"bits/ostream.tcc$", ""}, - {"bits/ostream_insert.h$", ""}, - {"bits/postypes.h$", ""}, - {"bits/ptr_traits.h$", ""}, - {"bits/random.h$", ""}, - {"bits/random.tcc$", ""}, - {"bits/range_access.h$", ""}, - {"bits/regex.h$", ""}, - {"bits/regex_compiler.h$", ""}, - {"bits/regex_constants.h$", ""}, - {"bits/regex_cursor.h$", ""}, - {"bits/regex_error.h$", ""}, - {"bits/regex_grep_matcher.h$", ""}, - {"bits/regex_grep_matcher.tcc$", ""}, - {"bits/regex_nfa.h$", ""}, - {"bits/shared_ptr.h$", ""}, - {"bits/shared_ptr_base.h$", ""}, - {"bits/slice_array.h$", ""}, - {"bits/sstream.tcc$", ""}, - {"bits/stl_algo.h$", ""}, - {"bits/stl_algobase.h$", ""}, - {"bits/stl_bvector.h$", ""}, - {"bits/stl_construct.h$", ""}, - {"bits/stl_deque.h$", ""}, - {"bits/stl_function.h$", ""}, - {"bits/stl_heap.h$", ""}, - {"bits/stl_iterator.h$", ""}, - {"bits/stl_iterator_base_funcs.h$", ""}, - {"bits/stl_iterator_base_types.h$", ""}, - {"bits/stl_list.h$", ""}, - {"bits/stl_map.h$", ""}, - {"bits/stl_multimap.h$", ""}, - {"bits/stl_multiset.h$", ""}, - {"bits/stl_numeric.h$", ""}, - {"bits/stl_pair.h$", ""}, - {"bits/stl_queue.h$", ""}, - {"bits/stl_raw_storage_iter.h$", ""}, - {"bits/stl_relops.h$", ""}, - {"bits/stl_set.h$", ""}, - {"bits/stl_stack.h$", ""}, - {"bits/stl_tempbuf.h$", ""}, - {"bits/stl_tree.h$", ""}, - {"bits/stl_uninitialized.h$", ""}, - {"bits/stl_vector.h$", ""}, - {"bits/stream_iterator.h$", ""}, - {"bits/streambuf.tcc$", ""}, - {"bits/streambuf_iterator.h$", ""}, - {"bits/stringfwd.h$", ""}, - {"bits/unique_ptr.h$", ""}, - {"bits/unordered_map.h$", ""}, - {"bits/unordered_set.h$", ""}, - {"bits/uses_allocator.h$", ""}, - {"bits/valarray_after.h$", ""}, - {"bits/valarray_array.h$", ""}, - {"bits/valarray_array.tcc$", ""}, - {"bits/valarray_before.h$", ""}, - {"bits/vector.tcc$", ""}, - {"bitset$", ""}, - {"ccomplex$", ""}, - {"cctype$", ""}, - {"cerrno$", ""}, - {"cfenv$", ""}, - {"cfloat$", ""}, - {"chrono$", ""}, - {"cinttypes$", ""}, - {"climits$", ""}, - {"clocale$", ""}, - {"cmath$", ""}, - {"complex$", ""}, - {"complex.h$", ""}, - {"condition_variable$", ""}, - {"csetjmp$", ""}, - {"csignal$", ""}, - {"cstdalign$", ""}, - {"cstdarg$", ""}, - {"cstdbool$", ""}, - {"cstdint$", ""}, - {"cstdio$", ""}, - {"cstdlib$", ""}, - {"cstring$", ""}, - {"ctgmath$", ""}, - {"ctime$", ""}, - {"cwchar$", ""}, - {"cwctype$", ""}, - {"cxxabi.h$", ""}, - {"debug/debug.h$", ""}, - {"deque$", ""}, - {"exception$", ""}, - {"ext/alloc_traits.h$", ""}, - {"ext/atomicity.h$", ""}, - {"ext/concurrence.h$", ""}, - {"ext/new_allocator.h$", ""}, - {"ext/numeric_traits.h$", ""}, - {"ext/string_conversions.h$", ""}, - {"ext/type_traits.h$", ""}, - {"fenv.h$", ""}, - {"forward_list$", ""}, - {"fstream$", ""}, - {"functional$", ""}, - {"future$", ""}, - {"initializer_list$", ""}, - {"iomanip$", ""}, - {"ios$", ""}, - {"iosfwd$", ""}, - {"iostream$", ""}, - {"istream$", ""}, - {"iterator$", ""}, - {"limits$", ""}, - {"list$", ""}, - {"locale$", ""}, - {"map$", ""}, - {"memory$", ""}, - {"mutex$", ""}, - {"new$", ""}, - {"numeric$", ""}, - {"ostream$", ""}, - {"queue$", ""}, - {"random$", ""}, - {"ratio$", ""}, - {"regex$", ""}, - {"scoped_allocator$", ""}, - {"set$", ""}, - {"sstream$", ""}, - {"stack$", ""}, - {"stdexcept$", ""}, - {"streambuf$", ""}, - {"string$", ""}, - {"system_error$", ""}, - {"tgmath.h$", ""}, - {"thread$", ""}, - {"tuple$", ""}, - {"type_traits$", ""}, - {"typeindex$", ""}, - {"typeinfo$", ""}, - {"unordered_map$", ""}, - {"unordered_set$", ""}, - {"utility$", ""}, - {"valarray$", ""}, - {"vector$", ""}, - {"include/complex.h$", ""}, - {"include/ctype.h$", ""}, - {"include/errno.h$", ""}, - {"include/fenv.h$", ""}, - {"include/inttypes.h$", ""}, - {"include/libio.h$", ""}, - {"include/limits.h$", ""}, - {"include/locale.h$", ""}, - {"include/math.h$", ""}, - {"include/setjmp.h$", ""}, - {"include/signal.h$", ""}, - {"include/stdint.h$", ""}, - {"include/stdio.h$", ""}, - {"include/stdlib.h$", ""}, - {"include/string.h$", ""}, - {"include/time.h$", ""}, - {"include/wchar.h$", ""}, - {"include/wctype.h$", ""}, - {"bits/cmathcalls.h$", ""}, - {"bits/errno.h$", ""}, - {"bits/fenv.h$", ""}, - {"bits/huge_val.h$", ""}, - {"bits/huge_valf.h$", ""}, - {"bits/huge_vall.h$", ""}, - {"bits/inf.h$", ""}, - {"bits/local_lim.h$", ""}, - {"bits/locale.h$", ""}, - {"bits/mathcalls.h$", ""}, - {"bits/mathdef.h$", ""}, - {"bits/nan.h$", ""}, - {"bits/posix1_lim.h$", ""}, - {"bits/posix2_lim.h$", ""}, - {"bits/setjmp.h$", ""}, - {"bits/sigaction.h$", ""}, - {"bits/sigcontext.h$", ""}, - {"bits/siginfo.h$", ""}, - {"bits/signum.h$", ""}, - {"bits/sigset.h$", ""}, - {"bits/sigstack.h$", ""}, - {"bits/stdio_lim.h$", ""}, - {"bits/sys_errlist.h$", ""}, - {"bits/time.h$", ""}, - {"bits/timex.h$", ""}, - {"bits/typesizes.h$", ""}, - {"bits/wchar.h$", ""}, - {"bits/wordsize.h$", ""}, - {"bits/xopen_lim.h$", ""}, - {"include/xlocale.h$", ""}, - {"bits/atomic_word.h$", ""}, - {"bits/basic_file.h$", ""}, - {"bits/c++allocator.h$", ""}, - {"bits/c++config.h$", ""}, - {"bits/c++io.h$", ""}, - {"bits/c++locale.h$", ""}, - {"bits/cpu_defines.h$", ""}, - {"bits/ctype_base.h$", ""}, - {"bits/cxxabi_tweaks.h$", ""}, - {"bits/error_constants.h$", ""}, - {"bits/gthr-default.h$", ""}, - {"bits/gthr.h$", ""}, - {"bits/opt_random.h$", ""}, - {"bits/os_defines.h$", ""}, - // GNU C headers - {"include/aio.h$", ""}, - {"include/aliases.h$", ""}, - {"include/alloca.h$", ""}, - {"include/ar.h$", ""}, - {"include/argp.h$", ""}, - {"include/argz.h$", ""}, - {"include/arpa/nameser.h$", ""}, - {"include/arpa/nameser_compat.h$", ""}, - {"include/byteswap.h$", ""}, - {"include/cpio.h$", ""}, - {"include/crypt.h$", ""}, - {"include/dirent.h$", ""}, - {"include/dlfcn.h$", ""}, - {"include/elf.h$", ""}, - {"include/endian.h$", ""}, - {"include/envz.h$", ""}, - {"include/err.h$", ""}, - {"include/error.h$", ""}, - {"include/execinfo.h$", ""}, - {"include/fcntl.h$", ""}, - {"include/features.h$", ""}, - {"include/fenv.h$", ""}, - {"include/fmtmsg.h$", ""}, - {"include/fnmatch.h$", ""}, - {"include/fstab.h$", ""}, - {"include/fts.h$", ""}, - {"include/ftw.h$", ""}, - {"include/gconv.h$", ""}, - {"include/getopt.h$", ""}, - {"include/glob.h$", ""}, - {"include/grp.h$", ""}, - {"include/gshadow.h$", ""}, - {"include/iconv.h$", ""}, - {"include/ifaddrs.h$", ""}, - {"include/kdb.h$", ""}, - {"include/langinfo.h$", ""}, - {"include/libgen.h$", ""}, - {"include/libintl.h$", ""}, - {"include/link.h$", ""}, - {"include/malloc.h$", ""}, - {"include/mcheck.h$", ""}, - {"include/memory.h$", ""}, - {"include/mntent.h$", ""}, - {"include/monetary.h$", ""}, - {"include/mqueue.h$", ""}, - {"include/netdb.h$", ""}, - {"include/netinet/in.h$", ""}, - {"include/nl_types.h$", ""}, - {"include/nss.h$", ""}, - {"include/obstack.h$", ""}, - {"include/panel.h$", ""}, - {"include/paths.h$", ""}, - {"include/printf.h$", ""}, - {"include/profile.h$", ""}, - {"include/pthread.h$", ""}, - {"include/pty.h$", ""}, - {"include/pwd.h$", ""}, - {"include/re_comp.h$", ""}, - {"include/regex.h$", ""}, - {"include/regexp.h$", ""}, - {"include/resolv.h$", ""}, - {"include/rpc/netdb.h$", ""}, - {"include/sched.h$", ""}, - {"include/search.h$", ""}, - {"include/semaphore.h$", ""}, - {"include/sgtty.h$", ""}, - {"include/shadow.h$", ""}, - {"include/spawn.h$", ""}, - {"include/stab.h$", ""}, - {"include/stdc-predef.h$", ""}, - {"include/stdio_ext.h$", ""}, - {"include/strings.h$", ""}, - {"include/stropts.h$", ""}, - {"include/sudo_plugin.h$", ""}, - {"include/sysexits.h$", ""}, - {"include/tar.h$", ""}, - {"include/tcpd.h$", ""}, - {"include/term.h$", ""}, - {"include/term_entry.h$", ""}, - {"include/termcap.h$", ""}, - {"include/termios.h$", ""}, - {"include/thread_db.h$", ""}, - {"include/tic.h$", ""}, - {"include/ttyent.h$", ""}, - {"include/uchar.h$", ""}, - {"include/ucontext.h$", ""}, - {"include/ulimit.h$", ""}, - {"include/unctrl.h$", ""}, - {"include/unistd.h$", ""}, - {"include/utime.h$", ""}, - {"include/utmp.h$", ""}, - {"include/utmpx.h$", ""}, - {"include/values.h$", ""}, - {"include/wordexp.h$", ""}, - {"fpu_control.h$", ""}, - {"ieee754.h$", ""}, - {"include/xlocale.h$", ""}, - {"gnu/lib-names.h$", ""}, - {"gnu/libc-version.h$", ""}, - {"gnu/option-groups.h$", ""}, - {"gnu/stubs-32.h$", ""}, - {"gnu/stubs-64.h$", ""}, - {"gnu/stubs-x32.h$", ""}, - {"include/rpc/auth_des.h$", ""}, - {"include/rpc/rpc_msg.h$", ""}, - {"include/rpc/pmap_clnt.h$", ""}, - {"include/rpc/rpc.h$", ""}, - {"include/rpc/types.h$", ""}, - {"include/rpc/auth_unix.h$", ""}, - {"include/rpc/key_prot.h$", ""}, - {"include/rpc/pmap_prot.h$", ""}, - {"include/rpc/auth.h$", ""}, - {"include/rpc/svc_auth.h$", ""}, - {"include/rpc/xdr.h$", ""}, - {"include/rpc/pmap_rmt.h$", ""}, - {"include/rpc/des_crypt.h$", ""}, - {"include/rpc/svc.h$", ""}, - {"include/rpc/rpc_des.h$", ""}, - {"include/rpc/clnt.h$", ""}, - {"include/scsi/scsi.h$", ""}, - {"include/scsi/sg.h$", ""}, - {"include/scsi/scsi_ioctl.h$", ""}, - {"include/netrose/rose.h$", ""}, - {"include/nfs/nfs.h$", ""}, - {"include/netatalk/at.h$", ""}, - {"include/netinet/ether.h$", ""}, - {"include/netinet/icmp6.h$", ""}, - {"include/netinet/if_ether.h$", ""}, - {"include/netinet/if_fddi.h$", ""}, - {"include/netinet/if_tr.h$", ""}, - {"include/netinet/igmp.h$", ""}, - {"include/netinet/in.h$", ""}, - {"include/netinet/in_systm.h$", ""}, - {"include/netinet/ip.h$", ""}, - {"include/netinet/ip6.h$", ""}, - {"include/netinet/ip_icmp.h$", ""}, - {"include/netinet/tcp.h$", ""}, - {"include/netinet/udp.h$", ""}, - {"include/netrom/netrom.h$", ""}, - {"include/protocols/routed.h$", ""}, - {"include/protocols/rwhod.h$", ""}, - {"include/protocols/talkd.h$", ""}, - {"include/protocols/timed.h$", ""}, - {"include/rpcsvc/klm_prot.x$", ""}, - {"include/rpcsvc/rstat.h$", ""}, - {"include/rpcsvc/spray.x$", ""}, - {"include/rpcsvc/nlm_prot.x$", ""}, - {"include/rpcsvc/nis_callback.x$", ""}, - {"include/rpcsvc/yp.h$", ""}, - {"include/rpcsvc/yp.x$", ""}, - {"include/rpcsvc/nfs_prot.h$", ""}, - {"include/rpcsvc/rex.h$", ""}, - {"include/rpcsvc/yppasswd.h$", ""}, - {"include/rpcsvc/rex.x$", ""}, - {"include/rpcsvc/nis_tags.h$", ""}, - {"include/rpcsvc/nis_callback.h$", ""}, - {"include/rpcsvc/nfs_prot.x$", ""}, - {"include/rpcsvc/bootparam_prot.x$", ""}, - {"include/rpcsvc/rusers.x$", ""}, - {"include/rpcsvc/rquota.x$", ""}, - {"include/rpcsvc/nis.h$", ""}, - {"include/rpcsvc/nislib.h$", ""}, - {"include/rpcsvc/ypupd.h$", ""}, - {"include/rpcsvc/bootparam.h$", ""}, - {"include/rpcsvc/spray.h$", ""}, - {"include/rpcsvc/key_prot.h$", ""}, - {"include/rpcsvc/klm_prot.h$", ""}, - {"include/rpcsvc/sm_inter.h$", ""}, - {"include/rpcsvc/nlm_prot.h$", ""}, - {"include/rpcsvc/yp_prot.h$", ""}, - {"include/rpcsvc/ypclnt.h$", ""}, - {"include/rpcsvc/rstat.x$", ""}, - {"include/rpcsvc/rusers.h$", ""}, - {"include/rpcsvc/key_prot.x$", ""}, - {"include/rpcsvc/sm_inter.x$", ""}, - {"include/rpcsvc/rquota.h$", ""}, - {"include/rpcsvc/nis.x$", ""}, - {"include/rpcsvc/bootparam_prot.h$", ""}, - {"include/rpcsvc/mount.h$", ""}, - {"include/rpcsvc/mount.x$", ""}, - {"include/rpcsvc/nis_object.x$", ""}, - {"include/rpcsvc/yppasswd.x$", ""}, - {"sys/acct.h$", ""}, - {"sys/auxv.h$", ""}, - {"sys/cdefs.h$", ""}, - {"sys/debugreg.h$", ""}, - {"sys/dir.h$", ""}, - {"sys/elf.h$", ""}, - {"sys/epoll.h$", ""}, - {"sys/eventfd.h$", ""}, - {"sys/fanotify.h$", ""}, - {"sys/file.h$", ""}, - {"sys/fsuid.h$", ""}, - {"sys/gmon.h$", ""}, - {"sys/gmon_out.h$", ""}, - {"sys/inotify.h$", ""}, - {"sys/io.h$", ""}, - {"sys/ioctl.h$", ""}, - {"sys/ipc.h$", ""}, - {"sys/kd.h$", ""}, - {"sys/kdaemon.h$", ""}, - {"sys/klog.h$", ""}, - {"sys/mman.h$", ""}, - {"sys/mount.h$", ""}, - {"sys/msg.h$", ""}, - {"sys/mtio.h$", ""}, - {"sys/param.h$", ""}, - {"sys/pci.h$", ""}, - {"sys/perm.h$", ""}, - {"sys/personality.h$", ""}, - {"sys/poll.h$", ""}, - {"sys/prctl.h$", ""}, - {"sys/procfs.h$", ""}, - {"sys/profil.h$", ""}, - {"sys/ptrace.h$", ""}, - {"sys/queue.h$", ""}, - {"sys/quota.h$", ""}, - {"sys/raw.h$", ""}, - {"sys/reboot.h$", ""}, - {"sys/reg.h$", ""}, - {"sys/resource.h$", ""}, - {"sys/select.h$", ""}, - {"sys/sem.h$", ""}, - {"sys/sendfile.h$", ""}, - {"sys/shm.h$", ""}, - {"sys/signalfd.h$", ""}, - {"sys/socket.h$", ""}, - {"sys/stat.h$", ""}, - {"sys/statfs.h$", ""}, - {"sys/statvfs.h$", ""}, - {"sys/swap.h$", ""}, - {"sys/syscall.h$", ""}, - {"sys/sysctl.h$", ""}, - {"sys/sysinfo.h$", ""}, - {"sys/syslog.h$", ""}, - {"sys/sysmacros.h$", ""}, - {"sys/termios.h$", ""}, - {"sys/time.h$", ""}, - {"sys/timeb.h$", ""}, - {"sys/timerfd.h$", ""}, - {"sys/times.h$", ""}, - {"sys/timex.h$", ""}, - {"sys/ttychars.h$", ""}, - {"sys/ttydefaults.h$", ""}, - {"sys/types.h$", ""}, - {"sys/ucontext.h$", ""}, - {"sys/uio.h$", ""}, - {"sys/un.h$", ""}, - {"sys/user.h$", ""}, - {"sys/ustat.h$", ""}, - {"sys/utsname.h$", ""}, - {"sys/vlimit.h$", ""}, - {"sys/vm86.h$", ""}, - {"sys/vtimes.h$", ""}, - {"sys/wait.h$", ""}, - {"sys/xattr.h$", ""}, - {"bits/epoll.h$", ""}, - {"bits/eventfd.h$", ""}, - {"bits/inotify.h$", ""}, - {"bits/ipc.h$", ""}, - {"bits/ipctypes.h$", ""}, - {"bits/mman-linux.h$", ""}, - {"bits/mman.h$", ""}, - {"bits/msq.h$", ""}, - {"bits/resource.h$", ""}, - {"bits/sem.h$", ""}, - {"bits/shm.h$", ""}, - {"bits/signalfd.h$", ""}, - {"bits/statfs.h$", ""}, - {"bits/statvfs.h$", ""}, - {"bits/timerfd.h$", ""}, - {"bits/utsname.h$", ""}, - {"bits/auxv.h$", ""}, - {"bits/byteswap-16.h$", ""}, - {"bits/byteswap.h$", ""}, - {"bits/confname.h$", ""}, - {"bits/dirent.h$", ""}, - {"bits/dlfcn.h$", ""}, - {"bits/elfclass.h$", ""}, - {"bits/endian.h$", ""}, - {"bits/environments.h$", ""}, - {"bits/fcntl-linux.h$", ""}, - {"bits/fcntl.h$", ""}, - {"bits/in.h$", ""}, - {"bits/ioctl-types.h$", ""}, - {"bits/ioctls.h$", ""}, - {"bits/link.h$", ""}, - {"bits/mqueue.h$", ""}, - {"bits/netdb.h$", ""}, - {"bits/param.h$", ""}, - {"bits/poll.h$", ""}, - {"bits/posix_opt.h$", ""}, - {"bits/pthreadtypes.h$", ""}, - {"bits/sched.h$", ""}, - {"bits/select.h$", ""}, - {"bits/semaphore.h$", ""}, - {"bits/sigthread.h$", ""}, - {"bits/sockaddr.h$", ""}, - {"bits/socket.h$", ""}, - {"bits/socket_type.h$", ""}, - {"bits/stab.def$", ""}, - {"bits/stat.h$", ""}, - {"bits/stropts.h$", ""}, - {"bits/syscall.h$", ""}, - {"bits/syslog-path.h$", ""}, - {"bits/termios.h$", ""}, - {"bits/types.h$", ""}, - {"bits/typesizes.h$", ""}, - {"bits/uio.h$", ""}, - {"bits/ustat.h$", ""}, - {"bits/utmp.h$", ""}, - {"bits/utmpx.h$", ""}, - {"bits/waitflags.h$", ""}, - {"bits/waitstatus.h$", ""}, - {"bits/xtitypes.h$", ""}, - }; - return &STLPostfixHeaderMap; -} - -} // namespace find_all_symbols -} // namespace clang Index: include-fixer/find-all-symbols/SymbolInfo.h =================================================================== --- include-fixer/find-all-symbols/SymbolInfo.h +++ /dev/null @@ -1,127 +0,0 @@ -//===-- SymbolInfo.h - Symbol Info ------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FIND_ALL_SYMBOLS_SYMBOLINFO_H -#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FIND_ALL_SYMBOLS_SYMBOLINFO_H - -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/YAMLTraits.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include - -namespace clang { -namespace find_all_symbols { - -/// \brief Contains all information for a Symbol. -class SymbolInfo { -public: - /// \brief The SymbolInfo Type. - enum class SymbolKind { - Function, - Class, - Variable, - TypedefName, - EnumDecl, - EnumConstantDecl, - Macro, - Unknown, - }; - - /// \brief The Context Type. - enum class ContextType { - Namespace, // Symbols declared in a namespace. - Record, // Symbols declared in a class. - EnumDecl, // Enum constants declared in a enum declaration. - }; - - /// \brief A pair of . - typedef std::pair Context; - - // The default constructor is required by YAML traits in - // LLVM_YAML_IS_DOCUMENT_LIST_VECTOR. - SymbolInfo() : Type(SymbolKind::Unknown), LineNumber(-1) {} - - SymbolInfo(llvm::StringRef Name, SymbolKind Type, llvm::StringRef FilePath, - int LineNumber, const std::vector &Contexts, - unsigned NumOccurrences = 0); - - /// \brief Get symbol name. - llvm::StringRef getName() const { return Name; } - - /// \brief Get the fully-qualified symbol name. - std::string getQualifiedName() const; - - /// \brief Get symbol type. - SymbolKind getSymbolKind() const { return Type; } - - /// \brief Get a relative file path where symbol comes from. - llvm::StringRef getFilePath() const { return FilePath; } - - /// \brief Get symbol contexts. - const std::vector &getContexts() const { - return Contexts; - } - - /// \brief Get a 1-based line number of the symbol's declaration. - int getLineNumber() const { return LineNumber; } - - /// \brief The number of times this symbol was found during an indexing run. - unsigned getNumOccurrences() const { return NumOccurrences; } - - bool operator<(const SymbolInfo &Symbol) const; - - bool operator==(const SymbolInfo &Symbol) const; - -private: - friend struct llvm::yaml::MappingTraits; - - /// \brief Identifier name. - std::string Name; - - /// \brief Symbol type. - SymbolKind Type; - - /// \brief The file path where the symbol comes from. It's a relative file - /// path based on the build directory. - std::string FilePath; - - /// \brief Contains information about symbol contexts. Context information is - /// stored from the inner-most level to outer-most level. - /// - /// For example, if a symbol 'x' is declared as: - /// namespace na { namespace nb { class A { int x; } } } - /// The contexts would be { {RECORD, "A"}, {NAMESPACE, "nb"}, {NAMESPACE, - /// "na"} }. - /// The name of an anonymous namespace is "". - /// - /// If the symbol is declared in `TranslationUnitDecl`, it has no context. - std::vector Contexts; - - /// \brief The 1-based line number of of the symbol's declaration. - int LineNumber; - - /// \brief The number of times this symbol was found during an indexing - /// run. Populated by the reducer and used to rank results. - unsigned NumOccurrences; -}; - -/// \brief Write SymbolInfos to a stream (YAML format). -bool WriteSymbolInfosToStream(llvm::raw_ostream &OS, - const std::set &Symbols); - -/// \brief Read SymbolInfos from a YAML document. -std::vector ReadSymbolInfosFromYAML(llvm::StringRef Yaml); - -} // namespace find_all_symbols -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FIND_ALL_SYMBOLS_SYMBOLINFO_H Index: include-fixer/find-all-symbols/SymbolInfo.cpp =================================================================== --- include-fixer/find-all-symbols/SymbolInfo.cpp +++ /dev/null @@ -1,119 +0,0 @@ -//===-- SymbolInfo.cpp - Symbol Info ----------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "SymbolInfo.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/YAMLTraits.h" -#include "llvm/Support/raw_ostream.h" - -using llvm::yaml::MappingTraits; -using llvm::yaml::IO; -using llvm::yaml::Input; -using ContextType = clang::find_all_symbols::SymbolInfo::ContextType; -using clang::find_all_symbols::SymbolInfo; -using SymbolKind = clang::find_all_symbols::SymbolInfo::SymbolKind; - -LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(SymbolInfo) -LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string) -LLVM_YAML_IS_SEQUENCE_VECTOR(SymbolInfo::Context) - -namespace llvm { -namespace yaml { -template <> struct MappingTraits { - static void mapping(IO &io, SymbolInfo &Symbol) { - io.mapRequired("Name", Symbol.Name); - io.mapRequired("Contexts", Symbol.Contexts); - io.mapRequired("FilePath", Symbol.FilePath); - io.mapRequired("LineNumber", Symbol.LineNumber); - io.mapRequired("Type", Symbol.Type); - io.mapRequired("NumOccurrences", Symbol.NumOccurrences); - } -}; - -template <> struct ScalarEnumerationTraits { - static void enumeration(IO &io, ContextType &value) { - io.enumCase(value, "Record", ContextType::Record); - io.enumCase(value, "Namespace", ContextType::Namespace); - io.enumCase(value, "EnumDecl", ContextType::EnumDecl); - } -}; - -template <> struct ScalarEnumerationTraits { - static void enumeration(IO &io, SymbolKind &value) { - io.enumCase(value, "Variable", SymbolKind::Variable); - io.enumCase(value, "Function", SymbolKind::Function); - io.enumCase(value, "Class", SymbolKind::Class); - io.enumCase(value, "TypedefName", SymbolKind::TypedefName); - io.enumCase(value, "EnumDecl", SymbolKind::EnumDecl); - io.enumCase(value, "EnumConstantDecl", SymbolKind::EnumConstantDecl); - io.enumCase(value, "Macro", SymbolKind::Macro); - io.enumCase(value, "Unknown", SymbolKind::Unknown); - } -}; - -template <> struct MappingTraits { - static void mapping(IO &io, SymbolInfo::Context &Context) { - io.mapRequired("ContextType", Context.first); - io.mapRequired("ContextName", Context.second); - } -}; - -} // namespace yaml -} // namespace llvm - -namespace clang { -namespace find_all_symbols { - -SymbolInfo::SymbolInfo(llvm::StringRef Name, SymbolKind Type, - llvm::StringRef FilePath, int LineNumber, - const std::vector &Contexts, - unsigned NumOccurrences) - : Name(Name), Type(Type), FilePath(FilePath), Contexts(Contexts), - LineNumber(LineNumber), NumOccurrences(NumOccurrences) {} - -bool SymbolInfo::operator==(const SymbolInfo &Symbol) const { - return std::tie(Name, Type, FilePath, LineNumber, Contexts) == - std::tie(Symbol.Name, Symbol.Type, Symbol.FilePath, Symbol.LineNumber, - Symbol.Contexts); -} - -bool SymbolInfo::operator<(const SymbolInfo &Symbol) const { - return std::tie(Name, Type, FilePath, LineNumber, Contexts) < - std::tie(Symbol.Name, Symbol.Type, Symbol.FilePath, Symbol.LineNumber, - Symbol.Contexts); -} - -std::string SymbolInfo::getQualifiedName() const { - std::string QualifiedName = Name; - for (const auto &Context : Contexts) { - if (Context.first == ContextType::EnumDecl) - continue; - QualifiedName = Context.second + "::" + QualifiedName; - } - return QualifiedName; -} - -bool WriteSymbolInfosToStream(llvm::raw_ostream &OS, - const std::set &Symbols) { - llvm::yaml::Output yout(OS); - for (auto Symbol : Symbols) - yout << Symbol; - return true; -} - -std::vector ReadSymbolInfosFromYAML(llvm::StringRef Yaml) { - std::vector Symbols; - llvm::yaml::Input yin(Yaml); - yin >> Symbols; - return Symbols; -} - -} // namespace find_all_symbols -} // namespace clang Index: include-fixer/find-all-symbols/SymbolReporter.h =================================================================== --- include-fixer/find-all-symbols/SymbolReporter.h +++ /dev/null @@ -1,30 +0,0 @@ -//===--- SymbolReporter.h - Symbol Reporter ---------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_REPORTER_H -#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_REPORTER_H - -#include "SymbolInfo.h" - -namespace clang { -namespace find_all_symbols { - -/// \brief An interface for classes that collect symbols. -class SymbolReporter { -public: - virtual ~SymbolReporter() = default; - - virtual void reportSymbol(llvm::StringRef FileName, - const SymbolInfo &Symbol) = 0; -}; - -} // namespace find_all_symbols -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_REPORTER_H Index: include-fixer/find-all-symbols/tool/CMakeLists.txt =================================================================== --- include-fixer/find-all-symbols/tool/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) - -add_clang_executable(find-all-symbols FindAllSymbolsMain.cpp) -target_link_libraries(find-all-symbols - - clangAST - clangASTMatchers - clangBasic - clangFrontend - clangLex - clangTooling - findAllSymbols - ) Index: include-fixer/find-all-symbols/tool/FindAllSymbolsMain.cpp =================================================================== --- include-fixer/find-all-symbols/tool/FindAllSymbolsMain.cpp +++ /dev/null @@ -1,162 +0,0 @@ -//===-- FindAllSymbolsMain.cpp - find all symbols tool ----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "FindAllSymbolsAction.h" -#include "STLPostfixHeaderMap.h" -#include "SymbolInfo.h" -#include "SymbolReporter.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/ASTMatchers/ASTMatchers.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Tooling/CommonOptionsParser.h" -#include "clang/Tooling/Tooling.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/ThreadPool.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include -#include -#include -#include - -using namespace clang::tooling; -using namespace llvm; -using SymbolInfo = clang::find_all_symbols::SymbolInfo; - -// Apply a custom category to all command-line options so that they are the -// only ones displayed. -static cl::OptionCategory FindAllSymbolsCategory("find_all_symbols options"); - -// CommonOptionsParser declares HelpMessage with a description of the common -// command-line options related to the compilation database and input files. -// It's nice to have this help message in all tools. -static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); - -// A help message for this specific tool can be added afterwards. -static cl::extrahelp MoreHelp("\nMore help text..."); - -static cl::opt OutputDir("output-dir", cl::desc(R"( -The output directory for saving the results.)"), - cl::init("."), - cl::cat(FindAllSymbolsCategory)); - -static cl::opt MergeDir("merge-dir", cl::desc(R"( -The directory for merging symbols.)"), - cl::init(""), - cl::cat(FindAllSymbolsCategory)); -namespace clang { -namespace find_all_symbols { - -class YamlReporter : public clang::find_all_symbols::SymbolReporter { -public: - ~YamlReporter() override { - for (const auto &Symbol : Symbols) { - int FD; - SmallString<128> ResultPath; - llvm::sys::fs::createUniqueFile( - OutputDir + "/" + llvm::sys::path::filename(Symbol.first) + - "-%%%%%%.yaml", - FD, ResultPath); - llvm::raw_fd_ostream OS(FD, /*shouldClose=*/true); - WriteSymbolInfosToStream(OS, Symbol.second); - } - } - - void reportSymbol(StringRef FileName, const SymbolInfo &Symbol) override { - Symbols[FileName].insert(Symbol); - } - -private: - std::map> Symbols; -}; - -bool Merge(llvm::StringRef MergeDir, llvm::StringRef OutputFile) { - std::error_code EC; - std::map SymbolToNumOccurrences; - std::mutex SymbolMutex; - auto AddSymbols = [&](ArrayRef Symbols) { - // Synchronize set accesses. - std::unique_lock LockGuard(SymbolMutex); - for (const auto &Symbol : Symbols) - ++SymbolToNumOccurrences[Symbol]; - }; - - // Load all symbol files in MergeDir. - { - llvm::ThreadPool Pool; - for (llvm::sys::fs::directory_iterator Dir(MergeDir, EC), DirEnd; - Dir != DirEnd && !EC; Dir.increment(EC)) { - // Parse YAML files in parallel. - Pool.async( - [&AddSymbols](std::string Path) { - auto Buffer = llvm::MemoryBuffer::getFile(Path); - if (!Buffer) { - llvm::errs() << "Can't open " << Path << "\n"; - return; - } - std::vector Symbols = - ReadSymbolInfosFromYAML(Buffer.get()->getBuffer()); - // FIXME: Merge without creating such a heavy contention point. - AddSymbols(Symbols); - }, - Dir->path()); - } - } - - llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_None); - if (EC) { - llvm::errs() << "Can't open '" << OutputFile << "': " << EC.message() - << '\n'; - return false; - } - std::set Result; - for (const auto &Entry : SymbolToNumOccurrences) { - const auto &Symbol = Entry.first; - Result.insert(SymbolInfo(Symbol.getName(), Symbol.getSymbolKind(), - Symbol.getFilePath(), Symbol.getLineNumber(), - Symbol.getContexts(), Entry.second)); - } - WriteSymbolInfosToStream(OS, Result); - return true; -} - -} // namespace clang -} // namespace find_all_symbols - -int main(int argc, const char **argv) { - CommonOptionsParser OptionsParser(argc, argv, FindAllSymbolsCategory); - ClangTool Tool(OptionsParser.getCompilations(), - OptionsParser.getSourcePathList()); - - std::vector sources = OptionsParser.getSourcePathList(); - if (sources.empty()) { - llvm::errs() << "Must specify at least one one source file.\n"; - return 1; - } - if (!MergeDir.empty()) { - clang::find_all_symbols::Merge(MergeDir, sources[0]); - return 0; - } - - clang::find_all_symbols::YamlReporter Reporter; - - auto Factory = - llvm::make_unique( - &Reporter, clang::find_all_symbols::getSTLPostfixHeaderMap()); - return Tool.run(Factory.get()); -} Index: include-fixer/find-all-symbols/tool/run-find-all-symbols.py =================================================================== --- include-fixer/find-all-symbols/tool/run-find-all-symbols.py +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/env python -# -#=- run-find-all-symbols.py - Parallel find-all-symbols runner -*- python -*-=# -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -#===------------------------------------------------------------------------===# - -""" -Parallel find-all-symbols runner -================================ - -Runs find-all-symbols over all files in a compilation database. - -Example invocations. -- Run find-all-symbols on all files in the current working directory. - run-find-all-symbols.py - -Compilation database setup: -http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html -""" - -import argparse -import json -import multiprocessing -import os -import Queue -import shutil -import subprocess -import sys -import tempfile -import threading - - -def find_compilation_database(path): - """Adjusts the directory until a compilation database is found.""" - result = './' - while not os.path.isfile(os.path.join(result, path)): - if os.path.realpath(result) == '/': - print 'Error: could not find compilation database.' - sys.exit(1) - result += '../' - return os.path.realpath(result) - - -def MergeSymbols(directory, args): - """Merge all symbol files (yaml) in a given directaory into a single file.""" - invocation = [args.binary, '-merge-dir='+directory, args.saving_path] - subprocess.call(invocation) - print 'Merge is finished. Saving results in ' + args.saving_path - - -def run_find_all_symbols(args, tmpdir, build_path, queue): - """Takes filenames out of queue and runs find-all-symbols on them.""" - while True: - name = queue.get() - invocation = [args.binary, name, '-output-dir='+tmpdir, '-p='+build_path] - sys.stdout.write(' '.join(invocation) + '\n') - subprocess.call(invocation) - queue.task_done() - - -def main(): - parser = argparse.ArgumentParser(description='Runs find-all-symbols over all' - 'files in a compilation database.') - parser.add_argument('-binary', metavar='PATH', - default='./bin/find-all-symbols', - help='path to find-all-symbols binary') - parser.add_argument('-j', type=int, default=0, - help='number of instances to be run in parallel.') - parser.add_argument('-p', dest='build_path', - help='path used to read a compilation database.') - parser.add_argument('-saving-path', default='./find_all_symbols_db.yaml', - help='result saving path') - args = parser.parse_args() - - db_path = 'compile_commands.json' - - if args.build_path is not None: - build_path = args.build_path - else: - build_path = find_compilation_database(db_path) - - tmpdir = tempfile.mkdtemp() - - # Load the database and extract all files. - database = json.load(open(os.path.join(build_path, db_path))) - files = [entry['file'] for entry in database] - - max_task = args.j - if max_task == 0: - max_task = multiprocessing.cpu_count() - - try: - # Spin up a bunch of tidy-launching threads. - queue = Queue.Queue(max_task) - for _ in range(max_task): - t = threading.Thread(target=run_find_all_symbols, - args=(args, tmpdir, build_path, queue)) - t.daemon = True - t.start() - - # Fill the queue with files. - for name in files: - queue.put(name) - - # Wait for all threads to be done. - queue.join() - - MergeSymbols(tmpdir, args) - - - except KeyboardInterrupt: - # This is a sad hack. Unfortunately subprocess goes - # bonkers with ctrl-c and we start forking merrily. - print '\nCtrl-C detected, goodbye.' - os.kill(0, 9) - - -if __name__ == '__main__': - main() Index: include-fixer/tool/CMakeLists.txt =================================================================== --- include-fixer/tool/CMakeLists.txt +++ include-fixer/tool/CMakeLists.txt @@ -3,11 +3,9 @@ add_clang_executable(clang-include-fixer ClangIncludeFixer.cpp) target_link_libraries(clang-include-fixer clangBasic - clangFormat clangFrontend clangIncludeFixer clangRewrite clangTooling clangToolingCore - findAllSymbols ) Index: include-fixer/tool/ClangIncludeFixer.cpp =================================================================== --- include-fixer/tool/ClangIncludeFixer.cpp +++ include-fixer/tool/ClangIncludeFixer.cpp @@ -7,299 +7,43 @@ // //===----------------------------------------------------------------------===// -#include "InMemorySymbolIndex.h" +#include "InMemoryXrefsDB.h" #include "IncludeFixer.h" -#include "IncludeFixerContext.h" -#include "SymbolIndexManager.h" -#include "YamlSymbolIndex.h" -#include "clang/Format/Format.h" #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Rewrite/Core/Rewriter.h" #include "clang/Tooling/CommonOptionsParser.h" -#include "clang/Tooling/Core/Replacement.h" #include "clang/Tooling/Tooling.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/YAMLTraits.h" - using namespace clang; -using namespace llvm; -using clang::include_fixer::IncludeFixerContext; - -LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(IncludeFixerContext) -LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string) - -namespace llvm { -namespace yaml { -template <> struct MappingTraits { - static void mapping(IO &io, IncludeFixerContext &Context) { - io.mapRequired("SymbolIdentifier", Context.SymbolIdentifier); - io.mapRequired("Headers", Context.Headers); - } -}; -} // namespace yaml -} // namespace llvm - -namespace { -cl::OptionCategory IncludeFixerCategory("Tool options"); - -enum DatabaseFormatTy { - fixed, ///< Hard-coded mapping. - yaml, ///< Yaml database created by find-all-symbols. -}; - -cl::opt DatabaseFormat( - "db", cl::desc("Specify input format"), - cl::values(clEnumVal(fixed, "Hard-coded mapping"), - clEnumVal(yaml, "Yaml database created by find-all-symbols"), - clEnumValEnd), - cl::init(yaml), cl::cat(IncludeFixerCategory)); - -cl::opt Input("input", - cl::desc("String to initialize the database"), - cl::cat(IncludeFixerCategory)); - -cl::opt - MinimizeIncludePaths("minimize-paths", - cl::desc("Whether to minimize added include paths"), - cl::init(true), cl::cat(IncludeFixerCategory)); - -cl::opt Quiet("q", cl::desc("Reduce terminal output"), cl::init(false), - cl::cat(IncludeFixerCategory)); - -cl::opt - STDINMode("stdin", - cl::desc("Override source file's content (in the overlaying\n" - "virtual file system) with input from and run\n" - "the tool on the new content with the compilation\n" - "options of the source file. This mode is currently\n" - "used for editor integration."), - cl::init(false), cl::cat(IncludeFixerCategory)); - -cl::opt OutputHeaders( - "output-headers", - cl::desc("Print the symbol being queried and all its relevant headers in\n" - "JSON format to stdout:\n" - " {\n" - " \"SymbolIdentifier\": \"foo\",\n" - " \"Headers\": [\"\\\"foo_a.h\\\"\"]\n" - " }"), - cl::init(false), cl::cat(IncludeFixerCategory)); - -cl::opt InsertHeader( - "insert-header", - cl::desc("Insert a specific header. This should run with STDIN mode.\n" - "The result is written to stdout. It is currently used for\n" - "editor integration. Support YAML/JSON format:\n" - " -insert-header=\"{SymbolIdentifier: foo,\n" - " Headers: ['\\\"foo_a.h\\\"']}\""), - cl::init(""), cl::cat(IncludeFixerCategory)); - -cl::opt - Style("style", - cl::desc("Fallback style for reformatting after inserting new " - "headers if there is no clang-format config file found."), - cl::init("llvm"), cl::cat(IncludeFixerCategory)); - -std::unique_ptr -createSymbolIndexManager(StringRef FilePath) { - auto SymbolIndexMgr = llvm::make_unique(); - switch (DatabaseFormat) { - case fixed: { - // Parse input and fill the database with it. - // =
<, header...> - // Multiple symbols can be given, separated by semicolons. - std::map> SymbolsMap; - SmallVector SemicolonSplits; - StringRef(Input).split(SemicolonSplits, ";"); - std::vector Symbols; - for (StringRef Pair : SemicolonSplits) { - auto Split = Pair.split('='); - std::vector Headers; - SmallVector CommaSplits; - Split.second.split(CommaSplits, ","); - for (size_t I = 0, E = CommaSplits.size(); I != E; ++I) - Symbols.push_back(find_all_symbols::SymbolInfo( - Split.first.trim(), - find_all_symbols::SymbolInfo::SymbolKind::Unknown, - CommaSplits[I].trim(), 1, {}, /*NumOccurrences=*/E - I)); - } - SymbolIndexMgr->addSymbolIndex( - llvm::make_unique(Symbols)); - break; - } - case yaml: { - llvm::ErrorOr> DB(nullptr); - if (!Input.empty()) { - DB = include_fixer::YamlSymbolIndex::createFromFile(Input); - } else { - // If we don't have any input file, look in the directory of the first - // file and its parents. - SmallString<128> AbsolutePath(tooling::getAbsolutePath(FilePath)); - StringRef Directory = llvm::sys::path::parent_path(AbsolutePath); - DB = include_fixer::YamlSymbolIndex::createFromDirectory( - Directory, "find_all_symbols_db.yaml"); - } - - if (!DB) { - llvm::errs() << "Couldn't find YAML db: " << DB.getError().message() - << '\n'; - return nullptr; - } - - SymbolIndexMgr->addSymbolIndex(std::move(*DB)); - break; - } - } - return SymbolIndexMgr; -} - -void writeToJson(llvm::raw_ostream &OS, const IncludeFixerContext& Context) { - OS << "{\n" - " \"SymbolIdentifier\": \"" << Context.getSymbolIdentifier() << "\",\n" - " \"Headers\": [ "; - for (const auto &Header : Context.getHeaders()) { - OS << " \"" << llvm::yaml::escape(Header) << "\""; - if (Header != Context.getHeaders().back()) - OS << ", "; - } - OS << " ]\n" - "}\n"; -} -int includeFixerMain(int argc, const char **argv) { - tooling::CommonOptionsParser options(argc, argv, IncludeFixerCategory); - tooling::ClangTool tool(options.getCompilations(), - options.getSourcePathList()); +static llvm::cl::OptionCategory tool_options("Tool options"); - // In STDINMode, we override the file content with the input. - // Since `tool.mapVirtualFile` takes `StringRef`, we define `Code` outside of - // the if-block so that `Code` is not released after the if-block. - std::unique_ptr Code; - if (STDINMode) { - assert(options.getSourcePathList().size() == 1 && - "Expect exactly one file path in STDINMode."); - llvm::ErrorOr> CodeOrErr = - MemoryBuffer::getSTDIN(); - if (std::error_code EC = CodeOrErr.getError()) { - errs() << EC.message() << "\n"; - return 1; - } - Code = std::move(CodeOrErr.get()); - if (Code->getBufferSize() == 0) - return 0; // Skip empty files. - - tool.mapVirtualFile(options.getSourcePathList().front(), Code->getBuffer()); - } - - StringRef FilePath = options.getSourcePathList().front(); - format::FormatStyle InsertStyle = format::getStyle("file", FilePath, Style); - - if (!InsertHeader.empty()) { - if (!STDINMode) { - errs() << "Should be running in STDIN mode\n"; - return 1; - } - - llvm::yaml::Input yin(InsertHeader); - IncludeFixerContext Context; - yin >> Context; - - if (Context.getHeaders().size() != 1) { - errs() << "Expect exactly one inserted header.\n"; - return 1; - } - - auto Replacements = clang::include_fixer::createInsertHeaderReplacements( - Code->getBuffer(), FilePath, Context.getHeaders().front(), InsertStyle); - if (!Replacements) { - errs() << "Failed to create header insertion replacement: " - << llvm::toString(Replacements.takeError()) << "\n"; - return 1; - } - auto ChangedCode = - tooling::applyAllReplacements(Code->getBuffer(), *Replacements); - if (!ChangedCode) { - llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n"; - return 1; - } - llvm::outs() << *ChangedCode; - return 0; - } - - // Set up data source. - std::unique_ptr SymbolIndexMgr = - createSymbolIndexManager(options.getSourcePathList().front()); - if (!SymbolIndexMgr) - return 1; +int main(int argc, const char **argv) { + clang::tooling::CommonOptionsParser options(argc, argv, tool_options); + clang::tooling::ClangTool tool(options.getCompilations(), + options.getSourcePathList()); + // Set up the data source. + std::map> XrefsMap = { + {"std::string", {""}}}; + auto XrefsDB = + llvm::make_unique(std::move(XrefsMap)); // Now run our tool. - include_fixer::IncludeFixerContext Context; - include_fixer::IncludeFixerActionFactory Factory(*SymbolIndexMgr, Context, - Style, MinimizeIncludePaths); - - if (tool.run(&Factory) != 0) { - llvm::errs() - << "Clang died with a fatal error! (incorrect include paths?)\n"; - return 1; - } - - if (OutputHeaders) { - writeToJson(llvm::outs(), Context); - return 0; - } + std::vector Replacements; + include_fixer::IncludeFixerActionFactory Factory(*XrefsDB, Replacements); - if (Context.getMatchedSymbols().empty()) - return 0; - - auto Buffer = llvm::MemoryBuffer::getFile(FilePath); - if (!Buffer) { - errs() << "Couldn't open file: " << FilePath; - return 1; - } - - // FIXME: Rank the results and pick the best one instead of the first one. - auto Replacements = clang::include_fixer::createInsertHeaderReplacements( - /*Code=*/Buffer.get()->getBuffer(), FilePath, - Context.getHeaders().front(), InsertStyle); - if (!Replacements) { - errs() << "Failed to create header insertion replacement: " - << llvm::toString(Replacements.takeError()) << "\n"; - return 1; - } - - if (!Quiet) - llvm::errs() << "Added #include" << Context.getHeaders().front(); - - // Add missing namespace qualifiers to the unidentified symbol. - if (Context.getSymbolRange().getLength() > 0) - Replacements->insert(Context.createSymbolReplacement(FilePath, 0)); + tool.run(&Factory); // Always succeeds. // Set up a new source manager for applying the resulting replacements. - IntrusiveRefCntPtr DiagOpts(new DiagnosticOptions); - DiagnosticsEngine Diagnostics(new DiagnosticIDs, &*DiagOpts); - TextDiagnosticPrinter DiagnosticPrinter(outs(), &*DiagOpts); - SourceManager SM(Diagnostics, tool.getFiles()); + llvm::IntrusiveRefCntPtr DiagOpts( + new clang::DiagnosticOptions); + clang::DiagnosticsEngine Diagnostics(new clang::DiagnosticIDs, &*DiagOpts); + clang::TextDiagnosticPrinter DiagnosticPrinter(llvm::outs(), &*DiagOpts); + clang::SourceManager source_manager(Diagnostics, tool.getFiles()); Diagnostics.setClient(&DiagnosticPrinter, false); - if (STDINMode) { - auto ChangedCode = - tooling::applyAllReplacements(Code->getBuffer(), *Replacements); - if (!ChangedCode) { - llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n"; - return 1; - } - llvm::outs() << *ChangedCode; - return 0; - } - // Write replacements to disk. - Rewriter Rewrites(SM, LangOptions()); - tooling::applyAllReplacements(*Replacements, Rewrites); + clang::Rewriter Rewrites(source_manager, clang::LangOptions()); + clang::tooling::applyAllReplacements(Replacements, Rewrites); return Rewrites.overwriteChangedFiles(); } - -} // namespace - -int main(int argc, const char **argv) { - return includeFixerMain(argc, argv); -} Index: include-fixer/tool/clang-include-fixer.py =================================================================== --- include-fixer/tool/clang-include-fixer.py +++ /dev/null @@ -1,149 +0,0 @@ -# This file is a minimal clang-include-fixer vim-integration. To install: -# - Change 'binary' if clang-include-fixer is not on the path (see below). -# - Add to your .vimrc: -# -# map ,cf :pyf path/to/llvm/source/tools/clang/tools/extra/include-fixer/tool/clang-include-fixer.py -# -# This enables clang-include-fixer for NORMAL and VISUAL mode. Change ",cf" to -# another binding if you need clang-include-fixer on a different key. -# -# To set up clang-include-fixer, see http://clang.llvm.org/extra/include-fixer.html -# -# With this integration you can press the bound key and clang-include-fixer will -# be run on the current buffer. -# -# It operates on the current, potentially unsaved buffer and does not create -# or save any files. To revert a fix, just undo. - -import argparse -import difflib -import subprocess -import vim -import json - -# set g:clang_include_fixer_path to the path to clang-include-fixer if it is not -# on the path. -# Change this to the full path if clang-include-fixer is not on the path. -binary = 'clang-include-fixer' -if vim.eval('exists("g:clang_include_fixer_path")') == "1": - binary = vim.eval('g:clang_include_fixer_path') - -maximum_suggested_headers = 3 -if vim.eval('exists("g:clang_include_fixer_maximum_suggested_headers")') == "1": - maximum_suggested_headers = max( - 1, - vim.eval('g:clang_include_fixer_maximum_suggested_headers')) - -increment_num = 5 -if vim.eval('exists("g:clang_include_fixer_increment_num")') == "1": - increment_num = max( - 1, - vim.eval('g:clang_include_fixer_increment_num')) - - -def GetUserSelection(message, headers, maximum_suggested_headers): - eval_message = message + '\n' - for idx, header in enumerate(headers[0:maximum_suggested_headers]): - eval_message += "({0}). {1}\n".format(idx + 1, header) - eval_message += "Enter (q) to quit;" - if maximum_suggested_headers < len(headers): - eval_message += " (m) to show {0} more candidates.".format( - min(increment_num, len(headers) - maximum_suggested_headers)) - - eval_message += "\nSelect (default 1): " - res = vim.eval("input('{0}')".format(eval_message)) - if res == '': - # choose the top ranked header by default - idx = 1 - elif res == 'q': - raise Exception(' Insertion cancelled...') - elif res == 'm': - return GetUserSelection(message, - headers, maximum_suggested_headers + increment_num) - else: - try: - idx = int(res) - if idx <= 0 or idx > len(headers): - raise Exception() - except Exception: - # Show a new prompt on invalid option instead of aborting so that users - # don't need to wait for another include-fixer run. - print >> sys.stderr, "Invalid option:", res - return GetUserSelection(message, headers, maximum_suggested_headers) - return headers[idx - 1] - - -def execute(command, text): - p = subprocess.Popen(command, - stdout=subprocess.PIPE, stderr=subprocess.PIPE, - stdin=subprocess.PIPE) - return p.communicate(input=text) - - -def InsertHeaderToVimBuffer(header, text): - command = [binary, "-stdin", "-insert-header=" + json.dumps(header), - vim.current.buffer.name] - stdout, stderr = execute(command, text) - if stdout: - lines = stdout.splitlines() - sequence = difflib.SequenceMatcher(None, vim.current.buffer, lines) - for op in reversed(sequence.get_opcodes()): - if op[0] is not 'equal': - vim.current.buffer[op[1]:op[2]] = lines[op[3]:op[4]] - - -def main(): - parser = argparse.ArgumentParser( - description='Vim integration for clang-include-fixer') - parser.add_argument('-db', default='yaml', - help='clang-include-fixer input format.') - parser.add_argument('-input', default='', - help='String to initialize the database.') - args = parser.parse_args() - - # Get the current text. - buf = vim.current.buffer - text = '\n'.join(buf) - - # Run command to get all headers. - command = [binary, "-stdin", "-output-headers", "-db=" + args.db, - "-input=" + args.input, vim.current.buffer.name] - stdout, stderr = execute(command, text) - if stderr: - print >> sys.stderr, "Error while running clang-include-fixer: " + stderr - return - - include_fixer_context = json.loads(stdout) - symbol = include_fixer_context["SymbolIdentifier"] - headers = include_fixer_context["Headers"] - - if not symbol: - print "The file is fine, no need to add a header.\n" - return - - if not headers: - print "Couldn't find a header for {0}.\n".format(symbol) - return - - # The first line is the symbol name. - # If there is only one suggested header, insert it directly. - if len(headers) == 1 or maximum_suggested_headers == 1: - InsertHeaderToVimBuffer({"SymbolIdentifier": symbol, - "Headers": [headers[0]]}, text) - print "Added #include {0} for {1}.\n".format(headers[0], symbol) - return - - try: - selected = GetUserSelection("choose a header file for {0}.".format(symbol), - headers, maximum_suggested_headers) - # Insert a selected header. - InsertHeaderToVimBuffer({"SymbolIdentifier": symbol, - "Headers": [selected]}, text) - print "Added #include {0} for {1}.\n".format(selected, symbol) - except Exception as error: - print >> sys.stderr, error.message - return - - -if __name__ == '__main__': - main() Index: test/CMakeLists.txt =================================================================== --- test/CMakeLists.txt +++ test/CMakeLists.txt @@ -42,11 +42,9 @@ # Individual tools we test. clang-apply-replacements - clang-include-fixer - clang-query clang-rename + clang-query clang-tidy - find-all-symbols modularize pp-trace Index: test/clang-rename/ClassTest.cpp =================================================================== --- test/clang-rename/ClassTest.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// RUN: cat %s > %t.cpp -// RUN: clang-rename -offset=138 -new-name=Hector %t.cpp -i -- -// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s -class Cla // CHECK: class Hector -{ -}; - -int main() -{ - Cla *Pointer = 0; // CHECK: Hector *Pointer = 0; - return 0; -} - -// Use grep -FUbo 'Cla' to get the correct offset of Cla when changing -// this file. Index: test/clang-rename/ClassTestByName.cpp =================================================================== --- test/clang-rename/ClassTestByName.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// RUN: cat %s > %t.cpp -// RUN: clang-rename -old-name=Cla -new-name=Hector %t.cpp -i -- -// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s -class Cla { // CHECK: class Hector -}; - -int main() { - Cla *Pointer = 0; // CHECK: Hector *Pointer = 0; - return 0; -} Index: test/clang-rename/ClassTestReplacements.cpp =================================================================== --- test/clang-rename/ClassTestReplacements.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// RUN: rm -rf %t -// RUN: mkdir -p %t/fixes -// RUN: cat %s > %t.cpp -// RUN: clang-rename -offset=256 -new-name=Hector -export-fixes=%t/fixes/clang-rename.yaml %t.cpp -- -// RUN: clang-apply-replacements %t -// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s -class Cla // CHECK: class Hector -{ -}; - -// Use grep -FUbo 'Cla' to get the correct offset of Cla when changing -// this file. Index: test/clang-rename/ConstCastExpr.cpp =================================================================== --- test/clang-rename/ConstCastExpr.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// RUN: cat %s > %t.cpp -// RUN: clang-rename -offset=133 -new-name=X %t.cpp -i -- -// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s -class Cla { -public: - int getValue() { - return 0; - } -}; - -int main() { - const Cla *C = new Cla(); - const_cast(C)->getValue(); // CHECK: const_cast -} - -// Use grep -FUbo 'Cla' to get the correct offset of foo when changing -// this file. Index: test/clang-rename/ConstructExpr.cpp =================================================================== --- test/clang-rename/ConstructExpr.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// RUN: cat %s > %t.cpp -// RUN: clang-rename -offset=133 -new-name=D %t.cpp -i -- -// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s -class Cla -{ -}; - -int main() -{ - Cla *C = new Cla(); // CHECK: D *C = new D(); -} - -// Use grep -FUbo 'Cla' to get the correct offset of foo when changing -// this file. Index: test/clang-rename/CtorDefTest.cpp =================================================================== --- test/clang-rename/CtorDefTest.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// RUN: cat %s > %t.cpp -// RUN: clang-rename -offset=133 -new-name=D %t.cpp -i -- -// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s -class C -{ -public: - C(); -}; - -C::C() // CHECK: D::D() -{ -} - -// Use grep -FUbo 'C' to get the correct offset of foo when changing -// this file. Index: test/clang-rename/CtorInitializerTest.cpp =================================================================== --- test/clang-rename/CtorInitializerTest.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// RUN: cat %s > %t.cpp -// RUN: clang-rename -offset=162 -new-name=hector %t.cpp -i -- -// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s -class A -{ -}; - -class Cla -{ - A foo; // CHECK: hector; -public: - Cla(); -}; - -Cla::Cla() // CHECK: Cla::Cla() -{ -} - -// Use grep -FUbo 'foo' to get the correct offset of foo when changing -// this file. Index: test/clang-rename/DeclRefExpr.cpp =================================================================== --- test/clang-rename/DeclRefExpr.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// RUN: cat %s > %t.cpp -// RUN: clang-rename -offset=158 -new-name=Y %t.cpp -i -- -// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s -class C -{ -public: - static int X; -}; - -int foo(int x) -{ - return 0; -} -#define FOO(a) foo(a) - -int main() -{ - C::X = 1; // CHECK: C::Y - FOO(C::X); // CHECK: C::Y - int y = C::X; // CHECK: C::Y -} - -// Use grep -FUbo 'X' to get the correct offset of foo when changing -// this file. Index: test/clang-rename/DtorDefTest.cpp =================================================================== --- test/clang-rename/DtorDefTest.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// RUN: cat %s > %t.cpp -// RUN: clang-rename -offset=135 -new-name=Bar %t.cpp -i -- -// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s -class Foo { -public: - Foo(); - ~Foo(); // CHECK: ~Bar(); -}; - -Foo::Foo() { -} - -Foo::~Foo() { // CHECK: Bar::~Bar() -} - -// Use grep -FUbo 'Foo' to get the correct offset of foo when changing -// this file. Index: test/clang-rename/DynamicCastExpr.cpp =================================================================== --- test/clang-rename/DynamicCastExpr.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// RUN: cat %s > %t.cpp -// RUN: clang-rename -offset=193 -new-name=X %t.cpp -i -- -frtti -// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s -class Base { - virtual int getValue() const = 0; -}; - -class Derived : public Base { -public: - int getValue() const { - return 0; - } -}; - -int main() { - Derived D; - const Base &Reference = D; - const Base *Pointer = &D; - - dynamic_cast(Reference).getValue(); // CHECK: dynamic_cast - dynamic_cast(Pointer)->getValue(); // CHECK: dynamic_cast -} - -// Use grep -FUbo 'Derived' to get the correct offset of foo when changing -// this file. Index: test/clang-rename/FieldTest.cpp =================================================================== --- test/clang-rename/FieldTest.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// RUN: cat %s > %t.cpp -// RUN: clang-rename -offset=150 -new-name=hector %t.cpp -i -- -// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s -class Cla -{ - int foo; // CHECK: hector; -public: - Cla(); -}; - -Cla::Cla() - : foo(0) // CHECK: hector(0) -{ -} - -// Use grep -FUbo 'foo' to get the correct offset of foo when changing -// this file. Index: test/clang-rename/MemberExprMacro.cpp =================================================================== --- test/clang-rename/MemberExprMacro.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// RUN: cat %s > %t.cpp -// RUN: clang-rename -offset=151 -new-name=Y %t.cpp -i -- -// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s -class C -{ -public: - int X; -}; - -int foo(int x) -{ - return 0; -} -#define FOO(a) foo(a) - -int main() -{ - C C; - C.X = 1; // CHECK: C.Y - FOO(C.X); // CHECK: C.Y - int y = C.X; // CHECK: C.Y -} - -// Use grep -FUbo 'C' to get the correct offset of foo when changing -// this file. Index: test/clang-rename/ReinterpretCastExpr.cpp =================================================================== --- test/clang-rename/ReinterpretCastExpr.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// RUN: cat %s > %t.cpp -// RUN: clang-rename -offset=133 -new-name=X %t.cpp -i -- -// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s -class Cla { -public: - int getValue() const { - return 0; - } -}; - -int main() { - void *C = new Cla(); - reinterpret_cast(C)->getValue(); // CHECK: reinterpret_cast -} - -// Use grep -FUbo 'Cla' to get the correct offset of foo when changing -// this file. Index: test/clang-rename/StaticCastExpr.cpp =================================================================== --- test/clang-rename/StaticCastExpr.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// RUN: cat %s > %t.cpp -// RUN: clang-rename -offset=150 -new-name=X %t.cpp -i -- -// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s -class Base { -}; - -class Derived : public Base { -public: - int getValue() const { - return 0; - } -}; - -int main() { - Derived D; - const Base &Reference = D; - const Base *Pointer = &D; - - static_cast(Reference).getValue(); // CHECK: static_cast - static_cast(Pointer)->getValue(); // CHECK: static_cast -} - -// Use grep -FUbo 'Derived' to get the correct offset of foo when changing -// this file. Index: test/clang-rename/VarTest.cpp =================================================================== --- test/clang-rename/VarTest.cpp +++ test/clang-rename/VarTest.cpp @@ -1,8 +1,8 @@ -// RUN: cat %s > %t.cpp -// RUN: clang-rename -offset=150 -new-name=hector %t.cpp -i -- -// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s namespace A { int foo; // CHECK: int hector; } +// RUN: cat %s > %t.cpp +// RUN: clang-rename -offset=18 -new-name=hector %t.cpp -i -- +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s int foo; // CHECK: int foo; int bar = foo; // CHECK: bar = foo; int baz = A::foo; // CHECK: baz = A::hector; Index: test/clang-tidy/boost-use-to-string.cpp =================================================================== --- test/clang-tidy/boost-use-to-string.cpp +++ /dev/null @@ -1,169 +0,0 @@ -// RUN: %check_clang_tidy %s boost-use-to-string %t - -namespace std { - -template -class basic_string {}; - -using string = basic_string; -using wstring = basic_string; -} - -namespace boost { -template -T lexical_cast(const V &) { - return T(); -}; -} - -struct my_weird_type {}; - -std::string fun(const std::string &) {} - -void test_to_string1() { - - auto xa = boost::lexical_cast(5); - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::to_string instead of boost::lexical_cast [boost-use-to-string] - // CHECK-FIXES: auto xa = std::to_string(5); - - auto z = boost::lexical_cast(42LL); - // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use std::to_string - // CHECK-FIXES: auto z = std::to_string(42LL); - - // this should not trigger - fun(boost::lexical_cast(42.0)); - auto non = boost::lexical_cast(42); - boost::lexical_cast("12"); -} - -void test_to_string2() { - int a; - long b; - long long c; - unsigned d; - unsigned long e; - unsigned long long f; - float g; - double h; - long double i; - bool j; - - fun(boost::lexical_cast(a)); - // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string - // CHECK-FIXES: fun(std::to_string(a)); - fun(boost::lexical_cast(b)); - // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string - // CHECK-FIXES: fun(std::to_string(b)); - fun(boost::lexical_cast(c)); - // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string - // CHECK-FIXES: fun(std::to_string(c)); - fun(boost::lexical_cast(d)); - // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string - // CHECK-FIXES: fun(std::to_string(d)); - fun(boost::lexical_cast(e)); - // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string - // CHECK-FIXES: fun(std::to_string(e)); - fun(boost::lexical_cast(f)); - // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string - // CHECK-FIXES: fun(std::to_string(f)); - - // No change for floating numbers. - fun(boost::lexical_cast(g)); - fun(boost::lexical_cast(h)); - fun(boost::lexical_cast(i)); - // And bool. - fun(boost::lexical_cast(j)); -} - -std::string fun(const std::wstring &) {} - -void test_to_wstring() { - int a; - long b; - long long c; - unsigned d; - unsigned long e; - unsigned long long f; - float g; - double h; - long double i; - bool j; - - fun(boost::lexical_cast(a)); - // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring instead of boost::lexical_cast [boost-use-to-string] - // CHECK-FIXES: fun(std::to_wstring(a)); - fun(boost::lexical_cast(b)); - // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring - // CHECK-FIXES: fun(std::to_wstring(b)); - fun(boost::lexical_cast(c)); - // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring - // CHECK-FIXES: fun(std::to_wstring(c)); - fun(boost::lexical_cast(d)); - // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring - // CHECK-FIXES: fun(std::to_wstring(d)); - fun(boost::lexical_cast(e)); - // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring - // CHECK-FIXES: fun(std::to_wstring(e)); - fun(boost::lexical_cast(f)); - // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring - // CHECK-FIXES: fun(std::to_wstring(f)); - - // No change for floating numbers - fun(boost::lexical_cast(g)); - fun(boost::lexical_cast(h)); - fun(boost::lexical_cast(i)); - // and bool. - fun(boost::lexical_cast(j)); -} - -const auto glob = boost::lexical_cast(42); -// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use std::to_string -// CHECK-FIXES: const auto glob = std::to_string(42); - -template -void string_as_T(T t = T()) { - boost::lexical_cast(42); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use std::to_string - // CHECK-FIXES: std::to_string(42); - - boost::lexical_cast(42); - string_as_T(boost::lexical_cast(42)); - auto p = boost::lexical_cast(42); - auto p2 = (T)boost::lexical_cast(42); - auto p3 = static_cast(boost::lexical_cast(42)); -} - -#define my_to_string boost::lexical_cast - -void no_fixup_inside_macro() { - my_to_string(12); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use std::to_string -} - -void no_warnings() { - fun(boost::lexical_cast("abc")); - fun(boost::lexical_cast("abc")); - fun(boost::lexical_cast(my_weird_type{})); - string_as_T(); - string_as_T(); -} - -struct Fields { - int integer; - float floating; - Fields* wierd; - const int &getConstInteger() const {return integer;} -}; - -void testFields() { - Fields fields; - auto s1 = boost::lexical_cast(fields.integer); - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::to_string - // CHECK-FIXES: auto s1 = std::to_string(fields.integer); - - auto s2 = boost::lexical_cast(fields.floating); - auto s3 = boost::lexical_cast(fields.wierd); - auto s4 = boost::lexical_cast(fields.getConstInteger()); - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::to_string - // CHECK-FIXES: auto s4 = std::to_string(fields.getConstInteger()); -} Index: test/clang-tidy/cert-err34-c.c =================================================================== --- test/clang-tidy/cert-err34-c.c +++ /dev/null @@ -1,103 +0,0 @@ -// RUN: %check_clang_tidy %s cert-err34-c %t -- -- -std=c11 - -typedef __SIZE_TYPE__ size_t; -typedef signed ptrdiff_t; -typedef long long intmax_t; -typedef unsigned long long uintmax_t; -typedef void * FILE; - -extern FILE *stdin; - -extern int fscanf(FILE * restrict stream, const char * restrict format, ...); -extern int scanf(const char * restrict format, ...); -extern int sscanf(const char * restrict s, const char * restrict format, ...); - -extern double atof(const char *nptr); -extern int atoi(const char *nptr); -extern long int atol(const char *nptr); -extern long long int atoll(const char *nptr); - -void f1(const char *in) { - int i; - long long ll; - unsigned int ui; - unsigned long long ull; - intmax_t im; - uintmax_t uim; - float f; - double d; - long double ld; - - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'sscanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c] - sscanf(in, "%d", &i); - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'fscanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtoll' instead [cert-err34-c] - fscanf(stdin, "%lld", &ll); - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'sscanf' used to convert a string to an unsigned integer value, but function will not report conversion errors; consider using 'strtoul' instead [cert-err34-c] - sscanf(in, "%u", &ui); - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'fscanf' used to convert a string to an unsigned integer value, but function will not report conversion errors; consider using 'strtoull' instead [cert-err34-c] - fscanf(stdin, "%llu", &ull); - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtoimax' instead [cert-err34-c] - scanf("%jd", &im); - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'fscanf' used to convert a string to an unsigned integer value, but function will not report conversion errors; consider using 'strtoumax' instead [cert-err34-c] - fscanf(stdin, "%ju", &uim); - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'sscanf' used to convert a string to a floating-point value, but function will not report conversion errors; consider using 'strtof' instead [cert-err34-c] - sscanf(in, "%f", &f); // to float - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'fscanf' used to convert a string to a floating-point value, but function will not report conversion errors; consider using 'strtod' instead [cert-err34-c] - fscanf(stdin, "%lg", &d); - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'sscanf' used to convert a string to a floating-point value, but function will not report conversion errors; consider using 'strtold' instead [cert-err34-c] - sscanf(in, "%Le", &ld); - - // These are conversions with other modifiers - short s; - char c; - size_t st; - ptrdiff_t pt; - - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert - scanf("%hhd", &c); - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert - scanf("%hd", &s); - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert - scanf("%zu", &st); - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert - scanf("%td", &pt); - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert - scanf("%o", ui); - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert - scanf("%X", ui); - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert - scanf("%x", ui); -} - -void f2(const char *in) { - // CHECK-MESSAGES: :[[@LINE+1]]:11: warning: 'atoi' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c] - int i = atoi(in); // to int - // CHECK-MESSAGES: :[[@LINE+1]]:12: warning: 'atol' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c] - long l = atol(in); // to long - // CHECK-MESSAGES: :[[@LINE+1]]:18: warning: 'atoll' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtoll' instead [cert-err34-c] - long long ll = atoll(in); // to long long - // CHECK-MESSAGES: :[[@LINE+1]]:14: warning: 'atof' used to convert a string to a floating-point value, but function will not report conversion errors; consider using 'strtod' instead [cert-err34-c] - double d = atof(in); // to double -} - -void f3(void) { - int i; - unsigned int u; - float f; - char str[32]; - - // Test that we don't report multiple infractions for a single call. - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert - scanf("%d%u%f", &i, &u, &f); - - // Test that we still catch infractions that are not the first specifier. - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert - scanf("%s%d", str, &i); -} - -void do_not_diagnose(void) { - char str[32]; - - scanf("%s", str); // Not a numerical conversion - scanf("%*d"); // Assignment suppressed -} Index: test/clang-tidy/cert-err34-c.cpp =================================================================== --- test/clang-tidy/cert-err34-c.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// RUN: %check_clang_tidy %s cert-err34-c %t -- -- -std=c++11 - -typedef void * FILE; - -extern FILE *stdin; - -extern int fscanf(FILE * stream, const char * format, ...); -extern int sscanf(const char * s, const char * format, ...); - -extern double atof(const char *nptr); -extern int atoi(const char *nptr); -extern long int atol(const char *nptr); -extern long long int atoll(const char *nptr); - -namespace std { -using ::FILE; using ::stdin; -using ::fscanf; using ::sscanf; -using ::atof; using ::atoi; using ::atol; using ::atoll; -} - -void f1(const char *in) { - int i; - long long ll; - - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'sscanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c] - std::sscanf(in, "%d", &i); - // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'fscanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtoll' instead [cert-err34-c] - std::fscanf(std::stdin, "%lld", &ll); -} - -void f2(const char *in) { - // CHECK-MESSAGES: :[[@LINE+1]]:11: warning: 'atoi' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c] - int i = std::atoi(in); // to int - // CHECK-MESSAGES: :[[@LINE+1]]:12: warning: 'atol' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c] - long l = std::atol(in); // to long - - using namespace std; - - // CHECK-MESSAGES: :[[@LINE+1]]:18: warning: 'atoll' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtoll' instead [cert-err34-c] - long long ll = atoll(in); // to long long - // CHECK-MESSAGES: :[[@LINE+1]]:14: warning: 'atof' used to convert a string to a floating-point value, but function will not report conversion errors; consider using 'strtod' instead [cert-err34-c] - double d = atof(in); // to double -} Index: test/clang-tidy/cert-limited-randomness.cpp =================================================================== --- /dev/null +++ test/clang-tidy/cert-limited-randomness.cpp @@ -0,0 +1,28 @@ +// RUN: %check_clang_tidy %s cert-msc50-cpp %t + +int rand(); +int rand(int); + +namespace std { +using ::rand; +} + +namespace nonstd { + int rand(); +} + +void testFunction1() { + int i = std::rand(); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: rand() function has limited randomness, use C++11 random library instead [cert-msc50-cpp] + + int j = ::rand(); + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: rand() function has limited randomness, use C++11 random library instead [cert-msc50-cpp] + + int k = rand(i); + + int l = nonstd::rand(); + + int m = rand(); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: rand() function has limited randomness, use C++11 random library instead [cert-msc50-cpp] +} + Index: test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp =================================================================== --- test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp +++ test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -- -std=c++98 -fno-delayed-template-parsing +// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -- -std=c++98 struct PositiveFieldBeforeConstructor { int F; @@ -103,14 +103,3 @@ int X; }; - -class PositiveIndirectMember { - struct { - int *A; - }; - - PositiveIndirectMember() : A() {} - PositiveIndirectMember(int) {} - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A - // CHECK-FIXES: PositiveIndirectMember(int) : A() {} -}; Index: test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp =================================================================== --- test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp +++ test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -- -std=c++11 -fno-delayed-template-parsing +// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t struct PositiveFieldBeforeConstructor { int F; @@ -85,14 +85,6 @@ int I; }; -struct A {}; -template class AA; -template class NegativeTemplateConstructor { - NegativeTemplateConstructor(const AA &, A) {} - bool Bool{false}; - // CHECK-FIXES: bool Bool{false}; -}; - #define UNINITIALIZED_FIELD_IN_MACRO_BODY(FIELD) \ struct UninitializedField##FIELD { \ UninitializedField##FIELD() {} \ @@ -183,14 +175,17 @@ ComplexNonTrivialType T; } -struct NegativeStaticMember { +struct PositiveStaticMember { static NonTrivialType X; static NonTrivialType Y; static constexpr NonTrivialType Z{}; }; -NonTrivialType NegativeStaticMember::X; -NonTrivialType NegativeStaticMember::Y{}; +NonTrivialType PositiveStaticMember::X; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: uninitialized record type: 'X' +// CHECK-FIXES: NonTrivialType PositiveStaticMember::X{}; + +NonTrivialType PositiveStaticMember::Y{}; struct PositiveMultipleConstructors { PositiveMultipleConstructors() {} @@ -247,7 +242,9 @@ int F; }; -static InheritedAggregate NegativeGlobal; +static InheritedAggregate PositiveGlobal; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: uninitialized record type: 'PositiveGlobal' +// CHECK-FIXES: InheritedAggregate PositiveGlobal{}; enum TestEnum { A, @@ -283,11 +280,6 @@ } } -static void NegativeStaticVariable() { - static NegativeCStruct S; - (void)S; -} - union NegativeUnionInClass { NegativeUnionInClass() {} // No message as a union can only initialize one member. int X = 0; @@ -346,24 +338,3 @@ Template F; }; - -// This pathological template fails to compile if actually instantiated. It -// results in the check seeing a null RecordDecl when examining the base class -// initializer list. -template -class PositiveSelfInitialization : NegativeAggregateType -{ - PositiveSelfInitialization() : PositiveSelfInitialization() {} - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: NegativeAggregateType - // CHECK-FIXES: PositiveSelfInitialization() : NegativeAggregateType(), PositiveSelfInitialization() {} -}; - -class PositiveIndirectMember { - struct { - int *A; - // CHECK-FIXES: int *A{}; - }; - - PositiveIndirectMember() {} - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A -}; Index: test/clang-tidy/cppcoreguidelines-pro-type-vararg.cpp =================================================================== --- test/clang-tidy/cppcoreguidelines-pro-type-vararg.cpp +++ test/clang-tidy/cppcoreguidelines-pro-type-vararg.cpp @@ -15,7 +15,7 @@ f_vararg(1, 7, 9); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not call c-style vararg functions [cppcoreguidelines-pro-type-vararg] c.g_vararg("foo"); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not call c-style vararg functions + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not call c-style vararg functions f(3); // OK c.g("foo"); // OK Index: test/clang-tidy/explain-checks.cpp =================================================================== --- test/clang-tidy/explain-checks.cpp +++ test/clang-tidy/explain-checks.cpp @@ -1,9 +1,9 @@ // RUN: clang-tidy -checks=-*,modernize-use-nullptr -explain-config | FileCheck --check-prefix=CHECK-MESSAGE1 %s // RUN: clang-tidy -config="{Checks: '-*,modernize-use-nullptr'}" -explain-config | FileCheck --check-prefix=CHECK-MESSAGE2 %s // RUN: clang-tidy -checks=modernize-use-nullptr -config="{Checks: '-*,modernize-use-nullptr'}" -explain-config | FileCheck --check-prefix=CHECK-MESSAGE3 %s -// RUN: clang-tidy -checks=modernize-use-nullptr -config="{Checks: '-*,-modernize-use-nullptr'}" %S/Inputs/explain-config/a.cc -explain-config -- | FileCheck --check-prefix=CHECK-MESSAGE4 %s +// RUN: clang-tidy -checks=modernize-use-nullptr -config="{Checks: '-*,-modernize-use-nullptr'}" %S/Inputs/explain-config/a.cc -explain-config | FileCheck --check-prefix=CHECK-MESSAGE4 %s // RUN: clang-tidy -checks=modernize-use-nullptr -config="{Checks: '-*,modernize-*'}" -explain-config | FileCheck --check-prefix=CHECK-MESSAGE5 %s -// RUN: clang-tidy -explain-config %S/Inputs/explain-config/a.cc -- | grep "'modernize-use-nullptr' is enabled in the .*[/\\]Inputs[/\\]explain-config[/\\].clang-tidy." +// RUN: clang-tidy -explain-config %S/Inputs/explain-config/a.cc -- | grep "'modernize-use-nullptr' is enabled in the %S/Inputs/explain-config/.clang-tidy." // CHECK-MESSAGE1: 'modernize-use-nullptr' is enabled in the command-line option '-checks'. // CHECK-MESSAGE2: 'modernize-use-nullptr' is enabled in the command-line option '-config'. Index: test/clang-tidy/google-default-arguments.cpp =================================================================== --- test/clang-tidy/google-default-arguments.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// RUN: %check_clang_tidy %s google-default-arguments %t - -struct A { - virtual void f(int I, int J = 3); - // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: default arguments on virtual or override methods are prohibited [google-default-arguments] -}; - -struct B : public A { - void f(int I, int J = 5); - // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: default arguments on virtual or override methods are prohibited -}; - -struct C : public B { - void f(int I, int J = 5) override; - // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: default arguments on virtual or override methods are prohibited -}; - -// Negatives. -struct D : public B { - void f(int I, int J) override; -}; - -struct X { - void f(int I, int J = 3); -}; - -struct Y : public X { - void f(int I, int J = 5); -}; Index: test/clang-tidy/list-checks.cpp =================================================================== --- test/clang-tidy/list-checks.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// REQUIRES: shell -// RUN: mkdir -p %T/clang-tidy/list-checks/ -// RUN: echo '{Checks: "-*,google-*"}' > %T/clang-tidy/.clang-tidy -// RUN: cd %T/clang-tidy/list-checks -// RUN: clang-tidy -list-checks | grep "^ *google-" Index: test/clang-tidy/misc-argument-comment.cpp =================================================================== --- test/clang-tidy/misc-argument-comment.cpp +++ test/clang-tidy/misc-argument-comment.cpp @@ -12,7 +12,6 @@ // CHECK-MESSAGES: [[@LINE+2]]:14: warning: argument name 'z' in comment does not match parameter name 'y' // CHECK-MESSAGES: :[[@LINE-5]]:19: note: 'y' declared here f(/*y=*/0, /*z=*/0); - // CHECK-FIXES: {{^}} f(/*y=*/0, /*z=*/0); } struct Closure {}; @@ -38,11 +37,4 @@ variadic(/*xxx=*/0, /*yyy=*/1); variadic2(/*zzZ=*/0, /*xxx=*/1, /*yyy=*/2); // CHECK-MESSAGES: [[@LINE-1]]:13: warning: argument name 'zzZ' in comment does not match parameter name 'zzz' - // CHECK-FIXES: variadic2(/*zzz=*/0, /*xxx=*/1, /*yyy=*/2); } - -#define FALSE 0 -void qqq(bool aaa); -void f() { qqq(/*bbb=*/FALSE); } -// CHECK-MESSAGES: [[@LINE-1]]:16: warning: argument name 'bbb' in comment does not match parameter name 'aaa' -// CHECK-FIXES: void f() { qqq(/*bbb=*/FALSE); } Index: test/clang-tidy/misc-assign-operator-signature.cpp =================================================================== --- /dev/null +++ test/clang-tidy/misc-assign-operator-signature.cpp @@ -0,0 +1,75 @@ +// RUN: %check_clang_tidy %s misc-assign-operator-signature %t + +struct Good { + Good& operator=(const Good&); + Good& operator=(Good&&); + + // Assign from other types is fine too. + Good& operator=(int); +}; + +struct AlsoGood { + // By value is also fine. + AlsoGood& operator=(AlsoGood); +}; + +struct BadReturn { + void operator=(const BadReturn&); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'BadReturn&' [misc-assign-operator-signature] + const BadReturn& operator=(BadReturn&&); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad + void operator=(int); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad +}; +struct BadReturn2 { + BadReturn2&& operator=(const BadReturn2&); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad + int operator=(BadReturn2&&); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad +}; + +struct BadArgument { + BadArgument& operator=(BadArgument&); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should take 'BadArgument const&', 'BadArgument&&' or 'BadArgument' + BadArgument& operator=(const BadArgument&&); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should take 'BadAr +}; + +struct BadModifier { + BadModifier& operator=(const BadModifier&) const; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should not be marked 'const' +}; + +struct Deleted { + // We don't check the return value of deleted operators. + void operator=(const Deleted&) = delete; + void operator=(Deleted&&) = delete; +}; + +class Private { + // We don't check the return value of private operators. + // Pre-C++11 way of disabling assignment. + void operator=(const Private &); +}; + +struct Virtual { + virtual Virtual& operator=(const Virtual &); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should not be marked 'virtual' +}; + +struct NoReturn { + int member; + + NoReturn &operator=(const NoReturn &rhs) { + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: operator=() should return *this + this->member = rhs.member; + } +}; + +struct ReturnOtherThanThis { + ReturnOtherThanThis& operator=(const ReturnOtherThanThis& rhs) { + return const_cast(rhs); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: operator=() should return *this + } +}; + Index: test/clang-tidy/misc-definitions-in-headers.hpp =================================================================== --- test/clang-tidy/misc-definitions-in-headers.hpp +++ test/clang-tidy/misc-definitions-in-headers.hpp @@ -103,8 +103,6 @@ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: function 'f7' defined in a header file; } -int f8() = delete; // OK: the function being marked delete is not callable. - int a = 1; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: variable 'a' defined in a header file; variable definitions in header files can lead to ODR violations [misc-definitions-in-headers] CA a1; Index: test/clang-tidy/misc-macro-parentheses.cpp =================================================================== --- test/clang-tidy/misc-macro-parentheses.cpp +++ test/clang-tidy/misc-macro-parentheses.cpp @@ -8,8 +8,6 @@ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: macro argument should be enclosed in parentheses [misc-macro-parentheses] #define BAD4(x) ((unsigned char)(x & 0xff)) // CHECK-MESSAGES: :[[@LINE-1]]:44: warning: macro argument should be enclosed in parentheses [misc-macro-parentheses] -#define BAD5(X) A*B=(C*)X+2 -// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: macro argument should be enclosed in parentheses [misc-macro-parentheses] #define GOOD1 1 #define GOOD2 (1+2) @@ -38,11 +36,6 @@ #define GOOD25(t) std::set s #define GOOD26(x) (a->*x) #define GOOD27(x) (a.*x) -#define GOOD28(x) namespace x {int b;} -#define GOOD29(...) std::cout << __VA_ARGS__; -#define GOOD30(args...) std::cout << args; -#define GOOD31(X) A*X=2 -#define GOOD32(X) std::vector // These are allowed for now.. #define MAYBE1 *12.34 Index: test/clang-tidy/misc-misplaced-const.c =================================================================== --- test/clang-tidy/misc-misplaced-const.c +++ /dev/null @@ -1,45 +0,0 @@ -// RUN: %check_clang_tidy %s misc-misplaced-const %t - -typedef int plain_i; -typedef int *ip; -typedef const int *cip; - -typedef void (*func_ptr)(void); - -void func(void) { - // ok - const int *i0 = 0; - const plain_i *i1 = 0; - const cip i2 = 0; // const applies to both pointer and pointee. - - // Not ok - const ip i3 = 0; - // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'i3' declared with a const-qualified typedef type; results in the type being 'int *const' instead of 'const int *' - - ip const i4 = 0; - // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'i4' declared with a const-qualified - - const volatile ip i5 = 0; - // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: 'i5' declared with a const-qualified typedef type; results in the type being 'int *const volatile' instead of 'const int *volatile' -} - -void func2(const plain_i *i1, - const cip i2, - const ip i3, - // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: 'i3' declared with a const-qualified - const int *i4) { -} - -struct S { - const int *i0; - const plain_i *i1; - const cip i2; - const ip i3; - // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'i3' declared with a const-qualified -}; - -// Function pointers should not be diagnosed because a function -// pointer type can never be const. -void func3(const func_ptr fp) { - const func_ptr fp2 = fp; -} Index: test/clang-tidy/misc-misplaced-const.cpp =================================================================== --- test/clang-tidy/misc-misplaced-const.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// RUN: %check_clang_tidy %s misc-misplaced-const %t - -typedef int plain_i; -typedef int *ip; -typedef const int *cip; - -void func() { - if (const int *i = 0) - ; - if (const plain_i *i = 0) - ; - if (const cip i = 0) - ; - - // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: 'i' declared with a const-qualified typedef type; results in the type being 'int *const' instead of 'const int *' - if (const ip i = 0) - ; -} - -template -struct S { - const Ty *i; - const Ty &i2; -}; - -template struct S; -template struct S; // ok -template struct S; - -template -struct U { - const Ty *i; - const Ty &i2; -}; - -template struct U; // ok - -struct T { - typedef void (T::*PMF)(); - - void f() { - const PMF val = &T::f; // ok - } -}; Index: test/clang-tidy/misc-move-const-arg.cpp =================================================================== --- test/clang-tidy/misc-move-const-arg.cpp +++ test/clang-tidy/misc-move-const-arg.cpp @@ -71,90 +71,3 @@ f10(1); f10(1); } - -class NoMoveSemantics { - public: - NoMoveSemantics(); - NoMoveSemantics(const NoMoveSemantics &); - - NoMoveSemantics &operator=(const NoMoveSemantics &); -}; - -void callByConstRef(const NoMoveSemantics &); -void callByConstRef(int i, const NoMoveSemantics &); - -void moveToConstReferencePositives() { - NoMoveSemantics obj; - - // Basic case. - callByConstRef(std::move(obj)); - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as - // CHECK-FIXES: callByConstRef(obj); - - // Also works for second argument. - callByConstRef(1, std::move(obj)); - // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: passing result of std::move() as - // CHECK-FIXES: callByConstRef(1, obj); - - // Works if std::move() applied to a temporary. - callByConstRef(std::move(NoMoveSemantics())); - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as - // CHECK-FIXES: callByConstRef(NoMoveSemantics()); - - // Works if calling a copy constructor. - NoMoveSemantics other(std::move(obj)); - // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: passing result of std::move() as - // CHECK-FIXES: NoMoveSemantics other(obj); - - // Works if calling assignment operator. - other = std::move(obj); - // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing result of std::move() as - // CHECK-FIXES: other = obj; -} - -class MoveSemantics { - public: - MoveSemantics(); - MoveSemantics(MoveSemantics &&); - - MoveSemantics &operator=(MoveSemantics &&); -}; - -void callByValue(MoveSemantics); - -void callByRValueRef(MoveSemantics &&); - -template -void templateFunction(T obj) { - T other = std::move(obj); -} - -#define M3(T, obj) \ - do { \ - T other = std::move(obj); \ - } while (true) - -#define CALL(func) (func)() - -void moveToConstReferenceNegatives() { - // No warning when actual move takes place. - MoveSemantics move_semantics; - callByValue(std::move(move_semantics)); - callByRValueRef(std::move(move_semantics)); - MoveSemantics other(std::move(move_semantics)); - other = std::move(move_semantics); - - // No warning if std::move() not used. - NoMoveSemantics no_move_semantics; - callByConstRef(no_move_semantics); - - // No warning if instantiating a template. - templateFunction(no_move_semantics); - - // No warning inside of macro expansions. - M3(NoMoveSemantics, no_move_semantics); - - // No warning inside of macro expansion, even if the macro expansion is inside - // a lambda that is, in turn, an argument to a macro. - CALL([no_move_semantics] { M3(NoMoveSemantics, no_move_semantics); }); -} Index: test/clang-tidy/misc-move-constructor-init.cpp =================================================================== --- test/clang-tidy/misc-move-constructor-init.cpp +++ test/clang-tidy/misc-move-constructor-init.cpp @@ -96,7 +96,7 @@ struct Positive { Positive(Movable M) : M_(M) {} - // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument 'M' can be moved to avoid copy [misc-move-constructor-init] + // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument can be moved to avoid copy [misc-move-constructor-init] // CHECK-FIXES: Positive(Movable M) : M_(std::move(M)) {} Movable M_; }; Index: test/clang-tidy/misc-redundant-expression.cpp =================================================================== --- test/clang-tidy/misc-redundant-expression.cpp +++ test/clang-tidy/misc-redundant-expression.cpp @@ -1,6 +1,4 @@ -// RUN: %check_clang_tidy %s misc-redundant-expression %t -- -- -std=c++11 - -typedef __INT64_TYPE__ I64; +// RUN: %check_clang_tidy %s misc-redundant-expression %t struct Point { int x; @@ -66,25 +64,25 @@ if ( + "dummy" == + "dummy") return 1; // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: both side of operator are equivalent - if (L"abc" == L"abc") return 1; + if (L"abc" == L"abc") return 1; // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: both side of operator are equivalent if (foo(0) - 2 < foo(0) - 2) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: both side of operator are equivalent + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: both side of operator are equivalent if (foo(bar(0)) < (foo(bar((0))))) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: both side of operator are equivalent + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: both side of operator are equivalent if (P1.x < P2.x && P1.x < P2.x) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: both side of operator are equivalent + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: both side of operator are equivalent if (P2.a[P1.x + 2] < P2.x && P2.a[(P1.x) + (2)] < (P2.x)) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: both side of operator are equivalent + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: both side of operator are equivalent return 0; } int Valid(int X, int Y) { if (X != Y) return 1; - if (X == Y + 0) return 1; + if (X == X + 0) return 1; if (P.x == P.y) return 1; if (P.a[P.x] < P.a[P.y]) return 1; if (P.a[0] < P.a[1]) return 1; @@ -102,36 +100,13 @@ return 0; } -int TestConditional(int x, int y) { - int k = 0; - k += (y < 0) ? x : x; - // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: 'true' and 'false' expression are equivalent - k += (y < 0) ? x + 1 : x + 1; - // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: 'true' and 'false' expression are equivalent - return k; -} - -struct MyStruct { - int x; -} Q; -bool operator==(const MyStruct& lhs, const MyStruct& rhs) { return lhs.x == rhs.x; } -bool TestOperator(const MyStruct& S) { - if (S == Q) return false; - return S == S; - // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: both side of overloaded operator are equivalent -} - #define LT(x, y) (void)((x) < (y)) -#define COND(x, y, z) ((x)?(y):(z)) -#define EQUALS(x, y) (x) == (y) int TestMacro(int X, int Y) { LT(0, 0); LT(1, 0); LT(X, X); LT(X+1, X + 1); - COND(X < Y, X, X); - EQUALS(Q, Q); } int TestFalsePositive(int* A, int X, float F) { @@ -143,343 +118,3 @@ if (F != F && F == F) return 1; return 0; } - -int TestBannedMacros() { -#define EAGAIN 3 -#define NOT_EAGAIN 3 - if (EAGAIN == 0 | EAGAIN == 0) return 0; - if (NOT_EAGAIN == 0 | NOT_EAGAIN == 0) return 0; - // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: both side of operator are equivalent -} - -struct MyClass { -static const int Value = 42; -}; -template -void TemplateCheck() { - static_assert(T::Value == U::Value, "should be identical"); - static_assert(T::Value == T::Value, "should be identical"); - // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: both side of overloaded operator are equivalent -} -void TestTemplate() { TemplateCheck(); } - -int TestArithmetic(int X, int Y) { - if (X + 1 == X) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false - if (X + 1 != X) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true - if (X - 1 == X) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false - if (X - 1 != X) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true - - if (X + 1LL == X) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false - if (X + 1ULL == X) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: logical expression is always false - - if (X == X + 1) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always false - if (X != X + 1) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always true - if (X == X - 1) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always false - if (X != X - 1) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always true - - if (X != X - 1U) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always true - if (X != X - 1LL) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always true - - if ((X+X) != (X+X) - 1) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true - - if (X + 1 == X + 2) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false - if (X + 1 != X + 2) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true - - if (X - 1 == X - 2) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false - if (X - 1 != X - 2) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true - - if (X + 1 == X - -1) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true - if (X + 1 != X - -1) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false - if (X + 1 == X - -2) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false - if (X + 1 != X - -2) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true - - if (X + 1 == X - (~0)) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true - if (X + 1 == X - (~0U)) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true - if (X + 1 == X - (~0ULL)) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true - - // Should not match. - if (X + 0.5 == X) return 1; - if (X + 1 == Y) return 1; - if (X + 1 == Y + 1) return 1; - if (X + 1 == Y + 2) return 1; - - return 0; -} - -int TestBitwise(int X) { - if ((X & 0xFF) == 0xF00) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false - if ((X & 0xFF) != 0xF00) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always true - if ((X | 0xFF) == 0xF00) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false - if ((X | 0xFF) != 0xF00) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always true - - if ((X | 0xFFULL) != 0xF00) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: logical expression is always true - if ((X | 0xFF) != 0xF00ULL) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always true - - if ((0xFF & X) == 0xF00) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false - if ((0xFF & X) != 0xF00) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always true - if ((0xFF & X) == 0xF00) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false - if ((0xFF & X) != 0xF00) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always true - - if ((0xFFLL & X) == 0xF00) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: logical expression is always false - if ((0xFF & X) == 0xF00ULL) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false - - return 0; -} - -int TestRelational(int X, int Y) { - if (X == 10 && X != 10) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false - if (X == 10 && (X != 10)) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false - if (X == 10 && !(X == 10)) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false - if (!(X != 10) && !(X == 10)) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false - - if (X == 10ULL && X != 10ULL) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false - if (!(X != 10U) && !(X == 10)) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: logical expression is always false - if (!(X != 10LL) && !(X == 10)) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: logical expression is always false - if (!(X != 10ULL) && !(X == 10)) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: logical expression is always false - - if (X == 0 && X) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false - if (X != 0 && !X) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false - if (X && !X) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always false - - if (X && !!X) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: equivalent expression on both side of logical operator - if (X != 0 && X) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: equivalent expression on both side of logical operator - if (X != 0 && !!X) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: equivalent expression on both side of logical operator - if (X == 0 && !X) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: equivalent expression on both side of logical operator - - if (X == 10 && X > 10) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false - if (X == 10 && X < 10) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false - if (X < 10 && X > 10) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false - if (X <= 10 && X > 10) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false - if (X < 10 && X >= 10) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false - if (X < 10 && X == 10) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false - - if (X > 5 && X <= 5) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false - if (X > -5 && X <= -5) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false - - if (X < 10 || X >= 10) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always true - if (X <= 10 || X > 10) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always true - if (X <= 10 || X >= 11) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always true - - if (X < 7 && X < 6) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant - if (X < 7 && X < 7) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both side of operator are equivalent - if (X < 7 && X < 8) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: expression is redundant - - if (X < 7 && X <= 5) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant - if (X < 7 && X <= 6) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: equivalent expression on both side of logical operator - if (X < 7 && X <= 7) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: expression is redundant - if (X < 7 && X <= 8) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: expression is redundant - - if (X <= 7 && X < 6) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant - if (X <= 7 && X < 7) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant - if (X <= 7 && X < 8) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: equivalent expression on both side of logical operator - - if (X <= 7 && X <= 5) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant - if (X <= 7 && X <= 6) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant - if (X <= 7 && X <= 7) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: both side of operator are equivalent - if (X <= 7 && X <= 8) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: expression is redundant - - if (X == 11 && X > 10) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: expression is redundant - if (X == 11 && X < 12) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: expression is redundant - if (X > 10 && X == 11) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant - if (X < 12 && X == 11) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant - - if (X != 11 && X == 42) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant - if (X != 11 && X > 11) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant - if (X != 11 && X < 11) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant - if (X != 11 && X < 8) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant - if (X != 11 && X > 14) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant - - if (X < 7 || X < 6) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: expression is redundant - if (X < 7 || X < 7) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both side of operator are equivalent - if (X < 7 || X < 8) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant - - // Should not match. - if (X == 10 && Y == 10) return 1; - if (X != 10 && X != 12) return 1; - if (X == 10 || X == 12) return 1; - if (X < 10 || X > 12) return 1; - if (X > 10 && X < 12) return 1; - if (X < 10 || X >= 12) return 1; - if (X > 10 && X <= 12) return 1; - if (X <= 10 || X > 12) return 1; - if (X >= 10 && X < 12) return 1; - if (X <= 10 || X >= 12) return 1; - if (X >= 10 && X <= 12) return 1; - if (X >= 10 && X <= 11) return 1; - if (X >= 10 && X < 11) return 1; - if (X > 10 && X <= 11) return 1; - if (X > 10 && X != 11) return 1; - if (X >= 10 && X <= 10) return 1; - if (X <= 10 && X >= 10) return 1; - if (!X && !Y) return 1; - if (!X && Y) return 1; - if (!X && Y == 0) return 1; - if (X == 10 && Y != 10) return 1; - if (X < 0 || X > 0) return 1; - - return 0; -} - -int TestValidExpression(int X) { - if (X - 1 == 1 - X) return 1; - if (2 * X == X) return 1; - if ((X << 1) == X) return 1; - - return 0; -} - -enum Color { Red, Yellow, Green }; -int TestRelatiopnalWithEnum(enum Color C) { - if (C == Red && C == Yellow) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: logical expression is always false - if (C == Red && C != Red) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: logical expression is always false - - // Should not match. - if (C == Red || C == Yellow) return 1; - if (C != Red && C != Yellow) return 1; - - return 0; -} - -template -int TestRelationalTemplated(int X) { - // This test causes a corner case with |isIntegerConstantExpr| where the type - // is dependant. There is an assert failing when evaluating - // sizeof(). - if (sizeof(T) == 4 || sizeof(T) == 8) return 1; - - if (X + 0 == -X) return 1; - if (X + 0 < X) return 1; - - return 0; -} - -int TestWithSignedUnsigned(int X) { - if (X + 1 == X + 1ULL) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true - if ((X & 0xFFU) == 0xF00) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: logical expression is always false - if ((X & 0xFF) == 0xF00U) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false - if ((X & 0xFFU) == 0xF00U) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: logical expression is always false - - return 0; -} - -int TestWithLong(int X, I64 Y) { - if (X + 0ULL == -X) return 1; - if (Y + 0 == -Y) return 1; - if (Y <= 10 && X >= 10LL) return 1; - if (Y <= 10 && X >= 10ULL) return 1; - if (X <= 10 || X > 12LL) return 1; - if (X <= 10 || X > 12ULL) return 1; - if (Y <= 10 || Y > 12) return 1; - - return 0; -} - -int TestWithMinMaxInt(int X) { - if (X <= X + 0xFFFFFFFFU) return 1; - if (X <= X + 0x7FFFFFFF) return 1; - if (X <= X + 0x80000000) return 1; - if (X <= 0xFFFFFFFFU && X > 0) return 1; - if (X <= 0xFFFFFFFFU && X > 0U) return 1; - - if (X + 0x80000000 == X - 0x80000000) return 1; - // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: logical expression is always true - - if (X > 0x7FFFFFFF || X < ((-0x7FFFFFFF)-1)) return 1; - if (X <= 0x7FFFFFFF && X >= ((-0x7FFFFFFF)-1)) return 1; - - return 0; -} Index: test/clang-tidy/misc-string-constructor.cpp =================================================================== --- test/clang-tidy/misc-string-constructor.cpp +++ test/clang-tidy/misc-string-constructor.cpp @@ -21,11 +21,9 @@ void Test() { std::string str('x', 4); - // CHECK-MESSAGES: [[@LINE-1]]:15: warning: string constructor parameters are probably swapped; expecting string(count, character) [misc-string-constructor] - // CHECK-FIXES: std::string str(4, 'x'); + // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructor parameters are probably swapped [misc-string-constructor] std::wstring wstr(L'x', 4); - // CHECK-MESSAGES: [[@LINE-1]]:16: warning: string constructor parameters are probably swapped - // CHECK-FIXES: std::wstring wstr(4, L'x'); + // CHECK-MESSAGES: [[@LINE-1]]:16: warning: constructor parameters are probably swapped std::string s0(0, 'x'); // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructor creating an empty string std::string s1(-4, 'x'); Index: test/clang-tidy/misc-swapped-arguments.cpp =================================================================== --- test/clang-tidy/misc-swapped-arguments.cpp +++ test/clang-tidy/misc-swapped-arguments.cpp @@ -22,7 +22,8 @@ double b = 1.0; F(b, M(Some, Function)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments. -// CHECK-FIXES: F(M(Some, Function), b); +// In macro, don't emit fixits. +// CHECK-FIXES: F(b, M(Some, Function)); #define N F(b, SomeFunction()) @@ -39,15 +40,4 @@ F(3, 1.0); // no-warning F(true, false); // no-warning F(0, 'c'); // no-warning - -#define APPLY(f, x, y) f(x, y) - APPLY(F, 1.0, 3); -// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments. -// CHECK-FIXES: APPLY(F, 3, 1.0); - -#define PARAMS 1.0, 3 -#define CALL(P) F(P) - CALL(PARAMS); -// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments. -// In macro, don't emit fixits. } Index: test/clang-tidy/misc-unconventional-assign-operator.cpp =================================================================== --- test/clang-tidy/misc-unconventional-assign-operator.cpp +++ /dev/null @@ -1,89 +0,0 @@ -// RUN: %check_clang_tidy %s misc-unconventional-assign-operator %t -- -- -std=c++11 -isystem %S/Inputs/Headers - -namespace std { -template -struct remove_reference { typedef T type; }; -template -struct remove_reference { typedef T type; }; -template -struct remove_reference { typedef T type; }; -template -typename remove_reference::type &&move(T &&t); -} - - -struct Good { - Good& operator=(const Good&); - Good& operator=(Good&&); - - // Assign from other types is fine too. - Good& operator=(int); -}; - -struct AlsoGood { - // By value is also fine. - AlsoGood& operator=(AlsoGood); -}; - -struct BadReturnType { - void operator=(const BadReturnType&); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'BadReturnType&' [misc-unconventional-assign-operator] - const BadReturnType& operator=(BadReturnType&&); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad - void operator=(int); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad -}; - -struct BadReturnType2 { - BadReturnType2&& operator=(const BadReturnType2&); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad - int operator=(BadReturnType2&&); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad -}; - -struct BadArgument { - BadArgument& operator=(BadArgument&); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should take 'BadArgument const&', 'BadArgument&&' or 'BadArgument' - BadArgument& operator=(const BadArgument&&); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should take 'BadAr -}; - -struct BadModifier { - BadModifier& operator=(const BadModifier&) const; - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should not be marked 'const' -}; - -struct Deleted { - // We don't check the return value of deleted operators. - void operator=(const Deleted&) = delete; - void operator=(Deleted&&) = delete; -}; - -class Private { - // We don't check the return value of private operators. - // Pre-C++11 way of disabling assignment. - void operator=(const Private &); -}; - -struct Virtual { - virtual Virtual& operator=(const Virtual &); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should not be marked 'virtual' -}; - -class BadReturnStatement { - int n; - -public: - BadReturnStatement& operator=(BadReturnStatement&& rhs) { - n = std::move(rhs.n); - return rhs; -// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: operator=() should always return '*this' - } - - // Do not check if return type is different from '&BadReturnStatement' - int operator=(int i) { - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad - n = i; - return n; - } -}; Index: test/clang-tidy/misc-unused-using-decls.cpp =================================================================== --- test/clang-tidy/misc-unused-using-decls.cpp +++ test/clang-tidy/misc-unused-using-decls.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s misc-unused-using-decls %t -- -- -fno-delayed-template-parsing +// RUN: %check_clang_tidy %s misc-unused-using-decls %t // ----- Definitions ----- template class vector {}; @@ -10,49 +10,7 @@ class D { public: static int i; }; template class E {}; template class F {}; -class G { public: static void func() {} }; -class H { public: static int i; }; -class I { - public: - static int ii; -}; -template class J {}; -class G; -class H; - -class Base { - public: - void f(); -}; - -D UsedInstance; -D UnusedInstance; - -int UsedFunc() { return 1; } -int UnusedFunc() { return 1; } -template int UsedTemplateFunc() { return 1; } -template int UnusedTemplateFunc() { return 1; } -template int UsedInTemplateFunc() { return 1; } -void OverloadFunc(int); -void OverloadFunc(double); -int FuncUsedByUsingDeclInMacro() { return 1; } - -class ostream { -public: - ostream &operator<<(ostream &(*PF)(ostream &)); -}; -extern ostream cout; -ostream &endl(ostream &os); - -enum Color1 { Green }; - -enum Color2 { Red }; - -enum Color3 { Yellow }; - -enum Color4 { Blue }; - -} // namespace n +} // ----- Using declarations ----- // eol-comments aren't removed (yet) @@ -66,75 +24,6 @@ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'E' is unused // CHECK-FIXES: {{^}}// E using n::F; -using n::G; -using n::H; -using n::I; -int I::ii = 1; -class Derived : public n::Base { - public: - using Base::f; -}; -using n::UsedInstance; -using n::UsedFunc; -using n::UsedTemplateFunc; -using n::UnusedInstance; // UnusedInstance -// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'UnusedInstance' is unused -// CHECK-FIXES: {{^}}// UnusedInstance -using n::UnusedFunc; // UnusedFunc -// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'UnusedFunc' is unused -// CHECK-FIXES: {{^}}// UnusedFunc -using n::cout; -using n::endl; - -using n::UsedInTemplateFunc; -using n::J; -template void Callee() { - J j; - UsedInTemplateFunc(); -} - -using n::OverloadFunc; // OverloadFunc -// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'OverloadFunc' is unused -// CHECK-FIXES: {{^}}// OverloadFunc - -#define DEFINE_INT(name) \ - namespace INT { \ - static const int _##name = 1; \ - } \ - using INT::_##name -DEFINE_INT(test); -#undef DEFIND_INT - -#define USING_FUNC \ - using n::FuncUsedByUsingDeclInMacro; -USING_FUNC -#undef USING_FUNC - -namespace N1 { -// n::G is used in namespace N2. -// Currently, the check doesn't support multiple scopes. All the relevant -// using-decls will be marked as used once we see an usage even the usage is in -// other scope. -using n::G; -} - -namespace N2 { -using n::G; -void f(G g); -} - -void IgnoreFunctionScope() { -// Using-decls defined in function scope will be ignored. -using n::H; -} - -using n::Color1; -// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'Color1' is unused -using n::Green; -// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'Green' is unused -using n::Color2; -using n::Color3; -using n::Blue; // ----- Usages ----- void f(B b); @@ -142,13 +31,5 @@ vector data; D::i = 1; F f; - void (*func)() = &G::func; - int *i = &H::i; - UsedInstance.i; - UsedFunc(); - UsedTemplateFunc(); - cout << endl; - Color2 color2; - int t1 = Color3::Yellow; - int t2 = Blue; } + Index: test/clang-tidy/modernize-avoid-bind.cpp =================================================================== --- test/clang-tidy/modernize-avoid-bind.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// RUN: %check_clang_tidy %s modernize-avoid-bind %t -- -- -std=c++14 - -namespace std { -inline namespace impl { -template -class bind_rt {}; - -template -bind_rt bind(Fp &&, Arguments &&...); -} -} - -int add(int x, int y) { return x + y; } - -void f() { - auto clj = std::bind(add, 2, 2); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind [modernize-avoid-bind] - // CHECK-FIXES: auto clj = [] { return add(2, 2); }; -} - -void g() { - int x = 2; - int y = 2; - auto clj = std::bind(add, x, y); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind - // CHECK-FIXES: auto clj = [=] { return add(x, y); }; -} - -struct placeholder {}; -placeholder _1; -placeholder _2; - -void h() { - int x = 2; - auto clj = std::bind(add, x, _1); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind - // CHECK-FIXES: auto clj = [=](auto && arg1) { return add(x, arg1); }; -} - -struct A; -struct B; -bool ABTest(const A &, const B &); - -void i() { - auto BATest = std::bind(ABTest, _2, _1); - // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: prefer a lambda to std::bind - // CHECK-FIXES: auto BATest = [](auto && arg1, auto && arg2) { return ABTest(arg2, arg1); }; -} - -void j() { - auto clj = std::bind(add, 2, 2, 2); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind - // No fix is applied for argument mismatches. - // CHECK-FIXES: auto clj = std::bind(add, 2, 2, 2); -} - -void k() { - auto clj = std::bind(add, _1, _1); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind - // No fix is applied for reused placeholders. - // CHECK-FIXES: auto clj = std::bind(add, _1, _1); -} - -void m() { - auto clj = std::bind(add, 1, add(2, 5)); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind - // No fix is applied for nested calls. - // CHECK-FIXES: auto clj = std::bind(add, 1, add(2, 5)); -} - Index: test/clang-tidy/modernize-make-shared.cpp =================================================================== --- test/clang-tidy/modernize-make-shared.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// RUN: %check_clang_tidy %s modernize-make-shared %t - -namespace std { - -template -class shared_ptr { -public: - shared_ptr(type *ptr); - shared_ptr(const shared_ptr &t) {} - shared_ptr(shared_ptr &&t) {} - ~shared_ptr(); - type &operator*() { return *ptr; } - type *operator->() { return ptr; } - type *release(); - void reset(); - void reset(type *pt); - -private: - type *ptr; -}; -} - -struct Base { - Base(); - Base(int, int); -}; - -struct Derived : public Base { - Derived(); - Derived(int, int); -}; - -struct APair { - int a, b; -}; - -struct DPair { - DPair() : a(0), b(0) {} - DPair(int x, int y) : a(y), b(x) {} - int a, b; -}; - -struct Empty {}; - -template -using shared_ptr_ = std::shared_ptr; - -void *operator new(__SIZE_TYPE__ Count, void *Ptr); - -int g(std::shared_ptr P); - -std::shared_ptr getPointer() { - return std::shared_ptr(new Base); - // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use std::make_shared instead - // CHECK-FIXES: return std::make_shared(); -} - -void basic() { - std::shared_ptr P1 = std::shared_ptr(new int()); - // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_shared instead [modernize-make-shared] - // CHECK-FIXES: std::shared_ptr P1 = std::make_shared(); - - // Without parenthesis. - std::shared_ptr P2 = std::shared_ptr(new int); - // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_shared instead [modernize-make-shared] - // CHECK-FIXES: std::shared_ptr P2 = std::make_shared(); - - // With auto. - auto P3 = std::shared_ptr(new int()); - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::make_shared instead - // CHECK-FIXES: auto P3 = std::make_shared(); - - { - // No std. - using namespace std; - shared_ptr Q = shared_ptr(new int()); - // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use std::make_shared instead - // CHECK-FIXES: shared_ptr Q = std::make_shared(); - } - - std::shared_ptr R(new int()); - - // Create the shared_ptr as a parameter to a function. - int T = g(std::shared_ptr(new int())); - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::make_shared instead - // CHECK-FIXES: int T = g(std::make_shared()); - - // Only replace if the type in the template is the same than the type returned - // by the new operator. - auto Pderived = std::shared_ptr(new Derived()); - - // The pointer is returned by the function, nothing to do. - std::shared_ptr RetPtr = getPointer(); - - // This emulates std::move. - std::shared_ptr Move = static_cast &&>(P1); - - // Placemenet arguments should not be removed. - int *PInt = new int; - std::shared_ptr Placement = std::shared_ptr(new (PInt) int{3}); -} - -void initialization(int T, Base b) { - // Test different kinds of initialization of the pointee. - - // Direct initialization with parenthesis. - std::shared_ptr PDir1 = std::shared_ptr(new DPair(1, T)); - // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead - // CHECK-FIXES: std::shared_ptr PDir1 = std::make_shared(1, T); - - // Direct initialization with braces. - std::shared_ptr PDir2 = std::shared_ptr(new DPair{2, T}); - // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead - // CHECK-FIXES: std::shared_ptr PDir2 = std::make_shared(2, T); - - // Aggregate initialization. - std::shared_ptr PAggr = std::shared_ptr(new APair{T, 1}); - // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead - // CHECK-FIXES: std::shared_ptr PAggr = std::make_shared(APair{T, 1}); - - // Test different kinds of initialization of the pointee, when the shared_ptr - // is initialized with braces. - - // Direct initialization with parenthesis. - std::shared_ptr PDir3 = std::shared_ptr{new DPair(3, T)}; - // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead - // CHECK-FIXES: std::shared_ptr PDir3 = std::make_shared(3, T); - - // Direct initialization with braces. - std::shared_ptr PDir4 = std::shared_ptr{new DPair{4, T}}; - // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead - // CHECK-FIXES: std::shared_ptr PDir4 = std::make_shared(4, T); - - // Aggregate initialization. - std::shared_ptr PAggr2 = std::shared_ptr{new APair{T, 2}}; - // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use std::make_shared instead - // CHECK-FIXES: std::shared_ptr PAggr2 = std::make_shared(APair{T, 2}); - - // Direct initialization with parenthesis, without arguments. - std::shared_ptr PDir5 = std::shared_ptr(new DPair()); - // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead - // CHECK-FIXES: std::shared_ptr PDir5 = std::make_shared(); - - // Direct initialization with braces, without arguments. - std::shared_ptr PDir6 = std::shared_ptr(new DPair{}); - // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead - // CHECK-FIXES: std::shared_ptr PDir6 = std::make_shared(); - - // Aggregate initialization without arguments. - std::shared_ptr PEmpty = std::shared_ptr(new Empty{}); - // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use std::make_shared instead - // CHECK-FIXES: std::shared_ptr PEmpty = std::make_shared(Empty{}); -} - -void aliases() { - typedef std::shared_ptr IntPtr; - IntPtr Typedef = IntPtr(new int); - // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use std::make_shared instead - // CHECK-FIXES: IntPtr Typedef = std::make_shared(); - - // We use 'bool' instead of '_Bool'. - typedef std::shared_ptr BoolPtr; - BoolPtr BoolType = BoolPtr(new bool); - // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use std::make_shared instead - // CHECK-FIXES: BoolPtr BoolType = std::make_shared(); - - // We use 'Base' instead of 'struct Base'. - typedef std::shared_ptr BasePtr; - BasePtr StructType = BasePtr(new Base); -// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_shared instead -// CHECK-FIXES: BasePtr StructType = std::make_shared(); - -#define PTR shared_ptr - std::shared_ptr Macro = std::PTR(new int); -// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use std::make_shared instead -// CHECK-FIXES: std::shared_ptr Macro = std::make_shared(); -#undef PTR - - std::shared_ptr Using = shared_ptr_(new int); - // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use std::make_shared instead - // CHECK-FIXES: std::shared_ptr Using = std::make_shared(); -} - -void whitespaces() { - // clang-format off - auto Space = std::shared_ptr (new int()); - // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use std::make_shared instead - // CHECK-FIXES: auto Space = std::make_shared(); - - auto Spaces = std :: shared_ptr (new int()); - // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use std::make_shared instead - // CHECK-FIXES: auto Spaces = std::make_shared(); - // clang-format on -} - -void nesting() { - auto Nest = std::shared_ptr>(new std::shared_ptr(new int)); - // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use std::make_shared instead - // CHECK-FIXES: auto Nest = std::make_shared>(new int); -} Index: test/clang-tidy/modernize-pass-by-value-macro-header.cpp =================================================================== --- test/clang-tidy/modernize-pass-by-value-macro-header.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: %check_clang_tidy %s modernize-pass-by-value %t -- -- -std=c++11 -isystem %S/Inputs/Headers - -// CHECK-FIXES: #include - -#define HEADER <./a.h> -#include HEADER - -struct A { -}; - -struct B { - B(const A &a) : a(a) {} -// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move [modernize-pass-by-value] -// CHECK-FIXES: B(A a) : a(std::move(a)) {} - A a; -}; Index: test/clang-tidy/modernize-pass-by-value-marco-header.cpp =================================================================== --- /dev/null +++ test/clang-tidy/modernize-pass-by-value-marco-header.cpp @@ -0,0 +1,16 @@ +// RUN: %check_clang_tidy %s modernize-pass-by-value %t -- -- -std=c++11 -isystem %S/Inputs/Headers + +// CHECK-FIXES: #include + +#define HEADER <./a.h> +#include HEADER + +struct A { +}; + +struct B { + B(const A &a) : a(a) {} +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move [modernize-pass-by-value] +// CHECK-FIXES: B(A a) : a(std::move(a)) {} + A a; +}; Index: test/clang-tidy/modernize-pass-by-value.cpp =================================================================== --- test/clang-tidy/modernize-pass-by-value.cpp +++ test/clang-tidy/modernize-pass-by-value.cpp @@ -1,5 +1,7 @@ // RUN: %check_clang_tidy %s modernize-pass-by-value %t -- -- -std=c++11 -fno-delayed-template-parsing +// CHECK-FIXES: #include + namespace { // POD types are trivially move constructible. struct Movable { @@ -147,7 +149,8 @@ // Test with value parameter. struct O { O(Movable M) : M(M) {} - // CHECK-FIXES: O(Movable M) : M(M) {} + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move + // CHECK-FIXES: O(Movable M) : M(std::move(M)) {} Movable M; }; @@ -179,7 +182,8 @@ } struct R { R(ns_R::RMovable M) : M(M) {} - // CHECK-FIXES: R(ns_R::RMovable M) : M(M) {} + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move + // CHECK-FIXES: R(ns_R::RMovable M) : M(std::move(M)) {} ns_R::RMovable M; }; @@ -190,12 +194,3 @@ Movable M; }; -template struct array { T A[N]; }; - -// Test that types that are trivially copyable will not use std::move. This will -// cause problems with misc-move-const-arg, as it will revert it. -struct T { - T(array a) : a_(a) {} - // CHECK-FIXES: T(array a) : a_(a) {} - array a_; -}; Index: test/clang-tidy/modernize-use-auto-new-remove-stars.cpp =================================================================== --- test/clang-tidy/modernize-use-auto-new-remove-stars.cpp +++ /dev/null @@ -1,106 +0,0 @@ -// RUN: %check_clang_tidy %s modernize-use-auto %t -- \ -// RUN: -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: '1'}]}" \ -// RUN: -- -std=c++11 - -class MyType {}; - -class MyDerivedType : public MyType {}; - -// FIXME: the replacement sometimes results in two consecutive spaces after -// the word 'auto' (due to the presence of spaces at both sides of '*'). -void auto_new() { - MyType *a_new = new MyType(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new - // CHECK-FIXES: auto a_new = new MyType(); - - static MyType *a_static = new MyType(); - // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use auto when initializing with new - // CHECK-FIXES: static auto a_static = new MyType(); - - MyType *derived = new MyDerivedType(); - - void *vd = new MyType(); - - // CV-qualifier tests. - // - // NOTE : the form "type const" is expected here because of a deficiency in - // TypeLoc where CV qualifiers are not considered part of the type location - // info. That is, all that is being replaced in each case is "MyType *" and - // not "MyType * const". - static MyType * const d_static = new MyType(); - // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use auto when initializing with new - // CHECK-FIXES: static auto const d_static = new MyType(); - - MyType * const a_const = new MyType(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new - // CHECK-FIXES: auto const a_const = new MyType(); - - MyType * volatile vol = new MyType(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new - // CHECK-FIXES: auto volatile vol = new MyType(); - - struct SType {} *stype = new SType; - - int (**func)(int, int) = new (int(*[5])(int,int)); - - int *array = new int[5]; - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new - // CHECK-FIXES: auto array = new int[5]; - - MyType *ptr(new MyType); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new - // CHECK-FIXES: auto ptr(new MyType); - - MyType *ptr2{new MyType}; - - { - // Test for declaration lists. - MyType *a = new MyType(), *b = new MyType(), *c = new MyType(); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto a = new MyType(), b = new MyType(), c = new MyType(); - - // Non-initialized declaration should not be transformed. - MyType *d = new MyType(), *e; - - MyType **f = new MyType*(), **g = new MyType*(); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto f = new MyType*(), g = new MyType*(); - - // Mismatching types in declaration lists should not be transformed. - MyType *h = new MyType(), **i = new MyType*(); - - // '*' shouldn't be removed in case of mismatching types with multiple - // declarations. - MyType *j = new MyType(), *k = new MyType(), **l = new MyType*(); - } - - { - // Test for typedefs. - typedef int * int_p; - // CHECK-FIXES: typedef int * int_p; - - int_p a = new int; - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto a = new int; - int_p *b = new int*; - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto b = new int*; - - // Test for typedefs in declarations lists. - int_p c = new int, d = new int; - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto c = new int, d = new int; - - // Different types should not be transformed. - int_p e = new int, *f = new int_p; - - int_p *g = new int*, *h = new int_p; - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto g = new int*, h = new int_p; - } - - // Don't warn when 'auto' is already being used. - auto aut = new MyType(); - auto *paut = new MyType(); - const auto *pcaut = new MyType(); -} Index: test/clang-tidy/modernize-use-auto-new.cpp =================================================================== --- test/clang-tidy/modernize-use-auto-new.cpp +++ test/clang-tidy/modernize-use-auto-new.cpp @@ -9,11 +9,11 @@ void auto_new() { MyType *a_new = new MyType(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new - // CHECK-FIXES: auto *a_new = new MyType(); + // CHECK-FIXES: auto a_new = new MyType(); static MyType *a_static = new MyType(); // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use auto when initializing with new - // CHECK-FIXES: static auto *a_static = new MyType(); + // CHECK-FIXES: static auto a_static = new MyType(); MyType *derived = new MyDerivedType(); @@ -27,15 +27,15 @@ // not "MyType * const". static MyType * const d_static = new MyType(); // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use auto when initializing with new - // CHECK-FIXES: static auto * const d_static = new MyType(); + // CHECK-FIXES: static auto const d_static = new MyType(); MyType * const a_const = new MyType(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new - // CHECK-FIXES: auto * const a_const = new MyType(); + // CHECK-FIXES: auto const a_const = new MyType(); MyType * volatile vol = new MyType(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new - // CHECK-FIXES: auto * volatile vol = new MyType(); + // CHECK-FIXES: auto volatile vol = new MyType(); struct SType {} *stype = new SType; @@ -43,11 +43,11 @@ int *array = new int[5]; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new - // CHECK-FIXES: auto *array = new int[5]; + // CHECK-FIXES: auto array = new int[5]; MyType *ptr(new MyType); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new - // CHECK-FIXES: auto *ptr(new MyType); + // CHECK-FIXES: auto ptr(new MyType); MyType *ptr2{new MyType}; @@ -55,14 +55,14 @@ // Test for declaration lists. MyType *a = new MyType(), *b = new MyType(), *c = new MyType(); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto *a = new MyType(), *b = new MyType(), *c = new MyType(); + // CHECK-FIXES: auto a = new MyType(), b = new MyType(), c = new MyType(); // Non-initialized declaration should not be transformed. MyType *d = new MyType(), *e; MyType **f = new MyType*(), **g = new MyType*(); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto **f = new MyType*(), **g = new MyType*(); + // CHECK-FIXES: auto f = new MyType*(), g = new MyType*(); // Mismatching types in declaration lists should not be transformed. MyType *h = new MyType(), **i = new MyType*(); @@ -75,26 +75,25 @@ { // Test for typedefs. typedef int * int_p; - // CHECK-FIXES: typedef int * int_p; int_p a = new int; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto a = new int; + // CHECK-FIXES: auto a = new int; int_p *b = new int*; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto *b = new int*; + // CHECK-FIXES: auto b = new int*; // Test for typedefs in declarations lists. int_p c = new int, d = new int; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto c = new int, d = new int; + // CHECK-FIXES: auto c = new int, d = new int; // Different types should not be transformed. int_p e = new int, *f = new int_p; int_p *g = new int*, *h = new int_p; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new - // CHECK-FIXES: auto *g = new int*, *h = new int_p; + // CHECK-FIXES: auto g = new int*, h = new int_p; } // Don't warn when 'auto' is already being used. Index: test/clang-tidy/modernize-use-bool-literals.cpp =================================================================== --- test/clang-tidy/modernize-use-bool-literals.cpp +++ /dev/null @@ -1,118 +0,0 @@ -// RUN: %check_clang_tidy %s modernize-use-bool-literals %t - -bool IntToTrue = 1; -// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: converting integer literal to bool, use bool literal instead [modernize-use-bool-literals] -// CHECK-FIXES: {{^}}bool IntToTrue = true;{{$}} - -bool IntToFalse(0); -// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: {{.*}} -// CHECK-FIXES: {{^}}bool IntToFalse(false);{{$}} - -bool LongLongToTrue{0x1LL}; -// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: {{.*}} -// CHECK-FIXES: {{^}}bool LongLongToTrue{true};{{$}} - -bool ExplicitCStyleIntToFalse = (bool)0; -// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: {{.*}} -// CHECK-FIXES: {{^}}bool ExplicitCStyleIntToFalse = false;{{$}} - -bool ExplicitFunctionalIntToFalse = bool(0); -// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: {{.*}} -// CHECK-FIXES: {{^}}bool ExplicitFunctionalIntToFalse = false;{{$}} - -bool ExplicitStaticIntToFalse = static_cast(0); -// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: {{.*}} -// CHECK-FIXES: {{^}}bool ExplicitStaticIntToFalse = false;{{$}} - -#define TRUE_MACRO 1 -// CHECK-FIXES: {{^}}#define TRUE_MACRO 1{{$}} - -bool MacroIntToTrue = TRUE_MACRO; -// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: converting integer literal to bool, use bool literal instead [modernize-use-bool-literals] -// CHECK-FIXES: {{^}}bool MacroIntToTrue = TRUE_MACRO;{{$}} - -#define FALSE_MACRO bool(0) -// CHECK-FIXES: {{^}}#define FALSE_MACRO bool(0){{$}} - -bool TrueBool = true; // OK - -bool FalseBool = bool(FALSE_MACRO); -// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: {{.*}} -// CHECK-FIXES: {{^}}bool FalseBool = bool(FALSE_MACRO);{{$}} - -void boolFunction(bool bar) { - -} - -char Character = 0; // OK - -unsigned long long LongInteger = 1; // OK - -#define MACRO_DEPENDENT_CAST(x) static_cast(x) -// CHECK-FIXES: {{^}}#define MACRO_DEPENDENT_CAST(x) static_cast(x){{$}} - -bool MacroDependentBool = MACRO_DEPENDENT_CAST(0); -// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: {{.*}} -// CHECK-FIXES: {{^}}bool MacroDependentBool = MACRO_DEPENDENT_CAST(0);{{$}} - -bool ManyMacrosDependent = MACRO_DEPENDENT_CAST(FALSE_MACRO); -// CHECK-MESSAGES: :[[@LINE-1]]:49: warning: {{.*}} -// CHECK-FIXES: {{^}}bool ManyMacrosDependent = MACRO_DEPENDENT_CAST(FALSE_MACRO);{{$}} - -class FooClass { - public: - FooClass() : JustBool(0) {} - // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: {{.*}} - // CHECK-FIXES: {{^ *}}FooClass() : JustBool(false) {}{{$}} - FooClass(int) : JustBool{0} {} - // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: {{.*}} - // CHECK-FIXES: {{^ *}}FooClass(int) : JustBool{false} {}{{$}} - private: - bool JustBool; - bool BoolWithBraces{0}; - // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: {{.*}} - // CHECK-FIXES: {{^ *}}bool BoolWithBraces{false};{{$}} - bool BoolFromInt = 0; - // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: {{.*}} - // CHECK-FIXES: {{^ *}}bool BoolFromInt = false;{{$}} - bool SimpleBool = true; // OK -}; - -template -void templateFunction(type) { - type TemplateType = 0; - // CHECK-FIXES: {{^ *}}type TemplateType = 0;{{$}} -} - -template -void valueDependentTemplateFunction() { - bool Boolean = c; - // CHECK-FIXES: {{^ *}}bool Boolean = c;{{$}} -} - -template -void anotherTemplateFunction(type) { - bool JustBool = 0; - // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: {{.*}} - // CHECK-FIXES: {{^ *}}bool JustBool = false;{{$}} -} - -int main() { - boolFunction(1); - // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: {{.*}} - // CHECK-FIXES: {{^ *}}boolFunction(true);{{$}} - - boolFunction(false); - - templateFunction(0); - - templateFunction(false); - - valueDependentTemplateFunction<1>(); - - anotherTemplateFunction(1); - - IntToTrue = 1; - // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: {{.*}} - // CHECK-FIXES: {{^ *}}IntToTrue = true;{{$}} -} Index: test/clang-tidy/modernize-use-emplace.cpp =================================================================== --- test/clang-tidy/modernize-use-emplace.cpp +++ /dev/null @@ -1,338 +0,0 @@ -// RUN: %check_clang_tidy %s modernize-use-emplace %t - -namespace std { -template -class vector { -public: - void push_back(const T &) {} - void push_back(T &&) {} - - template - void emplace_back(Args &&... args){}; -}; -template -class list { -public: - void push_back(const T &) {} - void push_back(T &&) {} - - template - void emplace_back(Args &&... args){}; -}; - -template -class deque { -public: - void push_back(const T &) {} - void push_back(T &&) {} - - template - void emplace_back(Args &&... args){}; -}; - -template -class pair { -public: - pair() = default; - pair(const pair &) = default; - pair(pair &&) = default; - - pair(const T1 &, const T2 &) {} - pair(T1 &&, T2 &&) {} - - template - pair(const pair &p){}; - template - pair(pair &&p){}; -}; - -template -pair make_pair(T1, T2) { - return pair(); -}; - -template -class unique_ptr { -public: - unique_ptr(T *) {} -}; -} // namespace std - -void testInts() { - std::vector v; - v.push_back(42); - v.push_back(int(42)); - v.push_back(int{42}); - v.push_back(42.0); - int z; - v.push_back(z); -} - -struct Something { - Something(int a, int b = 41) {} - Something() {} - void push_back(Something); -}; - -struct Convertable { - operator Something() { return Something{}; } -}; - -struct Zoz { - Zoz(Something, int = 42) {} -}; - -Zoz getZoz(Something s) { return Zoz(s); } - -void test_Something() { - std::vector v; - - v.push_back(Something(1, 2)); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back instead of push_back [modernize-use-emplace] - // CHECK-FIXES: v.emplace_back(1, 2); - - v.push_back(Something{1, 2}); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - // CHECK-FIXES: v.emplace_back(1, 2); - - v.push_back(Something()); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - // CHECK-FIXES: v.emplace_back(); - - v.push_back(Something{}); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - // CHECK-FIXES: v.emplace_back(); - - v.push_back(42); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - // CHECK-FIXES: v.emplace_back(42); - - Something temporary(42, 42); - temporary.push_back(temporary); - v.push_back(temporary); - - v.push_back(Convertable()); - v.push_back(Convertable{}); - Convertable s; - v.push_back(s); -} - -void test2() { - std::vector v; - v.push_back(Zoz(Something(21, 37))); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - // CHECK-FIXES: v.emplace_back(Something(21, 37)); - - v.push_back(Zoz(Something(21, 37), 42)); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - // CHECK-FIXES: v.emplace_back(Something(21, 37), 42); - - v.push_back(getZoz(Something(1, 2))); -} - -void testPair() { - std::vector> v; - v.push_back(std::pair(1, 2)); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - // CHECK-FIXES: v.emplace_back(1, 2); - - std::vector> v2; - v2.push_back(std::pair(Something(42, 42), Zoz(Something(21, 37)))); - // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use emplace_back - // CHECK-FIXES: v2.emplace_back(Something(42, 42), Zoz(Something(21, 37))); -} - -struct Base { - Base(int, int *, int = 42); -}; - -struct Derived : Base { - Derived(int *, Something) : Base(42, nullptr) {} -}; - -void testDerived() { - std::vector v; - v.push_back(Derived(nullptr, Something{})); -} - -void testNewExpr() { - std::vector v; - v.push_back(Derived(new int, Something{})); -} - -void testSpaces() { - std::vector v; - - // clang-format off - - v.push_back(Something(1, //arg1 - 2 // arg2 - ) // Something - ); - // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use emplace_back - // CHECK-FIXES: v.emplace_back(1, //arg1 - // CHECK-FIXES: 2 // arg2 - // CHECK-FIXES: // Something - // CHECK-FIXES: ); - - v.push_back( Something (1, 2) ); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - // CHECK-FIXES: v.emplace_back(1, 2 ); - - v.push_back( Something {1, 2} ); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - // CHECK-FIXES: v.emplace_back(1, 2 ); - - v.push_back( Something {} ); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - // CHECK-FIXES: v.emplace_back( ); - - v.push_back( - Something(1, 2) ); - // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use emplace_back - // CHECK-FIXES: v.emplace_back(1, 2 ); - - std::vector v2; - v2.push_back( - Base(42, nullptr)); - // CHECK-MESSAGES: :[[@LINE-2]]:6: warning: use emplace_back - // CHECK-FIXES: v2.emplace_back(42, nullptr); - - // clang-format on -} - -void testPointers() { - std::vector v; - v.push_back(new int(5)); - - std::vector> v2; - v2.push_back(new int(42)); - // This call can't be replaced with emplace_back. - // If emplacement will fail (not enough memory to add to vector) - // we will have leak of int because unique_ptr won't be constructed - // (and destructed) as in push_back case. - - auto *ptr = new int; - v2.push_back(ptr); - // Same here -} - -void testMakePair() { - std::vector> v; - // FIXME: add functionality to change calls of std::make_pair - v.push_back(std::make_pair(1, 2)); - - // FIXME: This is not a bug, but call of make_pair should be removed in the - // future. This one matches because the return type of make_pair is different - // than the pair itself. - v.push_back(std::make_pair(42LL, 13)); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - // CHECK-FIXES: v.emplace_back(std::make_pair(42LL, 13)); -} - -void testOtherCointainers() { - std::list l; - l.push_back(Something(42, 41)); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - // CHECK-FIXES: l.emplace_back(42, 41); - - std::deque d; - d.push_back(Something(42)); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - // CHECK-FIXES: d.emplace_back(42); -} - -class IntWrapper { -public: - IntWrapper(int x) : value(x) {} - IntWrapper operator+(const IntWrapper other) const { - return IntWrapper(value + other.value); - } - -private: - int value; -}; - -void testMultipleOpsInPushBack() { - std::vector v; - v.push_back(IntWrapper(42) + IntWrapper(27)); -} - -// Macro tests. -#define PUSH_BACK_WHOLE(c, x) c.push_back(x) -#define PUSH_BACK_NAME push_back -#define PUSH_BACK_ARG(x) (x) -#define SOME_OBJ Something(10) -#define MILLION 3 -#define SOME_WEIRD_PUSH(v) v.push_back(Something( -#define OPEN ( -#define CLOSE ) -void macroTest() { - std::vector v; - Something s; - - PUSH_BACK_WHOLE(v, Something(5, 6)); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use emplace_back - - v.PUSH_BACK_NAME(Something(5)); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - - v.push_back PUSH_BACK_ARG(Something(5, 6)); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - - v.push_back(SOME_OBJ); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - - v.push_back(Something(MILLION)); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - // CHECK-FIXES: v.emplace_back(MILLION); - - // clang-format off - v.push_back( Something OPEN 3 CLOSE ); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - // clang-format on - PUSH_BACK_WHOLE(s, Something(1)); -} - -struct A { - int value1, value2; -}; - -struct B { - B(A) {} -}; - -struct C { - int value1, value2, value3; -}; - -void testAggregation() { - // This should not be noticed or fixed; after the correction, the code won't - // compile. - - std::vector v; - v.push_back(A({1, 2})); - - std::vector vb; - vb.push_back(B({10, 42})); -} - -struct Bitfield { - unsigned bitfield : 1; - unsigned notBitfield; -}; - -void testBitfields() { - std::vector v; - Bitfield b; - v.push_back(Something(42, b.bitfield)); - v.push_back(Something(b.bitfield)); - - v.push_back(Something(42, b.notBitfield)); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - // CHECK-FIXES: v.emplace_back(42, b.notBitfield); - int var; - v.push_back(Something(42, var)); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back - // CHECK-FIXES: v.emplace_back(42, var); -} Index: test/clang-tidy/modernize-use-using.cpp =================================================================== --- test/clang-tidy/modernize-use-using.cpp +++ /dev/null @@ -1,87 +0,0 @@ -// RUN: %check_clang_tidy %s modernize-use-using %t - -typedef int Type; -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' [modernize-use-using] -// CHECK-FIXES: using Type = int; - -typedef long LL; -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using LL = long; - -typedef int Bla; -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using Bla = int; - -typedef Bla Bla2; -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using Bla2 = Bla; - -typedef void (*type)(int, int); -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using type = void (*)(int, int); - -typedef void (*type2)(); -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using type2 = void (*)(); - -class Class { - typedef long long Type; - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' - // CHECK-FIXES: using Type = long long; -}; - -typedef void (Class::*MyPtrType)(Bla) const; -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using MyPtrType = void (Class::*)(Bla)[[ATTR:( __attribute__\(\(thiscall\)\))?]] const; - -class Iterable { -public: - class Iterator {}; -}; - -template -class Test { - typedef typename T::iterator Iter; - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' - // CHECK-FIXES: using Iter = typename T::iterator; -}; - -using balba = long long; - -union A {}; - -typedef void (A::*PtrType)(int, int) const; -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using PtrType = void (A::*)(int, int)[[ATTR]] const; - -typedef Class some_class; -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using some_class = Class; - -typedef Class Cclass; -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using Cclass = Class; - -typedef Cclass cclass2; -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using cclass2 = Cclass; - -class cclass {}; - -typedef void (cclass::*MyPtrType3)(Bla); -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using MyPtrType3 = void (cclass::*)(Bla)[[ATTR]]; - -using my_class = int; - -typedef Test another; -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using another = Test; - -typedef int bla1, bla2, bla3; -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' - -#define CODE typedef int INT - -CODE; -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' Index: test/clang-tidy/nolint.cpp =================================================================== --- test/clang-tidy/nolint.cpp +++ test/clang-tidy/nolint.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s google-explicit-constructor,clang-diagnostic-unused-variable %t -- -extra-arg=-Wunused-variable -- +// RUN: %check_clang_tidy %s google-explicit-constructor %t class A { A(int i); }; // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: single-argument constructors must be marked explicit @@ -6,11 +6,4 @@ class B { B(int i); }; // NOLINT class C { C(int i); }; // NOLINT(we-dont-care-about-categories-yet) - -void f() { - int i; -// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: unused variable 'i' [clang-diagnostic-unused-variable] - int j; // NOLINT -} - -// CHECK-MESSAGES: Suppressed 3 warnings (3 NOLINT) +// CHECK-MESSAGES: Suppressed 2 warnings (2 NOLINT) Index: test/clang-tidy/performance-unnecessary-copy-initialization.cpp =================================================================== --- test/clang-tidy/performance-unnecessary-copy-initialization.cpp +++ test/clang-tidy/performance-unnecessary-copy-initialization.cpp @@ -36,65 +36,65 @@ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' is copy-constructed from a const reference; consider making it a const reference [performance-unnecessary-copy-initialization] // CHECK-FIXES: const auto& AutoAssigned = ExpensiveTypeReference(); const auto AutoCopyConstructed(ExpensiveTypeReference()); - // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable // CHECK-FIXES: const auto& AutoCopyConstructed(ExpensiveTypeReference()); const ExpensiveToCopyType VarAssigned = ExpensiveTypeReference(); - // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' + // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = ExpensiveTypeReference(); const ExpensiveToCopyType VarCopyConstructed(ExpensiveTypeReference()); - // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' + // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(ExpensiveTypeReference()); } void PositiveMethodCallConstReferenceParam(const ExpensiveToCopyType &Obj) { const auto AutoAssigned = Obj.reference(); - // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); const auto AutoCopyConstructed(Obj.reference()); - // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable // CHECK-FIXES: const auto& AutoCopyConstructed(Obj.reference()); const ExpensiveToCopyType VarAssigned = Obj.reference(); - // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' + // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj.reference(); const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); - // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' + // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj.reference()); } void PositiveMethodCallConstParam(const ExpensiveToCopyType Obj) { const auto AutoAssigned = Obj.reference(); - // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); const auto AutoCopyConstructed(Obj.reference()); - // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable // CHECK-FIXES: const auto& AutoCopyConstructed(Obj.reference()); const ExpensiveToCopyType VarAssigned = Obj.reference(); - // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' + // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj.reference(); const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); - // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' + // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj.reference()); } void PositiveMethodCallConstPointerParam(const ExpensiveToCopyType *const Obj) { const auto AutoAssigned = Obj->reference(); - // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable // CHECK-FIXES: const auto& AutoAssigned = Obj->reference(); const auto AutoCopyConstructed(Obj->reference()); - // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable // CHECK-FIXES: const auto& AutoCopyConstructed(Obj->reference()); const ExpensiveToCopyType VarAssigned = Obj->reference(); - // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' + // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj->reference(); const ExpensiveToCopyType VarCopyConstructed(Obj->reference()); - // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' + // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj->reference()); } void PositiveLocalConstValue() { const ExpensiveToCopyType Obj; const auto UnnecessaryCopy = Obj.reference(); - // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable // CHECK-FIXES: const auto& UnnecessaryCopy = Obj.reference(); } @@ -102,7 +102,7 @@ const ExpensiveToCopyType Obj; const ExpensiveToCopyType &ConstReference = Obj.reference(); const auto UnnecessaryCopy = ConstReference.reference(); - // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable // CHECK-FIXES: const auto& UnnecessaryCopy = ConstReference.reference(); } @@ -110,7 +110,7 @@ const ExpensiveToCopyType Obj; const ExpensiveToCopyType *const ConstPointer = &Obj; const auto UnnecessaryCopy = ConstPointer->reference(); - // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable // CHECK-FIXES: const auto& UnnecessaryCopy = ConstPointer->reference(); } @@ -130,20 +130,20 @@ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'AutoAssigned' is copy-constructed from a const reference but is only used as const reference; consider making it a const reference [performance-unnecessary-copy-initialization] // CHECK-FIXES: const auto& AutoAssigned = ExpensiveTypeReference(); auto AutoCopyConstructed(ExpensiveTypeReference()); - // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'AutoCopyConstructed' + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable // CHECK-FIXES: const auto& AutoCopyConstructed(ExpensiveTypeReference()); ExpensiveToCopyType VarAssigned = ExpensiveTypeReference(); - // CHECK-MESSAGES: [[@LINE-1]]:23: warning: the variable 'VarAssigned' + // CHECK-MESSAGES: [[@LINE-1]]:23: warning: the variable // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = ExpensiveTypeReference(); ExpensiveToCopyType VarCopyConstructed(ExpensiveTypeReference()); - // CHECK-MESSAGES: [[@LINE-1]]:23: warning: the variable 'VarCopyConstructed' + // CHECK-MESSAGES: [[@LINE-1]]:23: warning: the variable // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(ExpensiveTypeReference()); } void positiveNonConstVarInCodeBlock(const ExpensiveToCopyType &Obj) { { auto Assigned = Obj.reference(); - // CHECK-MESSAGES: [[@LINE-1]]:10: warning: the variable 'Assigned' + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: the variable // CHECK-FIXES: const auto& Assigned = Obj.reference(); Assigned.reference(); useAsConstReference(Assigned); @@ -174,57 +174,33 @@ } } -void PositiveMethodCallNonConstRefNotModified(ExpensiveToCopyType &Obj) { - const auto AutoAssigned = Obj.reference(); - // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' - // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); -} - -void NegativeMethodCallNonConstRefIsModified(ExpensiveToCopyType &Obj) { +void NegativeMethodCallNonConstRef(ExpensiveToCopyType &Obj) { const auto AutoAssigned = Obj.reference(); const auto AutoCopyConstructed(Obj.reference()); const ExpensiveToCopyType VarAssigned = Obj.reference(); const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); - mutate(&Obj); -} - -void PositiveMethodCallNonConstNotModified(ExpensiveToCopyType Obj) { - const auto AutoAssigned = Obj.reference(); - // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' - // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); } -void NegativeMethodCallNonConstValueArgumentIsModified(ExpensiveToCopyType Obj) { - Obj.nonConstMethod(); +void NegativeMethodCallNonConst(ExpensiveToCopyType Obj) { const auto AutoAssigned = Obj.reference(); + const auto AutoCopyConstructed(Obj.reference()); + const ExpensiveToCopyType VarAssigned = Obj.reference(); + const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); } -void PositiveMethodCallNonConstPointerNotModified(ExpensiveToCopyType *const Obj) { - const auto AutoAssigned = Obj->reference(); - // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' - // CHECK-FIXES: const auto& AutoAssigned = Obj->reference(); - Obj->constMethod(); -} - -void NegativeMethodCallNonConstPointerIsModified(ExpensiveToCopyType *const Obj) { +void NegativeMethodCallNonConstPointer(ExpensiveToCopyType *const Obj) { const auto AutoAssigned = Obj->reference(); const auto AutoCopyConstructed(Obj->reference()); const ExpensiveToCopyType VarAssigned = Obj->reference(); const ExpensiveToCopyType VarCopyConstructed(Obj->reference()); - mutate(Obj); } -void PositiveLocalVarIsNotModified() { - ExpensiveToCopyType LocalVar; - const auto AutoAssigned = LocalVar.reference(); - // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' - // CHECK-FIXES: const auto& AutoAssigned = LocalVar.reference(); -} - -void NegativeLocalVarIsModified() { +void NegativeObjIsNotParam() { ExpensiveToCopyType Obj; const auto AutoAssigned = Obj.reference(); - Obj = AutoAssigned; + const auto AutoCopyConstructed(Obj.reference()); + ExpensiveToCopyType VarAssigned = Obj.reference(); + ExpensiveToCopyType VarCopyConstructed(Obj.reference()); } struct NegativeConstructor { @@ -362,9 +338,3 @@ WeirdCopyCtorType neg_weird_1(orig, false); WeirdCopyCtorType neg_weird_2(orig, true); } -void WarningOnlyMultiDeclStmt() { - ExpensiveToCopyType orig; - ExpensiveToCopyType copy = orig, copy2; - // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy' of the variable 'orig' is never modified; consider avoiding the copy [performance-unnecessary-copy-initialization] - // CHECK-FIXES: ExpensiveToCopyType copy = orig, copy2; -} Index: test/clang-tidy/performance-unnecessary-value-param.cpp =================================================================== --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -1,7 +1,5 @@ // RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -// CHECK-FIXES: #include - struct ExpensiveToCopyType { const ExpensiveToCopyType & constReference() const { return *this; @@ -25,22 +23,6 @@ SomewhatTrivial& operator=(const SomewhatTrivial&); }; -struct MoveOnlyType { - MoveOnlyType(const MoveOnlyType &) = delete; - MoveOnlyType(MoveOnlyType &&) = default; - ~MoveOnlyType(); - void constMethod() const; -}; - -struct ExpensiveMovableType { - ExpensiveMovableType(); - ExpensiveMovableType(ExpensiveMovableType &&); - ExpensiveMovableType(const ExpensiveMovableType &) = default; - ExpensiveMovableType &operator=(const ExpensiveMovableType &) = default; - ExpensiveMovableType &operator=(ExpensiveMovableType &&); - ~ExpensiveMovableType(); -}; - void positiveExpensiveConstValue(const ExpensiveToCopyType Obj); // CHECK-FIXES: void positiveExpensiveConstValue(const ExpensiveToCopyType& Obj); void positiveExpensiveConstValue(const ExpensiveToCopyType Obj) { @@ -182,58 +164,8 @@ } }; -struct VirtualMethodWarningOnly { - virtual void methodWithExpensiveValueParam(ExpensiveToCopyType T) {} - // CHECK-MESSAGES: [[@LINE-1]]:66: warning: the parameter 'T' is copied - // CHECK-FIXES: virtual void methodWithExpensiveValueParam(ExpensiveToCopyType T) {} - virtual ~VirtualMethodWarningOnly() {} -}; - -struct PositiveNonVirualMethod { - void method(const ExpensiveToCopyType T) {} - // CHECK-MESSAGES: [[@LINE-1]]:41: warning: the const qualified parameter 'T' is copied - // CHECK-FIXES: void method(const ExpensiveToCopyType& T) {} -}; - struct NegativeDeletedMethod { ~NegativeDeletedMethod() {} NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete; // CHECK-FIXES: NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete; }; - -void NegativeMoveOnlyTypePassedByValue(MoveOnlyType M) { - M.constMethod(); -} - -void PositiveMoveOnCopyConstruction(ExpensiveMovableType E) { - auto F = E; - // CHECK-MESSAGES: [[@LINE-1]]:12: warning: parameter 'E' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param] - // CHECK-FIXES: auto F = std::move(E); -} - -void PositiveConstRefNotMoveSinceReferencedMultipleTimes(ExpensiveMovableType E) { - // CHECK-MESSAGES: [[@LINE-1]]:79: warning: the parameter 'E' is copied - // CHECK-FIXES: void PositiveConstRefNotMoveSinceReferencedMultipleTimes(const ExpensiveMovableType& E) { - auto F = E; - auto G = E; -} - -void PositiveMoveOnCopyAssignment(ExpensiveMovableType E) { - ExpensiveMovableType F; - F = E; - // CHECK-MESSAGES: [[@LINE-1]]:7: warning: parameter 'E' is passed by value - // CHECK-FIXES: F = std::move(E); -} - -void PositiveConstRefNotMoveConstructible(ExpensiveToCopyType T) { - // CHECK-MESSAGES: [[@LINE-1]]:63: warning: the parameter 'T' is copied - // CHECK-FIXES: void PositiveConstRefNotMoveConstructible(const ExpensiveToCopyType& T) { - auto U = T; -} - -void PositiveConstRefNotMoveAssignable(ExpensiveToCopyType A) { - // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the parameter 'A' is copied - // CHECK-FIXES: void PositiveConstRefNotMoveAssignable(const ExpensiveToCopyType& A) { - ExpensiveToCopyType B; - B = A; -} Index: test/clang-tidy/readability-avoid-const-params-in-decls.cpp =================================================================== --- test/clang-tidy/readability-avoid-const-params-in-decls.cpp +++ test/clang-tidy/readability-avoid-const-params-in-decls.cpp @@ -83,14 +83,3 @@ void NF(const int*); void NF(const int* const*); void NF(alias_const_type); - -// Regression test for when the 'const' token is not in the code. -#define CONCAT(a, b) a##b -void ConstNotVisible(CONCAT(cons, t) int i); -// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: parameter 'i' -// We warn, but we can't give a fix -// CHECK-FIXES: void ConstNotVisible(CONCAT(cons, t) int i); - -// Regression test. We should not warn (or crash) on lambda expressions -auto lambda_with_name = [](const int n) {}; -auto lambda_without_name = [](const int) {}; Index: test/clang-tidy/readability-identifier-naming.cpp =================================================================== --- test/clang-tidy/readability-identifier-naming.cpp +++ test/clang-tidy/readability-identifier-naming.cpp @@ -61,9 +61,6 @@ // RUN: {key: readability-identifier-naming.VariableCase, value: lower_case}, \ // RUN: {key: readability-identifier-naming.VirtualMethodCase, value: UPPER_CASE}, \ // RUN: {key: readability-identifier-naming.VirtualMethodPrefix, value: 'v_'}, \ -// RUN: {key: readability-identifier-naming.MacroDefinitionCase, value: UPPER_CASE}, \ -// RUN: {key: readability-identifier-naming.TypeAliasCase, value: lower_case}, \ -// RUN: {key: readability-identifier-naming.TypeAliasSuffix, value: '_t'}, \ // RUN: {key: readability-identifier-naming.IgnoreFailedSplit, value: 0} \ // RUN: ]}' -- -std=c++11 -fno-delayed-template-parsing \ // RUN: -I%S/Inputs/readability-identifier-naming \ @@ -194,8 +191,8 @@ // CHECK-FIXES: {{^}}class CMyOtherTemplatedClass : CMyTemplatedClass< CMyClass>, private CMyDerivedClass {};{{$}} template -using mysuper_tpl_t = my_other_templated_class <:: FOO_NS ::my_class>; -// CHECK-FIXES: {{^}}using mysuper_tpl_t = CMyOtherTemplatedClass <:: foo_ns ::CMyClass>;{{$}} +using MYSUPER_TPL = my_other_templated_class <:: FOO_NS ::my_class>; +// CHECK-FIXES: {{^}}using MYSUPER_TPL = CMyOtherTemplatedClass <:: foo_ns ::CMyClass>;{{$}} const int global_Constant = 6; // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: invalid case style for global constant 'global_Constant' @@ -308,21 +305,6 @@ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: invalid case style for typedef 'struct_type' // CHECK-FIXES: {{^}}typedef this_structure struct_type_t;{{$}} -struct_type GlobalTypedefTestFunction(struct_type a_argument1) { -// CHECK-FIXES: {{^}}struct_type_t GlobalTypedefTestFunction(struct_type_t a_argument1) { - struct_type typedef_test_1; -// CHECK-FIXES: {{^}} struct_type_t typedef_test_1; -} - -using my_struct_type = THIS___Structure; -// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for type alias 'my_struct_type' -// CHECK-FIXES: {{^}}using my_struct_type_t = this_structure;{{$}} - -template -using SomeOtherTemplate = my_other_templated_class <:: FOO_NS ::my_class>; -// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for type alias 'SomeOtherTemplate' -// CHECK-FIXES: {{^}}using some_other_template_t = CMyOtherTemplatedClass <:: foo_ns ::CMyClass>;{{$}} - static void static_Function() { // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: invalid case style for function 'static_Function' // CHECK-FIXES: {{^}}static void staticFunction() {{{$}} @@ -336,17 +318,5 @@ // CHECK-FIXES: {{^}} using ::foo_ns::inline_namespace::ce_function;{{$}} } -#define MY_TEST_Macro(X) X() -// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for macro definition 'MY_TEST_Macro' -// CHECK-FIXES: {{^}}#define MY_TEST_MACRO(X) X() - -void MY_TEST_Macro(function) {} -// CHECK-FIXES: {{^}}void MY_TEST_MACRO(function) {} } } - -template struct a { - typename t_t::template b<> c; -}; - -template