Compare commits
114 Commits
llvmorg-7.
...
llvmorg-3.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83f8b92b34 | ||
|
|
d2cd7c5902 | ||
|
|
76d2581450 | ||
|
|
13225a76de | ||
|
|
368a2bed7b | ||
|
|
95959916e7 | ||
|
|
7370495d29 | ||
|
|
813999532a | ||
|
|
4c7a06eb9c | ||
|
|
61c4ba945c | ||
|
|
562712ae80 | ||
|
|
ef492f7c44 | ||
|
|
3c78fb290a | ||
|
|
4262851e1b | ||
|
|
ff38e3da85 | ||
|
|
6bdbb229c0 | ||
|
|
fcd989333f | ||
|
|
e82b3c8f5f | ||
|
|
bc626ae563 | ||
|
|
4de5839c99 | ||
|
|
5ba548388f | ||
|
|
6036ee499c | ||
|
|
0ee1c0452b | ||
|
|
5a09dfa964 | ||
|
|
668c2339e1 | ||
|
|
2ffe33d726 | ||
|
|
3f0867ead3 | ||
|
|
c76f4b6602 | ||
|
|
28e01d94e1 | ||
|
|
192e2e2ca9 | ||
|
|
c25f426db2 | ||
|
|
66671a5b81 | ||
|
|
21bac108cf | ||
|
|
b625dc1f9e | ||
|
|
ca6c6b95d5 | ||
|
|
b2459060c8 | ||
|
|
0abd0b2d75 | ||
|
|
3e548d31e8 | ||
|
|
f48d9e60c0 | ||
|
|
904a8f6ac8 | ||
|
|
20b8eb19ee | ||
|
|
13b8dc2040 | ||
|
|
6a183487cc | ||
|
|
869abd3c4a | ||
|
|
d7eab8630c | ||
|
|
3df9c41538 | ||
|
|
8338208af2 | ||
|
|
b33695227a | ||
|
|
444a522e5d | ||
|
|
9b74891142 | ||
|
|
5f262c819d | ||
|
|
569deba640 | ||
|
|
2c74c29d92 | ||
|
|
c369220352 | ||
|
|
001a4b73cd | ||
|
|
405f701d60 | ||
|
|
dfb3dabbf1 | ||
|
|
c326e800f2 | ||
|
|
e3b981281d | ||
|
|
12646940aa | ||
|
|
fe62b2b0a7 | ||
|
|
f6c040eca0 | ||
|
|
317fbe2805 | ||
|
|
fe82a366df | ||
|
|
75c7375ee8 | ||
|
|
ec68271f06 | ||
|
|
4bd3da119e | ||
|
|
009ef32ff2 | ||
|
|
3869e6a789 | ||
|
|
d8f7f82712 | ||
|
|
aa124fa230 | ||
|
|
23513f4039 | ||
|
|
54f837917c | ||
|
|
800eae7e0b | ||
|
|
cdd225435f | ||
|
|
cd8406104c | ||
|
|
87d61cf9aa | ||
|
|
0e9a6b6dc0 | ||
|
|
832d6a68de | ||
|
|
b0ca78fb51 | ||
|
|
fc546f8627 | ||
|
|
6b823ba449 | ||
|
|
9a45867caf | ||
|
|
94f35ea76f | ||
|
|
014e7b834f | ||
|
|
0cec800e8d | ||
|
|
6323faf644 | ||
|
|
d180cc9112 | ||
|
|
81d4e6005c | ||
|
|
062184f19b | ||
|
|
b3ff622079 | ||
|
|
6207270016 | ||
|
|
c7bfb6d36a | ||
|
|
60c15ed5ff | ||
|
|
5975e88f88 | ||
|
|
b8f0391a7c | ||
|
|
dddf67f5d5 | ||
|
|
3c89b2c953 | ||
|
|
ffd65c839c | ||
|
|
aa9583d2ed | ||
|
|
5b15c0f87d | ||
|
|
2fbdb127ea | ||
|
|
6b7ac2a98c | ||
|
|
e1dceeca1a | ||
|
|
00cc493db6 | ||
|
|
9149bf6772 | ||
|
|
b4a2b91353 | ||
|
|
2cabf384c2 | ||
|
|
a0911d3f03 | ||
|
|
98ab17b1b3 | ||
|
|
b79ae58145 | ||
|
|
6e814ffb39 | ||
|
|
e25ce394b0 | ||
|
|
93c80e5bff |
@@ -1,6 +1,5 @@
|
||||
add_subdirectory(clang-apply-replacements)
|
||||
add_subdirectory(clang-modernize)
|
||||
add_subdirectory(clang-rename)
|
||||
add_subdirectory(modularize)
|
||||
add_subdirectory(module-map-checker)
|
||||
add_subdirectory(remove-cstr-calls)
|
||||
|
||||
@@ -13,8 +13,8 @@ include $(CLANG_LEVEL)/../../Makefile.config
|
||||
|
||||
PARALLEL_DIRS := remove-cstr-calls tool-template modularize \
|
||||
module-map-checker pp-trace
|
||||
DIRS := clang-apply-replacements clang-modernize clang-rename clang-tidy \
|
||||
clang-query unittests
|
||||
DIRS := clang-apply-replacements clang-modernize clang-tidy clang-query \
|
||||
unittests
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ int AddOverrideTransform::apply(const CompilationDatabase &Database,
|
||||
// Make Fixer available to handleBeginSource().
|
||||
this->Fixer = &Fixer;
|
||||
|
||||
if (int result = AddOverrideTool.run(createActionFactory(Finder).get())) {
|
||||
if (int result = AddOverrideTool.run(createActionFactory(Finder))) {
|
||||
llvm::errs() << "Error encountered during translation.\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -116,8 +116,7 @@ private:
|
||||
// checking for equality because it can also be part of the preamble if the
|
||||
// preamble is the whole file.
|
||||
unsigned Preamble =
|
||||
Lexer::ComputePreamble(SM.getBuffer(Guard.FID)->getBuffer(), LangOpts)
|
||||
.first;
|
||||
Lexer::ComputePreamble(SM.getBuffer(Guard.FID), LangOpts).first;
|
||||
unsigned IfndefOffset = SM.getFileOffset(Guard.IfndefLoc);
|
||||
if (IfndefOffset > (Preamble + 1))
|
||||
return;
|
||||
|
||||
@@ -49,8 +49,7 @@ private:
|
||||
FactoryAdaptor(MatchFinder &Finder, Transform &Owner)
|
||||
: Finder(Finder), Owner(Owner) {}
|
||||
|
||||
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &,
|
||||
StringRef) {
|
||||
ASTConsumer *CreateASTConsumer(CompilerInstance &, StringRef) {
|
||||
return Finder.newASTConsumer();
|
||||
}
|
||||
|
||||
@@ -129,9 +128,8 @@ Transform::addReplacementForCurrentTU(const clang::tooling::Replacement &R) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<FrontendActionFactory>
|
||||
Transform::createActionFactory(MatchFinder &Finder) {
|
||||
return llvm::make_unique<ActionFactory>(Finder, /*Owner=*/*this);
|
||||
FrontendActionFactory *Transform::createActionFactory(MatchFinder &Finder) {
|
||||
return new ActionFactory(Finder, /*Owner=*/ *this);
|
||||
}
|
||||
|
||||
Version Version::getFromString(llvm::StringRef VersionStr) {
|
||||
|
||||
@@ -208,8 +208,8 @@ protected:
|
||||
///
|
||||
/// The factory returned by this function is responsible for calling back to
|
||||
/// Transform to call handleBeginSource() and handleEndSource().
|
||||
std::unique_ptr<clang::tooling::FrontendActionFactory>
|
||||
createActionFactory(clang::ast_matchers::MatchFinder &Finder);
|
||||
clang::tooling::FrontendActionFactory *
|
||||
createActionFactory(clang::ast_matchers::MatchFinder &Finder);
|
||||
|
||||
private:
|
||||
const std::string Name;
|
||||
|
||||
@@ -48,7 +48,7 @@ int LoopConvertTransform::apply(const CompilationDatabase &Database,
|
||||
LFK_PseudoArray, /*Owner=*/ *this);
|
||||
Finder.addMatcher(makePseudoArrayLoopMatcher(), &PseudoarrrayLoopFixer);
|
||||
|
||||
if (int result = LoopTool.run(createActionFactory(Finder).get())) {
|
||||
if (int result = LoopTool.run(createActionFactory(Finder))) {
|
||||
llvm::errs() << "Error encountered during translation.\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ int PassByValueTransform::apply(const tooling::CompilationDatabase &Database,
|
||||
// make the replacer available to handleBeginSource()
|
||||
this->Replacer = &Replacer;
|
||||
|
||||
if (Tool.run(createActionFactory(Finder).get())) {
|
||||
if (Tool.run(createActionFactory(Finder))) {
|
||||
llvm::errs() << "Error encountered during translation.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ ReplaceAutoPtrTransform::apply(const CompilationDatabase &Database,
|
||||
Finder.addMatcher(makeAutoPtrUsingDeclMatcher(), &Replacer);
|
||||
Finder.addMatcher(makeTransferOwnershipExprMatcher(), &Fixer);
|
||||
|
||||
if (Tool.run(createActionFactory(Finder).get())) {
|
||||
if (Tool.run(createActionFactory(Finder))) {
|
||||
llvm::errs() << "Error encountered during translation.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ int UseAutoTransform::apply(const clang::tooling::CompilationDatabase &Database,
|
||||
Finder.addMatcher(makeIteratorDeclMatcher(), &ReplaceIterators);
|
||||
Finder.addMatcher(makeDeclWithNewMatcher(), &ReplaceNew);
|
||||
|
||||
if (int Result = UseAutoTool.run(createActionFactory(Finder).get())) {
|
||||
if (int Result = UseAutoTool.run(createActionFactory(Finder))) {
|
||||
llvm::errs() << "Error encountered during translation.\n";
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,8 @@ int UseNullptrTransform::apply(const CompilationDatabase &Database,
|
||||
NullptrFixer Fixer(AcceptedChanges, MacroNames, /*Owner=*/ *this);
|
||||
|
||||
Finder.addMatcher(makeCastSequenceMatcher(), &Fixer);
|
||||
if (int result = UseNullptrTool.run(createActionFactory(Finder).get())) {
|
||||
|
||||
if (int result = UseNullptrTool.run(createActionFactory(Finder))) {
|
||||
llvm::errs() << "Error encountered during translation.\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -248,15 +248,14 @@ static CompilerVersions handleSupportedCompilers(const char *ProgName,
|
||||
return RequiredVersions;
|
||||
}
|
||||
|
||||
std::unique_ptr<CompilationDatabase>
|
||||
autoDetectCompilations(std::string &ErrorMessage) {
|
||||
CompilationDatabase *autoDetectCompilations(std::string &ErrorMessage) {
|
||||
// Auto-detect a compilation database from BuildPath.
|
||||
if (BuildPath.getNumOccurrences() > 0)
|
||||
return CompilationDatabase::autoDetectFromDirectory(BuildPath,
|
||||
ErrorMessage);
|
||||
// Try to auto-detect a compilation database from the first source.
|
||||
if (!SourcePaths.empty()) {
|
||||
if (std::unique_ptr<CompilationDatabase> Compilations =
|
||||
if (CompilationDatabase *Compilations =
|
||||
CompilationDatabase::autoDetectFromSource(SourcePaths[0],
|
||||
ErrorMessage)) {
|
||||
// FIXME: just pass SourcePaths[0] once getCompileCommands supports
|
||||
@@ -276,7 +275,7 @@ autoDetectCompilations(std::string &ErrorMessage) {
|
||||
// If no compilation database can be detected from source then we create a
|
||||
// fixed compilation database with c++11 support.
|
||||
std::string CommandLine[] = { "-std=c++11" };
|
||||
return llvm::make_unique<FixedCompilationDatabase>(".", CommandLine);
|
||||
return new FixedCompilationDatabase(".", CommandLine);
|
||||
}
|
||||
|
||||
ErrorMessage = "Could not determine sources to transform";
|
||||
@@ -335,7 +334,7 @@ int main(int argc, const char **argv) {
|
||||
|
||||
if (!Compilations) {
|
||||
std::string ErrorMessage;
|
||||
Compilations = autoDetectCompilations(ErrorMessage);
|
||||
Compilations.reset(autoDetectCompilations(ErrorMessage));
|
||||
if (!Compilations) {
|
||||
llvm::errs() << llvm::sys::path::filename(argv[0]) << ": " << ErrorMessage
|
||||
<< "\n";
|
||||
|
||||
@@ -157,12 +157,23 @@ QueryRef makeInvalidQueryFromDiagnostics(const Diagnostics &Diag) {
|
||||
return new InvalidQuery(OS.str());
|
||||
}
|
||||
|
||||
class QuerySessionSema : public Parser::RegistrySema {
|
||||
public:
|
||||
QuerySessionSema(const QuerySession &QS) : QS(QS) {}
|
||||
|
||||
ast_matchers::dynamic::VariantValue getNamedValue(StringRef Name) override {
|
||||
return QS.NamedValues.lookup(Name);
|
||||
}
|
||||
|
||||
private:
|
||||
const QuerySession &QS;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
QueryRef QueryParser::completeMatcherExpression() {
|
||||
std::vector<MatcherCompletion> Comps = Parser::completeExpression(
|
||||
StringRef(Begin, End - Begin), CompletionPos - Begin, nullptr,
|
||||
&QS.NamedValues);
|
||||
StringRef(Begin, End - Begin), CompletionPos - Begin);
|
||||
for (std::vector<MatcherCompletion>::iterator I = Comps.begin(),
|
||||
E = Comps.end();
|
||||
I != E; ++I) {
|
||||
@@ -183,6 +194,8 @@ QueryRef QueryParser::doParse() {
|
||||
.Case("unlet", PQK_Unlet)
|
||||
.Default(PQK_Invalid);
|
||||
|
||||
QuerySessionSema S(QS);
|
||||
|
||||
switch (QKind) {
|
||||
case PQK_NoOp:
|
||||
return new NoOpQuery;
|
||||
@@ -201,8 +214,8 @@ QueryRef QueryParser::doParse() {
|
||||
|
||||
Diagnostics Diag;
|
||||
ast_matchers::dynamic::VariantValue Value;
|
||||
if (!Parser::parseExpression(StringRef(Begin, End - Begin), nullptr,
|
||||
&QS.NamedValues, &Value, &Diag)) {
|
||||
if (!Parser::parseExpression(StringRef(Begin, End - Begin), &S, &Value,
|
||||
&Diag)) {
|
||||
return makeInvalidQueryFromDiagnostics(Diag);
|
||||
}
|
||||
|
||||
@@ -215,7 +228,7 @@ QueryRef QueryParser::doParse() {
|
||||
|
||||
Diagnostics Diag;
|
||||
Optional<DynTypedMatcher> Matcher = Parser::parseMatcherExpression(
|
||||
StringRef(Begin, End - Begin), nullptr, &QS.NamedValues, &Diag);
|
||||
StringRef(Begin, End - Begin), &S, &Diag);
|
||||
if (!Matcher) {
|
||||
return makeInvalidQueryFromDiagnostics(Diag);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include "QueryParser.h"
|
||||
#include "QuerySession.h"
|
||||
#include "clang/Frontend/ASTUnit.h"
|
||||
#include "clang/Tooling/CommonOptionsParser.h"
|
||||
#include "clang/Tooling/CompilationDatabase.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include "llvm/LineEditor/LineEditor.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
@@ -46,30 +46,45 @@ using namespace clang::query;
|
||||
using namespace clang::tooling;
|
||||
using namespace llvm;
|
||||
|
||||
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
|
||||
static cl::OptionCategory ClangQueryCategory("clang-query options");
|
||||
static cl::opt<std::string> BuildPath("b", cl::desc("Specify build path"),
|
||||
cl::value_desc("<path>"));
|
||||
|
||||
static cl::list<std::string> Commands("c", cl::desc("Specify command to run"),
|
||||
cl::value_desc("command"),
|
||||
cl::cat(ClangQueryCategory));
|
||||
cl::value_desc("<command>"));
|
||||
|
||||
static cl::list<std::string> CommandFiles("f",
|
||||
cl::desc("Read commands from file"),
|
||||
cl::value_desc("file"),
|
||||
cl::cat(ClangQueryCategory));
|
||||
cl::value_desc("<file>"));
|
||||
|
||||
static cl::list<std::string> SourcePaths(cl::Positional,
|
||||
cl::desc("<source0> [... <sourceN>]"),
|
||||
cl::OneOrMore);
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
llvm::sys::PrintStackTraceOnErrorSignal();
|
||||
|
||||
CommonOptionsParser OptionsParser(argc, argv, ClangQueryCategory);
|
||||
cl::ParseCommandLineOptions(argc, argv);
|
||||
|
||||
if (!Commands.empty() && !CommandFiles.empty()) {
|
||||
llvm::errs() << argv[0] << ": cannot specify both -c and -f\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
ClangTool Tool(OptionsParser.getCompilations(),
|
||||
OptionsParser.getSourcePathList());
|
||||
std::unique_ptr<CompilationDatabase> Compilations(
|
||||
FixedCompilationDatabase::loadFromCommandLine(argc, argv));
|
||||
if (!Compilations) { // Couldn't find a compilation DB from the command line
|
||||
std::string ErrorMessage;
|
||||
Compilations.reset(
|
||||
!BuildPath.empty() ?
|
||||
CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage) :
|
||||
CompilationDatabase::autoDetectFromSource(SourcePaths[0], ErrorMessage)
|
||||
);
|
||||
|
||||
// Still no compilation DB? - bail.
|
||||
if (!Compilations)
|
||||
llvm::report_fatal_error(ErrorMessage);
|
||||
}
|
||||
|
||||
ClangTool Tool(*Compilations, SourcePaths);
|
||||
std::vector<std::unique_ptr<ASTUnit>> ASTs;
|
||||
if (Tool.buildASTs(ASTs) != 0)
|
||||
return 1;
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
set(LLVM_LINK_COMPONENTS support)
|
||||
|
||||
add_clang_executable(clang-rename
|
||||
ClangRename.cpp
|
||||
USRFinder.cpp
|
||||
USRFindingAction.cpp
|
||||
USRLocFinder.cpp
|
||||
RenamingAction.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(clang-rename
|
||||
clangAST
|
||||
clangBasic
|
||||
clangFrontend
|
||||
clangIndex
|
||||
clangRewrite
|
||||
clangTooling
|
||||
)
|
||||
|
||||
install(TARGETS clang-rename RUNTIME DESTINATION bin)
|
||||
@@ -1,151 +0,0 @@
|
||||
//===--- tools/extra/clang-rename/ClangRename.cpp - Clang rename tool -----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief This file implements a clang-rename tool that automatically finds and
|
||||
/// renames symbols in C++ code.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "USRFindingAction.h"
|
||||
#include "RenamingAction.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Basic/TargetOptions.h"
|
||||
#include "clang/Frontend/CommandLineSourceLoc.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/FrontendAction.h"
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "clang/Parse/Parser.h"
|
||||
#include "clang/Parse/ParseAST.h"
|
||||
#include "clang/Rewrite/Core/Rewriter.h"
|
||||
#include "clang/Tooling/CommonOptionsParser.h"
|
||||
#include "clang/Tooling/Refactoring.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
cl::OptionCategory ClangRenameCategory("Clang-rename options");
|
||||
|
||||
static cl::opt<std::string>
|
||||
NewName(
|
||||
"new-name",
|
||||
cl::desc("The new name to change the symbol to."),
|
||||
cl::cat(ClangRenameCategory));
|
||||
static cl::opt<unsigned>
|
||||
SymbolOffset(
|
||||
"offset",
|
||||
cl::desc("Locates the symbol by offset as opposed to <line>:<column>."),
|
||||
cl::cat(ClangRenameCategory));
|
||||
static cl::opt<bool>
|
||||
Inplace(
|
||||
"i",
|
||||
cl::desc("Overwrite edited <file>s."),
|
||||
cl::cat(ClangRenameCategory));
|
||||
static cl::opt<bool>
|
||||
PrintName(
|
||||
"pn",
|
||||
cl::desc("Print the found symbol's name prior to renaming to stderr."),
|
||||
cl::cat(ClangRenameCategory));
|
||||
static cl::opt<bool>
|
||||
PrintLocations(
|
||||
"pl",
|
||||
cl::desc("Print the locations affected by renaming to stderr."),
|
||||
cl::cat(ClangRenameCategory));
|
||||
|
||||
#define CLANG_RENAME_VERSION "0.0.1"
|
||||
|
||||
static void PrintVersion() {
|
||||
outs() << "clang-rename version " << CLANG_RENAME_VERSION << "\n";
|
||||
}
|
||||
|
||||
using namespace clang;
|
||||
|
||||
const char RenameUsage[] = "A tool to rename symbols in C/C++ code.\n\
|
||||
clang-rename renames every occurrence of a symbol found at <offset> in\n\
|
||||
<source0>. If -i is specified, the edited files are overwritten to disk.\n\
|
||||
Otherwise, the results are written to stdout.\n";
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
cl::SetVersionPrinter(PrintVersion);
|
||||
tooling::CommonOptionsParser OP(argc, argv, ClangRenameCategory, RenameUsage);
|
||||
|
||||
// Check the arguments for correctness.
|
||||
|
||||
if (NewName.empty()) {
|
||||
errs() << "clang-rename: no new name provided.\n\n";
|
||||
cl::PrintHelpMessage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Get the USRs.
|
||||
auto Files = OP.getSourcePathList();
|
||||
tooling::RefactoringTool Tool(OP.getCompilations(), Files);
|
||||
rename::USRFindingAction USRAction(SymbolOffset);
|
||||
|
||||
// Find the USRs.
|
||||
Tool.run(tooling::newFrontendActionFactory(&USRAction).get());
|
||||
const auto &USRs = USRAction.getUSRs();
|
||||
const auto &PrevName = USRAction.getUSRSpelling();
|
||||
|
||||
if (PrevName.empty())
|
||||
// An error should have already been printed.
|
||||
exit(1);
|
||||
|
||||
if (PrintName)
|
||||
errs() << "clang-rename: found name: " << PrevName;
|
||||
|
||||
// Perform the renaming.
|
||||
rename::RenamingAction RenameAction(NewName, PrevName, USRs,
|
||||
Tool.getReplacements(), PrintLocations);
|
||||
auto Factory = tooling::newFrontendActionFactory(&RenameAction);
|
||||
int res;
|
||||
|
||||
if (Inplace) {
|
||||
res = Tool.runAndSave(Factory.get());
|
||||
} else {
|
||||
res = Tool.run(Factory.get());
|
||||
|
||||
// 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.
|
||||
LangOptions DefaultLangOptions;
|
||||
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
|
||||
new DiagnosticOptions();
|
||||
TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
|
||||
DiagnosticsEngine Diagnostics(
|
||||
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
|
||||
&*DiagOpts, &DiagnosticPrinter, false);
|
||||
auto &FileMgr = Tool.getFiles();
|
||||
SourceManager Sources(Diagnostics, FileMgr);
|
||||
Rewriter Rewrite(Sources, DefaultLangOptions);
|
||||
|
||||
Tool.applyAllReplacements(Rewrite);
|
||||
for (const auto &File : Files) {
|
||||
const auto *Entry = FileMgr.getFile(File);
|
||||
auto ID = Sources.translateFile(Entry);
|
||||
Rewrite.getEditBuffer(ID).write(outs());
|
||||
}
|
||||
}
|
||||
|
||||
exit(res);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
##===- tools/extra/clang-rename/Makefile -------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL := ../../..
|
||||
TOOLNAME = clang-rename
|
||||
include $(CLANG_LEVEL)/../../Makefile.config
|
||||
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
|
||||
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a \
|
||||
clangTooling.a clangParse.a clangSema.a clangIndex.a \
|
||||
clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
|
||||
clangStaticAnalyzerCore.a clangAnalysis.a clangRewriteFrontend.a \
|
||||
clangRewrite.a clangEdit.a clangAST.a clangLex.a clangBasic.a
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
@@ -1,90 +0,0 @@
|
||||
//===--- tools/extra/clang-rename/RenamingAction.cpp - Clang rename tool --===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Provides an action to rename every symbol at a point.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "RenamingAction.h"
|
||||
#include "USRLocFinder.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/FrontendAction.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "clang/Tooling/CommonOptionsParser.h"
|
||||
#include "clang/Tooling/Refactoring.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace clang {
|
||||
namespace rename {
|
||||
|
||||
class RenamingASTConsumer : public ASTConsumer {
|
||||
public:
|
||||
RenamingASTConsumer(const std::string &NewName,
|
||||
const std::string &PrevName,
|
||||
const std::vector<std::string> &USRs,
|
||||
tooling::Replacements &Replaces,
|
||||
bool PrintLocations)
|
||||
: NewName(NewName), PrevName(PrevName), USRs(USRs), Replaces(Replaces),
|
||||
PrintLocations(PrintLocations) {
|
||||
}
|
||||
|
||||
void HandleTranslationUnit(ASTContext &Context) override {
|
||||
const auto &SourceMgr = Context.getSourceManager();
|
||||
std::vector<SourceLocation> RenamingCandidates;
|
||||
std::vector<SourceLocation> NewCandidates;
|
||||
|
||||
for (const auto &USR : USRs) {
|
||||
NewCandidates = getLocationsOfUSR(USR, Context.getTranslationUnitDecl());
|
||||
RenamingCandidates.insert(RenamingCandidates.end(), NewCandidates.begin(),
|
||||
NewCandidates.end());
|
||||
NewCandidates.clear();
|
||||
}
|
||||
|
||||
auto PrevNameLen = PrevName.length();
|
||||
if (PrintLocations)
|
||||
for (const auto &Loc : RenamingCandidates) {
|
||||
FullSourceLoc FullLoc(Loc, SourceMgr);
|
||||
errs() << "clang-rename: renamed at: " << SourceMgr.getFilename(Loc)
|
||||
<< ":" << FullLoc.getSpellingLineNumber() << ":"
|
||||
<< FullLoc.getSpellingColumnNumber() << "\n";
|
||||
Replaces.insert(tooling::Replacement(SourceMgr, Loc, PrevNameLen,
|
||||
NewName));
|
||||
}
|
||||
else
|
||||
for (const auto &Loc : RenamingCandidates)
|
||||
Replaces.insert(tooling::Replacement(SourceMgr, Loc, PrevNameLen,
|
||||
NewName));
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string &NewName, &PrevName;
|
||||
const std::vector<std::string> &USRs;
|
||||
tooling::Replacements &Replaces;
|
||||
bool PrintLocations;
|
||||
};
|
||||
|
||||
std::unique_ptr<ASTConsumer> RenamingAction::newASTConsumer() {
|
||||
return llvm::make_unique<RenamingASTConsumer>(NewName, PrevName, USRs,
|
||||
Replaces, PrintLocations);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
//===--- tools/extra/clang-rename/RenamingAction.h - Clang rename tool ----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Provides an action to rename every symbol at a point.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_RENAMING_ACTION_H_
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_RENAMING_ACTION_H_
|
||||
|
||||
#include "clang/Tooling/Refactoring.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTConsumer;
|
||||
class CompilerInstance;
|
||||
|
||||
namespace rename {
|
||||
|
||||
class RenamingAction {
|
||||
public:
|
||||
RenamingAction(const std::string &NewName, const std::string &PrevName,
|
||||
const std::vector<std::string> &USRs,
|
||||
tooling::Replacements &Replaces, bool PrintLocations = false)
|
||||
: NewName(NewName), PrevName(PrevName), USRs(USRs), Replaces(Replaces),
|
||||
PrintLocations(PrintLocations) {
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTConsumer> newASTConsumer();
|
||||
|
||||
private:
|
||||
const std::string &NewName, &PrevName;
|
||||
const std::vector<std::string> &USRs;
|
||||
tooling::Replacements &Replaces;
|
||||
bool PrintLocations;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_RENAMING_ACTION_H_
|
||||
@@ -1,162 +0,0 @@
|
||||
//===--- tools/extra/clang-rename/USRFinder.cpp - Clang rename tool -------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file Implements a recursive AST visitor that finds the USR of a symbol at a
|
||||
/// point.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "USRFinder.h"
|
||||
#include "clang/AST/AST.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "clang/Index/USRGeneration.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace clang {
|
||||
namespace rename {
|
||||
|
||||
// NamedDeclFindingASTVisitor recursively visits each AST node to find the
|
||||
// symbol underneath the cursor.
|
||||
// FIXME: move to seperate .h/.cc file if this gets too large.
|
||||
namespace {
|
||||
class NamedDeclFindingASTVisitor
|
||||
: public clang::RecursiveASTVisitor<NamedDeclFindingASTVisitor> {
|
||||
public:
|
||||
// \brief Finds the NamedDecl at a point in the source.
|
||||
// \param Point the location in the source to search for the NamedDecl.
|
||||
explicit NamedDeclFindingASTVisitor(const SourceManager &SourceMgr,
|
||||
const SourceLocation Point)
|
||||
: Result(nullptr), SourceMgr(SourceMgr),
|
||||
Point(Point) {
|
||||
}
|
||||
|
||||
// Declaration visitors:
|
||||
|
||||
// \brief Checks if the point falls within the NameDecl. This covers every
|
||||
// declaration of a named entity that we may come across. Usually, just
|
||||
// checking if the point lies within the length of the name of the declaration
|
||||
// and the start location is sufficient.
|
||||
bool VisitNamedDecl(const NamedDecl *Decl) {
|
||||
return setResult(Decl, Decl->getLocation(),
|
||||
Decl->getNameAsString().length());
|
||||
}
|
||||
|
||||
// Expression visitors:
|
||||
|
||||
bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
|
||||
// Check the namespace specifier first.
|
||||
if (!checkNestedNameSpecifierLoc(Expr->getQualifierLoc()))
|
||||
return false;
|
||||
|
||||
const auto *Decl = Expr->getFoundDecl();
|
||||
return setResult(Decl, Expr->getLocation(),
|
||||
Decl->getNameAsString().length());
|
||||
}
|
||||
|
||||
bool VisitMemberExpr(const MemberExpr *Expr) {
|
||||
const auto *Decl = Expr->getFoundDecl().getDecl();
|
||||
return setResult(Decl, Expr->getMemberLoc(),
|
||||
Decl->getNameAsString().length());
|
||||
}
|
||||
|
||||
// Other:
|
||||
|
||||
const NamedDecl *getNamedDecl() {
|
||||
return Result;
|
||||
}
|
||||
|
||||
private:
|
||||
// \brief Determines if a namespace qualifier contains the point.
|
||||
// \returns false on success and sets Result.
|
||||
bool checkNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
|
||||
while (NameLoc) {
|
||||
const auto *Decl = NameLoc.getNestedNameSpecifier()->getAsNamespace();
|
||||
if (Decl && !setResult(Decl, NameLoc.getLocalBeginLoc(),
|
||||
Decl->getNameAsString().length()))
|
||||
return false;
|
||||
NameLoc = NameLoc.getPrefix();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// \brief Sets Result to Decl if the Point is within Start and End.
|
||||
// \returns false on success.
|
||||
bool setResult(const NamedDecl *Decl, SourceLocation Start,
|
||||
SourceLocation End) {
|
||||
if (!Start.isValid() || !Start.isFileID() || !End.isValid() ||
|
||||
!End.isFileID() || !isPointWithin(Start, End)) {
|
||||
return true;
|
||||
}
|
||||
Result = Decl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// \brief Sets Result to Decl if Point is within Loc and Loc + Offset.
|
||||
// \returns false on success.
|
||||
bool setResult(const NamedDecl *Decl, SourceLocation Loc,
|
||||
unsigned Offset) {
|
||||
// FIXME: Add test for Offset == 0. Add test for Offset - 1 (vs -2 etc).
|
||||
return Offset == 0 ||
|
||||
setResult(Decl, Loc, Loc.getLocWithOffset(Offset - 1));
|
||||
}
|
||||
|
||||
// \brief Determines if the Point is within Start and End.
|
||||
bool isPointWithin(const SourceLocation Start, const SourceLocation End) {
|
||||
// FIXME: Add tests for Point == End.
|
||||
return Point == Start || Point == End ||
|
||||
(SourceMgr.isBeforeInTranslationUnit(Start, Point) &&
|
||||
SourceMgr.isBeforeInTranslationUnit(Point, End));
|
||||
}
|
||||
|
||||
const NamedDecl *Result;
|
||||
const SourceManager &SourceMgr;
|
||||
const SourceLocation Point; // The location to find the NamedDecl.
|
||||
};
|
||||
}
|
||||
|
||||
const NamedDecl *getNamedDeclAt(const ASTContext &Context,
|
||||
const SourceLocation Point) {
|
||||
const auto &SourceMgr = Context.getSourceManager();
|
||||
const auto SearchFile = SourceMgr.getFilename(Point);
|
||||
|
||||
NamedDeclFindingASTVisitor Visitor(SourceMgr, Point);
|
||||
|
||||
// We only want to search the decls that exist in the same file as the point.
|
||||
auto Decls = Context.getTranslationUnitDecl()->decls();
|
||||
for (auto &CurrDecl : Decls) {
|
||||
const auto FileLoc = CurrDecl->getLocStart();
|
||||
const auto FileName = SourceMgr.getFilename(FileLoc);
|
||||
// FIXME: Add test.
|
||||
if (FileName == SearchFile) {
|
||||
Visitor.TraverseDecl(CurrDecl);
|
||||
if (const NamedDecl *Result = Visitor.getNamedDecl()) {
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string getUSRForDecl(const Decl *Decl) {
|
||||
llvm::SmallVector<char, 128> Buff;
|
||||
|
||||
// FIXME: Add test for the nullptr case.
|
||||
if (Decl == nullptr || index::generateUSRForDecl(Decl, Buff))
|
||||
return "";
|
||||
|
||||
return std::string(Buff.data(), Buff.size());
|
||||
}
|
||||
|
||||
} // namespace clang
|
||||
} // namespace rename
|
||||
@@ -1,39 +0,0 @@
|
||||
//===--- tools/extra/clang-rename/USRFinder.h - Clang rename tool ---------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Methods for determining the USR of a symbol at a location in source
|
||||
/// code.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDER_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class Decl;
|
||||
class SourceLocation;
|
||||
class NamedDecl;
|
||||
|
||||
namespace rename {
|
||||
|
||||
// Given an AST context and a point, returns a NamedDecl identifying the symbol
|
||||
// at the point. Returns null if nothing is found at the point.
|
||||
const NamedDecl *getNamedDeclAt(const ASTContext &Context,
|
||||
const SourceLocation Point);
|
||||
|
||||
// Converts a Decl into a USR.
|
||||
std::string getUSRForDecl(const Decl *Decl);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDER_H
|
||||
@@ -1,118 +0,0 @@
|
||||
//===--- tools/extra/clang-rename/USRFindingAction.cpp - Clang rename tool ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Provides an action to rename every symbol at a point.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "USRFindingAction.h"
|
||||
#include "USRFinder.h"
|
||||
#include "clang/AST/AST.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/FrontendAction.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "clang/Tooling/CommonOptionsParser.h"
|
||||
#include "clang/Tooling/Refactoring.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace clang {
|
||||
namespace rename {
|
||||
|
||||
// Get the USRs for the constructors of the class.
|
||||
static std::vector<std::string> getAllConstructorUSRs(
|
||||
const CXXRecordDecl *Decl) {
|
||||
std::vector<std::string> USRs;
|
||||
|
||||
// We need to get the definition of the record (as opposed to any forward
|
||||
// declarations) in order to find the constructor and destructor.
|
||||
const auto *RecordDecl = Decl->getDefinition();
|
||||
|
||||
// Iterate over all the constructors and add their USRs.
|
||||
for (const auto &CtorDecl : RecordDecl->ctors())
|
||||
USRs.push_back(getUSRForDecl(CtorDecl));
|
||||
|
||||
// Ignore destructors. GetLocationsOfUSR will find the declaration of and
|
||||
// explicit calls to a destructor through TagTypeLoc (and it is better for the
|
||||
// purpose of renaming).
|
||||
//
|
||||
// For example, in the following code segment,
|
||||
// 1 class C {
|
||||
// 2 ~C();
|
||||
// 3 };
|
||||
// At line 3, there is a NamedDecl starting from '~' and a TagTypeLoc starting
|
||||
// from 'C'.
|
||||
|
||||
return USRs;
|
||||
}
|
||||
|
||||
struct NamedDeclFindingConsumer : public ASTConsumer {
|
||||
void HandleTranslationUnit(ASTContext &Context) override {
|
||||
const auto &SourceMgr = Context.getSourceManager();
|
||||
// The file we look for the USR in will always be the main source file.
|
||||
const auto Point = SourceMgr.getLocForStartOfFile(
|
||||
SourceMgr.getMainFileID()).getLocWithOffset(SymbolOffset);
|
||||
if (!Point.isValid())
|
||||
return;
|
||||
const NamedDecl *FoundDecl = getNamedDeclAt(Context, Point);
|
||||
if (FoundDecl == nullptr) {
|
||||
FullSourceLoc FullLoc(Point, SourceMgr);
|
||||
errs() << "clang-rename: could not find symbol at "
|
||||
<< SourceMgr.getFilename(Point) << ":"
|
||||
<< FullLoc.getSpellingLineNumber() << ":"
|
||||
<< FullLoc.getSpellingColumnNumber() << " (offset " << SymbolOffset
|
||||
<< ").\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// If the decl is a constructor or destructor, we want to instead take the
|
||||
// decl of the parent record.
|
||||
if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl))
|
||||
FoundDecl = CtorDecl->getParent();
|
||||
else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(FoundDecl))
|
||||
FoundDecl = DtorDecl->getParent();
|
||||
|
||||
// If the decl is in any way relatedpp to a class, we want to make sure we
|
||||
// search for the constructor and destructor as well as everything else.
|
||||
if (const auto *Record = dyn_cast<CXXRecordDecl>(FoundDecl))
|
||||
*USRs = getAllConstructorUSRs(Record);
|
||||
|
||||
USRs->push_back(getUSRForDecl(FoundDecl));
|
||||
*SpellingName = FoundDecl->getNameAsString();
|
||||
}
|
||||
|
||||
unsigned SymbolOffset;
|
||||
std::string *SpellingName;
|
||||
std::vector<std::string> *USRs;
|
||||
};
|
||||
|
||||
std::unique_ptr<ASTConsumer>
|
||||
USRFindingAction::newASTConsumer() {
|
||||
std::unique_ptr<NamedDeclFindingConsumer> Consumer(
|
||||
new NamedDeclFindingConsumer);
|
||||
SpellingName = "";
|
||||
Consumer->SymbolOffset = SymbolOffset;
|
||||
Consumer->USRs = &USRs;
|
||||
Consumer->SpellingName = &SpellingName;
|
||||
return std::move(Consumer);
|
||||
}
|
||||
|
||||
} // namespace rename
|
||||
} // namespace clang
|
||||
@@ -1,50 +0,0 @@
|
||||
//===--- tools/extra/clang-rename/USRFindingAction.h - Clang rename tool --===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Provides an action to find all relevent USRs at a point.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDING_ACTION_H_
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDING_ACTION_H_
|
||||
|
||||
#include "clang/Frontend/FrontendAction.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTConsumer;
|
||||
class CompilerInstance;
|
||||
class NamedDecl;
|
||||
|
||||
namespace rename {
|
||||
|
||||
struct USRFindingAction {
|
||||
USRFindingAction(unsigned Offset) : SymbolOffset(Offset) {
|
||||
}
|
||||
std::unique_ptr<ASTConsumer> newASTConsumer();
|
||||
|
||||
// \brief get the spelling of the USR(s) as it would appear in source files.
|
||||
const std::string &getUSRSpelling() {
|
||||
return SpellingName;
|
||||
}
|
||||
|
||||
const std::vector<std::string> &getUSRs() {
|
||||
return USRs;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned SymbolOffset;
|
||||
std::string SpellingName;
|
||||
std::vector<std::string> USRs;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDING_ACTION_H_
|
||||
@@ -1,103 +0,0 @@
|
||||
//===--- tools/extra/clang-rename/USRLocFinder.cpp - Clang rename tool ----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Mehtods for finding all instances of a USR. Our strategy is very
|
||||
/// simple; we just compare the USR at every relevant AST node with the one
|
||||
/// provided.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "USRLocFinder.h"
|
||||
#include "USRFinder.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Index/USRGeneration.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace clang {
|
||||
namespace rename {
|
||||
|
||||
namespace {
|
||||
// \brief This visitor recursively searches for all instances of a USR in a
|
||||
// translation unit and stores them for later usage.
|
||||
class USRLocFindingASTVisitor
|
||||
: public clang::RecursiveASTVisitor<USRLocFindingASTVisitor> {
|
||||
public:
|
||||
explicit USRLocFindingASTVisitor(const std::string USR) : USR(USR) {
|
||||
}
|
||||
|
||||
// Declaration visitors:
|
||||
|
||||
bool VisitNamedDecl(const NamedDecl *Decl) {
|
||||
if (getUSRForDecl(Decl) == USR) {
|
||||
LocationsFound.push_back(Decl->getLocation());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Expression visitors:
|
||||
|
||||
bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
|
||||
const auto *Decl = Expr->getFoundDecl();
|
||||
|
||||
checkNestedNameSpecifierLoc(Expr->getQualifierLoc());
|
||||
if (getUSRForDecl(Decl) == USR) {
|
||||
LocationsFound.push_back(Expr->getLocation());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitMemberExpr(const MemberExpr *Expr) {
|
||||
const auto *Decl = Expr->getFoundDecl().getDecl();
|
||||
if (getUSRForDecl(Decl) == USR) {
|
||||
LocationsFound.push_back(Expr->getMemberLoc());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Non-visitors:
|
||||
|
||||
// \brief Returns a list of unique locations. Duplicate or overlapping
|
||||
// locations are erroneous and should be reported!
|
||||
const std::vector<clang::SourceLocation> &getLocationsFound() const {
|
||||
return LocationsFound;
|
||||
}
|
||||
|
||||
private:
|
||||
// Namespace traversal:
|
||||
void checkNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
|
||||
while (NameLoc) {
|
||||
const auto *Decl = NameLoc.getNestedNameSpecifier()->getAsNamespace();
|
||||
if (Decl && getUSRForDecl(Decl) == USR)
|
||||
LocationsFound.push_back(NameLoc.getLocalBeginLoc());
|
||||
NameLoc = NameLoc.getPrefix();
|
||||
}
|
||||
}
|
||||
|
||||
// All the locations of the USR were found.
|
||||
const std::string USR;
|
||||
std::vector<clang::SourceLocation> LocationsFound;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
std::vector<SourceLocation> getLocationsOfUSR(const std::string USR,
|
||||
Decl *Decl) {
|
||||
USRLocFindingASTVisitor visitor(USR);
|
||||
|
||||
visitor.TraverseDecl(Decl);
|
||||
return visitor.getLocationsFound();
|
||||
}
|
||||
|
||||
} // namespace rename
|
||||
} // namespace clang
|
||||
@@ -1,35 +0,0 @@
|
||||
//===--- tools/extra/clang-rename/USRLocFinder.h - Clang rename tool ------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Provides functionality for finding all instances of a USR in a given
|
||||
/// AST.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_LOC_FINDER_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_LOC_FINDER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Decl;
|
||||
class SourceLocation;
|
||||
|
||||
namespace rename {
|
||||
|
||||
// FIXME: make this an AST matcher. Wouldn't that be awesome??? I agree!
|
||||
std::vector<SourceLocation> getLocationsOfUSR(const std::string usr,
|
||||
Decl *decl);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_LOC_FINDER_H
|
||||
@@ -27,4 +27,3 @@ add_subdirectory(tool)
|
||||
add_subdirectory(llvm)
|
||||
add_subdirectory(google)
|
||||
add_subdirectory(misc)
|
||||
add_subdirectory(utils)
|
||||
|
||||
@@ -179,10 +179,10 @@ private:
|
||||
|
||||
class ClangTidyASTConsumer : public MultiplexConsumer {
|
||||
public:
|
||||
ClangTidyASTConsumer(std::vector<std::unique_ptr<ASTConsumer>> Consumers,
|
||||
ClangTidyASTConsumer(const SmallVectorImpl<ASTConsumer *> &Consumers,
|
||||
std::unique_ptr<ast_matchers::MatchFinder> Finder,
|
||||
std::vector<std::unique_ptr<ClangTidyCheck>> Checks)
|
||||
: MultiplexConsumer(std::move(Consumers)), Finder(std::move(Finder)),
|
||||
: MultiplexConsumer(Consumers), Finder(std::move(Finder)),
|
||||
Checks(std::move(Checks)) {}
|
||||
|
||||
private:
|
||||
@@ -203,8 +203,8 @@ ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<clang::ASTConsumer>
|
||||
ClangTidyASTConsumerFactory::CreateASTConsumer(
|
||||
|
||||
clang::ASTConsumer *ClangTidyASTConsumerFactory::CreateASTConsumer(
|
||||
clang::CompilerInstance &Compiler, StringRef File) {
|
||||
// FIXME: Move this to a separate method, so that CreateASTConsumer doesn't
|
||||
// modify Compiler.
|
||||
@@ -213,7 +213,7 @@ ClangTidyASTConsumerFactory::CreateASTConsumer(
|
||||
Context.setASTContext(&Compiler.getASTContext());
|
||||
|
||||
std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
|
||||
GlobList &Filter = Context.getChecksFilter();
|
||||
ChecksFilter &Filter = Context.getChecksFilter();
|
||||
CheckFactories->createChecks(Filter, Checks);
|
||||
|
||||
std::unique_ptr<ast_matchers::MatchFinder> Finder(
|
||||
@@ -224,7 +224,7 @@ ClangTidyASTConsumerFactory::CreateASTConsumer(
|
||||
Check->registerPPCallbacks(Compiler);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<ASTConsumer>> Consumers;
|
||||
SmallVector<ASTConsumer *, 2> Consumers;
|
||||
if (!Checks.empty())
|
||||
Consumers.push_back(Finder->newASTConsumer());
|
||||
|
||||
@@ -240,23 +240,22 @@ ClangTidyASTConsumerFactory::CreateASTConsumer(
|
||||
AnalyzerOptions->AnalysisDiagOpt = PD_NONE;
|
||||
AnalyzerOptions->AnalyzeNestedBlocks = true;
|
||||
AnalyzerOptions->eagerlyAssumeBinOpBifurcation = true;
|
||||
std::unique_ptr<ento::AnalysisASTConsumer> AnalysisConsumer =
|
||||
ento::CreateAnalysisConsumer(
|
||||
Compiler.getPreprocessor(), Compiler.getFrontendOpts().OutputFile,
|
||||
AnalyzerOptions, Compiler.getFrontendOpts().Plugins);
|
||||
ento::AnalysisASTConsumer *AnalysisConsumer = ento::CreateAnalysisConsumer(
|
||||
Compiler.getPreprocessor(), Compiler.getFrontendOpts().OutputFile,
|
||||
AnalyzerOptions, Compiler.getFrontendOpts().Plugins);
|
||||
AnalysisConsumer->AddDiagnosticConsumer(
|
||||
new AnalyzerDiagnosticConsumer(Context));
|
||||
Consumers.push_back(std::move(AnalysisConsumer));
|
||||
Consumers.push_back(AnalysisConsumer);
|
||||
}
|
||||
return llvm::make_unique<ClangTidyASTConsumer>(
|
||||
std::move(Consumers), std::move(Finder), std::move(Checks));
|
||||
return new ClangTidyASTConsumer(Consumers, std::move(Finder),
|
||||
std::move(Checks));
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
ClangTidyASTConsumerFactory::getCheckNames(GlobList &Filter) {
|
||||
ClangTidyASTConsumerFactory::getCheckNames(ChecksFilter &Filter) {
|
||||
std::vector<std::string> CheckNames;
|
||||
for (const auto &CheckFactory : *CheckFactories) {
|
||||
if (Filter.contains(CheckFactory.first))
|
||||
if (Filter.isCheckEnabled(CheckFactory.first))
|
||||
CheckNames.push_back(CheckFactory.first);
|
||||
}
|
||||
|
||||
@@ -268,7 +267,7 @@ ClangTidyASTConsumerFactory::getCheckNames(GlobList &Filter) {
|
||||
}
|
||||
|
||||
ClangTidyASTConsumerFactory::CheckersList
|
||||
ClangTidyASTConsumerFactory::getCheckersControlList(GlobList &Filter) {
|
||||
ClangTidyASTConsumerFactory::getCheckersControlList(ChecksFilter &Filter) {
|
||||
CheckersList List;
|
||||
|
||||
bool AnalyzerChecksEnabled = false;
|
||||
@@ -276,7 +275,7 @@ ClangTidyASTConsumerFactory::getCheckersControlList(GlobList &Filter) {
|
||||
std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
|
||||
AnalyzerChecksEnabled =
|
||||
AnalyzerChecksEnabled ||
|
||||
(!CheckName.startswith("debug") && Filter.contains(Checker));
|
||||
(!CheckName.startswith("debug") && Filter.isCheckEnabled(Checker));
|
||||
}
|
||||
|
||||
if (AnalyzerChecksEnabled) {
|
||||
@@ -291,7 +290,7 @@ ClangTidyASTConsumerFactory::getCheckersControlList(GlobList &Filter) {
|
||||
std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
|
||||
|
||||
if (CheckName.startswith("core") ||
|
||||
(!CheckName.startswith("debug") && Filter.contains(Checker)))
|
||||
(!CheckName.startswith("debug") && Filter.isCheckEnabled(Checker)))
|
||||
List.push_back(std::make_pair(CheckName, true));
|
||||
}
|
||||
}
|
||||
@@ -332,15 +331,16 @@ ClangTidyStats runClangTidy(ClangTidyOptionsProvider *OptionsProvider,
|
||||
|
||||
class ActionFactory : public FrontendActionFactory {
|
||||
public:
|
||||
ActionFactory(ClangTidyContext &Context) : ConsumerFactory(Context) {}
|
||||
FrontendAction *create() override { return new Action(&ConsumerFactory); }
|
||||
ActionFactory(ClangTidyASTConsumerFactory *ConsumerFactory)
|
||||
: ConsumerFactory(ConsumerFactory) {}
|
||||
FrontendAction *create() override { return new Action(ConsumerFactory); }
|
||||
|
||||
private:
|
||||
class Action : public ASTFrontendAction {
|
||||
public:
|
||||
Action(ClangTidyASTConsumerFactory *Factory) : Factory(Factory) {}
|
||||
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
|
||||
StringRef File) override {
|
||||
ASTConsumer *CreateASTConsumer(CompilerInstance &Compiler,
|
||||
StringRef File) override {
|
||||
return Factory->CreateASTConsumer(Compiler, File);
|
||||
}
|
||||
|
||||
@@ -348,11 +348,10 @@ ClangTidyStats runClangTidy(ClangTidyOptionsProvider *OptionsProvider,
|
||||
ClangTidyASTConsumerFactory *Factory;
|
||||
};
|
||||
|
||||
ClangTidyASTConsumerFactory ConsumerFactory;
|
||||
ClangTidyASTConsumerFactory *ConsumerFactory;
|
||||
};
|
||||
|
||||
ActionFactory Factory(Context);
|
||||
Tool.run(&Factory);
|
||||
Tool.run(new ActionFactory(new ClangTidyASTConsumerFactory(Context)));
|
||||
*Errors = Context.getErrors();
|
||||
return Context.getStats();
|
||||
}
|
||||
|
||||
@@ -99,15 +99,15 @@ public:
|
||||
ClangTidyASTConsumerFactory(ClangTidyContext &Context);
|
||||
|
||||
/// \brief Returns an ASTConsumer that runs the specified clang-tidy checks.
|
||||
std::unique_ptr<clang::ASTConsumer>
|
||||
CreateASTConsumer(clang::CompilerInstance &Compiler, StringRef File);
|
||||
clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &Compiler,
|
||||
StringRef File);
|
||||
|
||||
/// \brief Get the list of enabled checks.
|
||||
std::vector<std::string> getCheckNames(GlobList &Filter);
|
||||
std::vector<std::string> getCheckNames(ChecksFilter &Filter);
|
||||
|
||||
private:
|
||||
typedef std::vector<std::pair<std::string, bool> > CheckersList;
|
||||
CheckersList getCheckersControlList(GlobList &Filter);
|
||||
CheckersList getCheckersControlList(ChecksFilter &Filter);
|
||||
|
||||
ClangTidyContext &Context;
|
||||
std::unique_ptr<ClangTidyCheckFactories> CheckFactories;
|
||||
|
||||
@@ -146,18 +146,18 @@ static llvm::Regex ConsumeGlob(StringRef &GlobList) {
|
||||
return llvm::Regex(RegexText);
|
||||
}
|
||||
|
||||
GlobList::GlobList(StringRef Globs)
|
||||
: Positive(!ConsumeNegativeIndicator(Globs)),
|
||||
Regex(ConsumeGlob(Globs)),
|
||||
NextGlob(Globs.empty() ? nullptr : new GlobList(Globs)) {}
|
||||
ChecksFilter::ChecksFilter(StringRef GlobList)
|
||||
: Positive(!ConsumeNegativeIndicator(GlobList)),
|
||||
Regex(ConsumeGlob(GlobList)),
|
||||
NextFilter(GlobList.empty() ? nullptr : new ChecksFilter(GlobList)) {}
|
||||
|
||||
bool GlobList::contains(StringRef S, bool Contains) {
|
||||
if (Regex.match(S))
|
||||
Contains = Positive;
|
||||
bool ChecksFilter::isCheckEnabled(StringRef Name, bool Enabled) {
|
||||
if (Regex.match(Name))
|
||||
Enabled = Positive;
|
||||
|
||||
if (NextGlob)
|
||||
Contains = NextGlob->contains(S, Contains);
|
||||
return Contains;
|
||||
if (NextFilter)
|
||||
Enabled = NextFilter->isCheckEnabled(Name, Enabled);
|
||||
return Enabled;
|
||||
}
|
||||
|
||||
ClangTidyContext::ClangTidyContext(ClangTidyOptionsProvider *OptionsProvider)
|
||||
@@ -202,7 +202,7 @@ void ClangTidyContext::setSourceManager(SourceManager *SourceMgr) {
|
||||
|
||||
void ClangTidyContext::setCurrentFile(StringRef File) {
|
||||
CurrentFile = File;
|
||||
CheckFilter.reset(new GlobList(getOptions().Checks));
|
||||
CheckFilter.reset(new ChecksFilter(getOptions().Checks));
|
||||
}
|
||||
|
||||
void ClangTidyContext::setASTContext(ASTContext *Context) {
|
||||
@@ -217,7 +217,7 @@ const ClangTidyOptions &ClangTidyContext::getOptions() const {
|
||||
return OptionsProvider->getOptions(CurrentFile);
|
||||
}
|
||||
|
||||
GlobList &ClangTidyContext::getChecksFilter() {
|
||||
ChecksFilter &ClangTidyContext::getChecksFilter() {
|
||||
assert(CheckFilter != nullptr);
|
||||
return *CheckFilter;
|
||||
}
|
||||
@@ -248,7 +248,7 @@ ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx)
|
||||
void ClangTidyDiagnosticConsumer::finalizeLastError() {
|
||||
if (!Errors.empty()) {
|
||||
ClangTidyError &Error = Errors.back();
|
||||
if (!Context.getChecksFilter().contains(Error.CheckName) &&
|
||||
if (!Context.getChecksFilter().isCheckEnabled(Error.CheckName) &&
|
||||
Error.DiagLevel != ClangTidyError::Error) {
|
||||
++Context.Stats.ErrorsIgnoredCheckFilter;
|
||||
Errors.pop_back();
|
||||
|
||||
@@ -65,25 +65,24 @@ struct ClangTidyError {
|
||||
Level DiagLevel;
|
||||
};
|
||||
|
||||
/// \brief Read-only set of strings represented as a list of positive and
|
||||
/// negative globs. Positive globs add all matched strings to the set, negative
|
||||
/// globs remove them in the order of appearance in the list.
|
||||
class GlobList {
|
||||
/// \brief Filters checks by name.
|
||||
class ChecksFilter {
|
||||
public:
|
||||
/// \brief \p GlobList is a comma-separated list of globs (only '*'
|
||||
/// metacharacter is supported) with optional '-' prefix to denote exclusion.
|
||||
GlobList(StringRef Globs);
|
||||
ChecksFilter(StringRef GlobList);
|
||||
|
||||
/// \brief Returns \c true if the pattern matches \p S. The result is the last
|
||||
/// matching glob's Positive flag.
|
||||
bool contains(StringRef S) { return contains(S, false); }
|
||||
/// \brief Returns \c true if the check with the specified \p Name should be
|
||||
/// enabled. The result is the last matching glob's Positive flag. If \p Name
|
||||
/// is not matched by any globs, the check is not enabled.
|
||||
bool isCheckEnabled(StringRef Name) { return isCheckEnabled(Name, false); }
|
||||
|
||||
private:
|
||||
bool contains(StringRef S, bool Contains);
|
||||
bool isCheckEnabled(StringRef Name, bool Enabled);
|
||||
|
||||
bool Positive;
|
||||
llvm::Regex Regex;
|
||||
std::unique_ptr<GlobList> NextGlob;
|
||||
std::unique_ptr<ChecksFilter> NextFilter;
|
||||
};
|
||||
|
||||
/// \brief Contains displayed and ignored diagnostic counters for a ClangTidy
|
||||
@@ -146,7 +145,7 @@ public:
|
||||
StringRef getCheckName(unsigned DiagnosticID) const;
|
||||
|
||||
/// \brief Returns check filter for the \c CurrentFile.
|
||||
GlobList &getChecksFilter();
|
||||
ChecksFilter &getChecksFilter();
|
||||
|
||||
/// \brief Returns global options.
|
||||
const ClangTidyGlobalOptions &getGlobalOptions() const;
|
||||
@@ -180,7 +179,7 @@ private:
|
||||
std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
|
||||
|
||||
std::string CurrentFile;
|
||||
std::unique_ptr<GlobList> CheckFilter;
|
||||
std::unique_ptr<ChecksFilter> CheckFilter;
|
||||
|
||||
ClangTidyStats Stats;
|
||||
|
||||
|
||||
@@ -27,9 +27,10 @@ void ClangTidyCheckFactories::addCheckFactory(StringRef Name,
|
||||
}
|
||||
|
||||
void ClangTidyCheckFactories::createChecks(
|
||||
GlobList &Filter, std::vector<std::unique_ptr<ClangTidyCheck>> &Checks) {
|
||||
ChecksFilter &Filter,
|
||||
std::vector<std::unique_ptr<ClangTidyCheck>> &Checks) {
|
||||
for (const auto &Factory : Factories) {
|
||||
if (Filter.contains(Factory.first)) {
|
||||
if (Filter.isCheckEnabled(Factory.first)) {
|
||||
ClangTidyCheck *Check = Factory.second->createCheck();
|
||||
Check->setName(Factory.first);
|
||||
Checks.emplace_back(Check);
|
||||
|
||||
@@ -86,7 +86,7 @@ public:
|
||||
/// store them in \p Checks.
|
||||
///
|
||||
/// The caller takes ownership of the return \c ClangTidyChecks.
|
||||
void createChecks(GlobList &Filter,
|
||||
void createChecks(ChecksFilter &Filter,
|
||||
std::vector<std::unique_ptr<ClangTidyCheck>> &Checks);
|
||||
|
||||
typedef std::map<std::string, CheckFactoryBase *> FactoryMap;
|
||||
|
||||
@@ -11,6 +11,6 @@ CLANG_LEVEL := ../../..
|
||||
LIBRARYNAME := clangTidy
|
||||
include $(CLANG_LEVEL)/../../Makefile.config
|
||||
|
||||
DIRS = utils llvm google misc tool
|
||||
DIRS = llvm google misc tool
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
||||
@@ -60,12 +60,6 @@ bool pointedTypesAreEqual(QualType SourceType, QualType DestType) {
|
||||
void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
const auto *CastExpr = Result.Nodes.getNodeAs<CStyleCastExpr>("cast");
|
||||
|
||||
auto ParenRange = CharSourceRange::getTokenRange(CastExpr->getLParenLoc(),
|
||||
CastExpr->getRParenLoc());
|
||||
// Ignore casts in macros.
|
||||
if (ParenRange.getBegin().isMacroID() || ParenRange.getEnd().isMacroID())
|
||||
return;
|
||||
|
||||
// Casting to void is an idiomatic way to mute "unused variable" and similar
|
||||
// warnings.
|
||||
if (CastExpr->getTypeAsWritten()->isVoidType())
|
||||
@@ -75,6 +69,8 @@ void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
CastExpr->getSubExprAsWritten()->getType().getCanonicalType();
|
||||
QualType DestType = CastExpr->getTypeAsWritten().getCanonicalType();
|
||||
|
||||
auto ParenRange = CharSourceRange::getTokenRange(CastExpr->getLParenLoc(),
|
||||
CastExpr->getRParenLoc());
|
||||
if (SourceType == DestType) {
|
||||
diag(CastExpr->getLocStart(), "Redundant cast to the same type.")
|
||||
<< FixItHint::CreateRemoval(ParenRange);
|
||||
@@ -88,6 +84,8 @@ void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
|
||||
auto ReplaceWithCast = [&](StringRef CastType) {
|
||||
diag_builder << ("Use " + CastType + ".").str();
|
||||
if (ParenRange.getBegin().isMacroID() || ParenRange.getEnd().isMacroID())
|
||||
return;
|
||||
|
||||
const Expr *SubExpr = CastExpr->getSubExprAsWritten()->IgnoreImpCasts();
|
||||
std::string CastText = (CastType + "<" + DestTypeString + ">").str();
|
||||
|
||||
@@ -20,6 +20,15 @@ namespace ast_matchers {
|
||||
AST_MATCHER(DeclRefExpr, hasExplicitTemplateArgs) {
|
||||
return Node.hasExplicitTemplateArgs();
|
||||
}
|
||||
|
||||
// FIXME: This should just be callee(ignoringImpCasts()) but it's not overloaded
|
||||
// for Expr.
|
||||
AST_MATCHER_P(CallExpr, calleeIgnoringParenImpCasts, internal::Matcher<Stmt>,
|
||||
InnerMatcher) {
|
||||
const Expr *ExprNode = Node.getCallee();
|
||||
return (ExprNode != nullptr &&
|
||||
InnerMatcher.matches(*ExprNode->IgnoreParenImpCasts(), Finder, Builder));
|
||||
}
|
||||
} // namespace ast_matchers
|
||||
|
||||
namespace tidy {
|
||||
@@ -33,10 +42,10 @@ ExplicitMakePairCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
|
||||
callExpr(unless(hasAncestor(decl(anyOf(
|
||||
recordDecl(ast_matchers::isTemplateInstantiation()),
|
||||
functionDecl(ast_matchers::isTemplateInstantiation()))))),
|
||||
callee(expr(ignoringParenImpCasts(
|
||||
calleeIgnoringParenImpCasts(
|
||||
declRefExpr(hasExplicitTemplateArgs(),
|
||||
to(functionDecl(hasName("::std::make_pair"))))
|
||||
.bind("declref"))))).bind("call"),
|
||||
.bind("declref"))).bind("call"),
|
||||
this);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,14 +37,6 @@ void NamedParameterCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
if (Function->isImplicit())
|
||||
return;
|
||||
|
||||
// Ignore declarations without a definition if we're not dealing with an
|
||||
// overriden method.
|
||||
const FunctionDecl *Definition = nullptr;
|
||||
if (!Function->isDefined(Definition) &&
|
||||
(!isa<CXXMethodDecl>(Function) ||
|
||||
cast<CXXMethodDecl>(Function)->size_overridden_methods() == 0))
|
||||
return;
|
||||
|
||||
// TODO: Handle overloads.
|
||||
// TODO: We could check that all redeclarations use the same name for
|
||||
// arguments in the same position.
|
||||
@@ -78,34 +70,25 @@ void NamedParameterCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
"all parameters should be named in a function");
|
||||
|
||||
for (auto P : UnnamedParams) {
|
||||
// Fallback to an unused marker.
|
||||
StringRef NewName = "unused";
|
||||
|
||||
// If the method is overridden, try to copy the name from the base method
|
||||
// into the overrider.
|
||||
const ParmVarDecl *Parm = P.first->getParamDecl(P.second);
|
||||
const auto *M = dyn_cast<CXXMethodDecl>(P.first);
|
||||
if (M && M->size_overridden_methods() > 0) {
|
||||
const ParmVarDecl *OtherParm =
|
||||
(*M->begin_overridden_methods())->getParamDecl(P.second);
|
||||
StringRef Name = OtherParm->getName();
|
||||
if (!Name.empty())
|
||||
NewName = Name;
|
||||
std::string Name = OtherParm->getNameAsString();
|
||||
if (!Name.empty()) {
|
||||
D << FixItHint::CreateInsertion(Parm->getLocation(),
|
||||
" /*" + Name + "*/");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If the definition has a named parameter use that name.
|
||||
if (Definition) {
|
||||
const ParmVarDecl *DefParm = Definition->getParamDecl(P.second);
|
||||
StringRef Name = DefParm->getName();
|
||||
if (!Name.empty())
|
||||
NewName = Name;
|
||||
}
|
||||
|
||||
// Now insert the comment. Note that getLocation() points to the place
|
||||
// where the name would be, this allows us to also get complex cases like
|
||||
// function pointers right.
|
||||
const ParmVarDecl *Parm = P.first->getParamDecl(P.second);
|
||||
D << FixItHint::CreateInsertion(Parm->getLocation(),
|
||||
" /*" + NewName.str() + "*/");
|
||||
// Otherwise just insert an unused marker. Note that getLocation() points
|
||||
// to the place where the name would be, this allows us to also get
|
||||
// complex cases like function pointers right.
|
||||
D << FixItHint::CreateInsertion(Parm->getLocation(), " /*unused*/");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
set(LLVM_LINK_COMPONENTS support)
|
||||
|
||||
add_clang_library(clangTidyLLVMModule
|
||||
HeaderGuardCheck.cpp
|
||||
IncludeOrderCheck.cpp
|
||||
LLVMTidyModule.cpp
|
||||
NamespaceCommentCheck.cpp
|
||||
@@ -13,6 +12,4 @@ add_clang_library(clangTidyLLVMModule
|
||||
clangBasic
|
||||
clangLex
|
||||
clangTidy
|
||||
clangTidyUtils
|
||||
clangTooling
|
||||
)
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
//===--- HeaderGuardCheck.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 "HeaderGuardCheck.h"
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
|
||||
bool LLVMHeaderGuardCheck::shouldFixHeaderGuard(StringRef Filename) {
|
||||
return Filename.endswith(".h");
|
||||
}
|
||||
|
||||
std::string LLVMHeaderGuardCheck::getHeaderGuard(StringRef Filename,
|
||||
StringRef OldGuard) {
|
||||
std::string Guard = tooling::getAbsolutePath(Filename);
|
||||
|
||||
// Sanitize the path. There are some rules for compatibility with the historic
|
||||
// style in include/llvm and include/clang which we want to preserve.
|
||||
|
||||
// We don't want _INCLUDE_ in our guards.
|
||||
size_t PosInclude = Guard.rfind("include/");
|
||||
if (PosInclude != StringRef::npos)
|
||||
Guard = Guard.substr(PosInclude + std::strlen("include/"));
|
||||
|
||||
// For clang we drop the _TOOLS_.
|
||||
size_t PosToolsClang = Guard.rfind("tools/clang/");
|
||||
if (PosToolsClang != StringRef::npos)
|
||||
Guard = Guard.substr(PosToolsClang + std::strlen("tools/"));
|
||||
|
||||
// The remainder is LLVM_FULL_PATH_TO_HEADER_H
|
||||
size_t PosLLVM = Guard.rfind("llvm/");
|
||||
if (PosLLVM != StringRef::npos)
|
||||
Guard = Guard.substr(PosLLVM);
|
||||
|
||||
std::replace(Guard.begin(), Guard.end(), '/', '_');
|
||||
std::replace(Guard.begin(), Guard.end(), '.', '_');
|
||||
std::replace(Guard.begin(), Guard.end(), '-', '_');
|
||||
|
||||
// The prevalent style in clang is LLVM_CLANG_FOO_BAR_H
|
||||
if (StringRef(Guard).startswith("clang"))
|
||||
Guard = "LLVM_" + Guard;
|
||||
|
||||
return StringRef(Guard).upper();
|
||||
}
|
||||
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
||||
@@ -1,29 +0,0 @@
|
||||
//===--- HeaderGuardCheck.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_LLVM_HEADER_GUARD_CHECK_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_HEADER_GUARD_CHECK_H
|
||||
|
||||
#include "../utils/HeaderGuard.h"
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
|
||||
/// Finds and fixes header guards that do not adhere to LLVM style.
|
||||
class LLVMHeaderGuardCheck : public HeaderGuardCheck {
|
||||
public:
|
||||
bool shouldSuggestEndifComment(StringRef Filename) override { return false; }
|
||||
bool shouldFixHeaderGuard(StringRef Filename) override;
|
||||
std::string getHeaderGuard(StringRef Filename, StringRef OldGuard) override;
|
||||
};
|
||||
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_HEADER_GUARD_CHECK_H
|
||||
@@ -18,148 +18,26 @@ namespace tidy {
|
||||
namespace {
|
||||
class IncludeOrderPPCallbacks : public PPCallbacks {
|
||||
public:
|
||||
explicit IncludeOrderPPCallbacks(ClangTidyCheck &Check, SourceManager &SM)
|
||||
: LookForMainModule(true), Check(Check), SM(SM) {}
|
||||
explicit IncludeOrderPPCallbacks(IncludeOrderCheck &Check) : Check(Check) {}
|
||||
|
||||
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
|
||||
StringRef FileName, bool IsAngled,
|
||||
CharSourceRange FilenameRange, const FileEntry *File,
|
||||
StringRef SearchPath, StringRef RelativePath,
|
||||
const Module *Imported) override;
|
||||
void EndOfMainFile() override;
|
||||
const Module *Imported) override {
|
||||
// FIXME: This is a dummy implementation to show how to get at preprocessor
|
||||
// information. Implement a real include order check.
|
||||
Check.diag(HashLoc, "This is an include");
|
||||
}
|
||||
|
||||
private:
|
||||
struct IncludeDirective {
|
||||
SourceLocation Loc; ///< '#' location in the include directive
|
||||
CharSourceRange Range; ///< SourceRange for the file name
|
||||
StringRef Filename; ///< Filename as a string
|
||||
bool IsAngled; ///< true if this was an include with angle brackets
|
||||
bool IsMainModule; ///< true if this was the first include in a file
|
||||
};
|
||||
std::vector<IncludeDirective> IncludeDirectives;
|
||||
bool LookForMainModule;
|
||||
|
||||
ClangTidyCheck &Check;
|
||||
SourceManager &SM;
|
||||
IncludeOrderCheck &Check;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void IncludeOrderCheck::registerPPCallbacks(CompilerInstance &Compiler) {
|
||||
Compiler.getPreprocessor().addPPCallbacks(
|
||||
new IncludeOrderPPCallbacks(*this, Compiler.getSourceManager()));
|
||||
}
|
||||
|
||||
static int getPriority(StringRef Filename, bool IsAngled, bool IsMainModule) {
|
||||
// We leave the main module header at the top.
|
||||
if (IsMainModule)
|
||||
return 0;
|
||||
|
||||
// LLVM and clang headers are in the penultimate position.
|
||||
if (Filename.startswith("llvm/") || Filename.startswith("llvm-c/") ||
|
||||
Filename.startswith("clang/") || Filename.startswith("clang-c/"))
|
||||
return 2;
|
||||
|
||||
// System headers are sorted to the end.
|
||||
if (IsAngled || Filename.startswith("gtest/"))
|
||||
return 3;
|
||||
|
||||
// Other headers are inserted between the main module header and LLVM headers.
|
||||
return 1;
|
||||
}
|
||||
|
||||
void IncludeOrderPPCallbacks::InclusionDirective(
|
||||
SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
|
||||
bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
|
||||
StringRef SearchPath, StringRef RelativePath, const Module *Imported) {
|
||||
// We recognize the first include as a special main module header and want
|
||||
// to leave it in the top position.
|
||||
IncludeDirective ID = {HashLoc, FilenameRange, FileName, IsAngled, false};
|
||||
if (LookForMainModule && !IsAngled) {
|
||||
ID.IsMainModule = true;
|
||||
LookForMainModule = false;
|
||||
}
|
||||
IncludeDirectives.push_back(std::move(ID));
|
||||
}
|
||||
|
||||
void IncludeOrderPPCallbacks::EndOfMainFile() {
|
||||
LookForMainModule = true;
|
||||
if (IncludeDirectives.empty())
|
||||
return;
|
||||
|
||||
// TODO: find duplicated includes.
|
||||
|
||||
// Form blocks of includes. We don't want to sort across blocks. This also
|
||||
// implicitly makes us never reorder over #defines or #if directives.
|
||||
// FIXME: We should be more careful about sorting below comments as we don't
|
||||
// know if the comment refers to the next include or the whole block that
|
||||
// follows.
|
||||
std::vector<unsigned> Blocks(1, 0);
|
||||
for (unsigned I = 1, E = IncludeDirectives.size(); I != E; ++I)
|
||||
if (SM.getExpansionLineNumber(IncludeDirectives[I].Loc) !=
|
||||
SM.getExpansionLineNumber(IncludeDirectives[I - 1].Loc) + 1)
|
||||
Blocks.push_back(I);
|
||||
Blocks.push_back(IncludeDirectives.size()); // Sentinel value.
|
||||
|
||||
// Get a vector of indices.
|
||||
std::vector<unsigned> IncludeIndices;
|
||||
for (unsigned I = 0, E = IncludeDirectives.size(); I != E; ++I)
|
||||
IncludeIndices.push_back(I);
|
||||
|
||||
// Sort the includes. We first sort by priority, then lexicographically.
|
||||
for (unsigned BI = 0, BE = Blocks.size() - 1; BI != BE; ++BI)
|
||||
std::sort(IncludeIndices.begin() + Blocks[BI],
|
||||
IncludeIndices.begin() + Blocks[BI + 1],
|
||||
[this](unsigned LHSI, unsigned RHSI) {
|
||||
IncludeDirective &LHS = IncludeDirectives[LHSI];
|
||||
IncludeDirective &RHS = IncludeDirectives[RHSI];
|
||||
|
||||
int PriorityLHS =
|
||||
getPriority(LHS.Filename, LHS.IsAngled, LHS.IsMainModule);
|
||||
int PriorityRHS =
|
||||
getPriority(RHS.Filename, RHS.IsAngled, RHS.IsMainModule);
|
||||
|
||||
return std::tie(PriorityLHS, LHS.Filename) <
|
||||
std::tie(PriorityRHS, RHS.Filename);
|
||||
});
|
||||
|
||||
// Emit a warning for each block and fixits for all changes within that block.
|
||||
for (unsigned BI = 0, BE = Blocks.size() - 1; BI != BE; ++BI) {
|
||||
// Find the first include that's not in the right position.
|
||||
unsigned I, E;
|
||||
for (I = Blocks[BI], E = Blocks[BI + 1]; I != E; ++I)
|
||||
if (IncludeIndices[I] != I)
|
||||
break;
|
||||
|
||||
if (I == E)
|
||||
continue;
|
||||
|
||||
// Emit a warning.
|
||||
auto D = Check.diag(IncludeDirectives[I].Loc,
|
||||
"#includes are not sorted properly");
|
||||
|
||||
// Emit fix-its for all following includes in this block.
|
||||
for (; I != E; ++I) {
|
||||
if (IncludeIndices[I] == I)
|
||||
continue;
|
||||
const IncludeDirective &CopyFrom = IncludeDirectives[IncludeIndices[I]];
|
||||
|
||||
SourceLocation FromLoc = CopyFrom.Range.getBegin();
|
||||
const char *FromData = SM.getCharacterData(FromLoc);
|
||||
unsigned FromLen = std::strcspn(FromData, "\n");
|
||||
|
||||
StringRef FixedName(FromData, FromLen);
|
||||
|
||||
SourceLocation ToLoc = IncludeDirectives[I].Range.getBegin();
|
||||
const char *ToData = SM.getCharacterData(ToLoc);
|
||||
unsigned ToLen = std::strcspn(ToData, "\n");
|
||||
auto ToRange =
|
||||
CharSourceRange::getCharRange(ToLoc, ToLoc.getLocWithOffset(ToLen));
|
||||
|
||||
D << FixItHint::CreateReplacement(ToRange, FixedName);
|
||||
}
|
||||
}
|
||||
|
||||
IncludeDirectives.clear();
|
||||
Compiler.getPreprocessor()
|
||||
.addPPCallbacks(new IncludeOrderPPCallbacks(*this));
|
||||
}
|
||||
|
||||
} // namespace tidy
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "../ClangTidy.h"
|
||||
#include "../ClangTidyModule.h"
|
||||
#include "../ClangTidyModuleRegistry.h"
|
||||
#include "HeaderGuardCheck.h"
|
||||
#include "IncludeOrderCheck.h"
|
||||
#include "NamespaceCommentCheck.h"
|
||||
#include "TwineLocalCheck.h"
|
||||
@@ -21,8 +20,6 @@ namespace tidy {
|
||||
class LLVMModule : public ClangTidyModule {
|
||||
public:
|
||||
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
|
||||
CheckFactories.addCheckFactory(
|
||||
"llvm-header-guard", new ClangTidyCheckFactory<LLVMHeaderGuardCheck>());
|
||||
CheckFactories.addCheckFactory(
|
||||
"llvm-include-order", new ClangTidyCheckFactory<IncludeOrderCheck>());
|
||||
CheckFactories.addCheckFactory(
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ArgumentCommentCheck.h"
|
||||
#include "../ClangTidy.h"
|
||||
#include "../ClangTidyModule.h"
|
||||
#include "../ClangTidyModuleRegistry.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
@@ -22,15 +25,7 @@ ArgumentCommentCheck::ArgumentCommentCheck()
|
||||
: IdentRE("^(/\\* *)([_A-Za-z][_A-Za-z0-9]*)( *= *\\*/)$") {}
|
||||
|
||||
void ArgumentCommentCheck::registerMatchers(MatchFinder *Finder) {
|
||||
Finder->addMatcher(
|
||||
callExpr(unless(operatorCallExpr()),
|
||||
// NewCallback's arguments relate to the pointed function, don't
|
||||
// check them against NewCallback's parameter names.
|
||||
// FIXME: Make this configurable.
|
||||
unless(hasDeclaration(functionDecl(anyOf(
|
||||
hasName("NewCallback"), hasName("NewPermanentCallback"))))))
|
||||
.bind("expr"),
|
||||
this);
|
||||
Finder->addMatcher(callExpr(unless(operatorCallExpr())).bind("expr"), this);
|
||||
Finder->addMatcher(constructExpr().bind("expr"), this);
|
||||
}
|
||||
|
||||
@@ -86,10 +81,10 @@ ArgumentCommentCheck::isLikelyTypo(llvm::ArrayRef<ParmVarDecl *> Params,
|
||||
if (ThisED >= UpperBound)
|
||||
return false;
|
||||
|
||||
for (unsigned I = 0, E = Params.size(); I != E; ++I) {
|
||||
if (I == ArgIndex)
|
||||
for (const auto &Param : Params) {
|
||||
if (&Param - Params.begin() == ArgIndex)
|
||||
continue;
|
||||
IdentifierInfo *II = Params[I]->getIdentifier();
|
||||
IdentifierInfo *II = Param->getIdentifier();
|
||||
if (!II)
|
||||
continue;
|
||||
|
||||
|
||||
@@ -24,9 +24,6 @@ AST_MATCHER(QualType, isBoolean) { return Node->isBooleanType(); }
|
||||
namespace tidy {
|
||||
|
||||
void BoolPointerImplicitConversion::registerMatchers(MatchFinder *Finder) {
|
||||
auto InTemplateInstantiation = hasAncestor(
|
||||
decl(anyOf(recordDecl(ast_matchers::isTemplateInstantiation()),
|
||||
functionDecl(ast_matchers::isTemplateInstantiation()))));
|
||||
// Look for ifs that have an implicit bool* to bool conversion in the
|
||||
// condition. Filter negations.
|
||||
Finder->addMatcher(
|
||||
@@ -35,8 +32,7 @@ void BoolPointerImplicitConversion::registerMatchers(MatchFinder *Finder) {
|
||||
hasSourceExpression(expr(
|
||||
hasType(pointerType(pointee(isBoolean()))),
|
||||
ignoringParenImpCasts(declRefExpr().bind("expr")))),
|
||||
isPointerToBoolean())))),
|
||||
unless(InTemplateInstantiation)).bind("if"),
|
||||
isPointerToBoolean()))))).bind("if"),
|
||||
this);
|
||||
}
|
||||
|
||||
@@ -45,10 +41,6 @@ BoolPointerImplicitConversion::check(const MatchFinder::MatchResult &Result) {
|
||||
auto *If = Result.Nodes.getStmtAs<IfStmt>("if");
|
||||
auto *Var = Result.Nodes.getStmtAs<DeclRefExpr>("expr");
|
||||
|
||||
// Ignore macros.
|
||||
if (Var->getLocStart().isMacroID())
|
||||
return;
|
||||
|
||||
// Only allow variable accesses for now, no function calls or member exprs.
|
||||
// Check that we don't dereference the variable anywhere within the if. This
|
||||
// avoids false positives for checks of the pointer for nullptr before it is
|
||||
|
||||
@@ -6,8 +6,6 @@ add_clang_library(clangTidyMiscModule
|
||||
MiscTidyModule.cpp
|
||||
RedundantSmartptrGet.cpp
|
||||
SwappedArgumentsCheck.cpp
|
||||
UndelegatedConstructor.cpp
|
||||
UnusedRAII.cpp
|
||||
UseOverride.cpp
|
||||
|
||||
LINK_LIBS
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
#include "BoolPointerImplicitConversion.h"
|
||||
#include "RedundantSmartptrGet.h"
|
||||
#include "SwappedArgumentsCheck.h"
|
||||
#include "UndelegatedConstructor.h"
|
||||
#include "UnusedRAII.h"
|
||||
#include "UseOverride.h"
|
||||
|
||||
namespace clang {
|
||||
@@ -36,12 +34,6 @@ public:
|
||||
CheckFactories.addCheckFactory(
|
||||
"misc-swapped-arguments",
|
||||
new ClangTidyCheckFactory<SwappedArgumentsCheck>());
|
||||
CheckFactories.addCheckFactory(
|
||||
"misc-undelegated-constructor",
|
||||
new ClangTidyCheckFactory<UndelegatedConstructorCheck>());
|
||||
CheckFactories.addCheckFactory(
|
||||
"misc-unused-raii",
|
||||
new ClangTidyCheckFactory<UnusedRAIICheck>());
|
||||
CheckFactories.addCheckFactory(
|
||||
"misc-use-override",
|
||||
new ClangTidyCheckFactory<UseOverride>());
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
//===--- UndelegatedConstructor.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 "UndelegatedConstructor.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
|
||||
using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang {
|
||||
|
||||
namespace ast_matchers {
|
||||
AST_MATCHER_P(Stmt, ignoringTemporaryExpr, internal::Matcher<Stmt>,
|
||||
InnerMatcher) {
|
||||
const Stmt *E = &Node;
|
||||
for (;;) {
|
||||
// Temporaries with non-trivial dtors.
|
||||
if (const auto *EWC = dyn_cast<ExprWithCleanups>(E))
|
||||
E = EWC->getSubExpr();
|
||||
// Temporaries with zero or more than two ctor arguments.
|
||||
else if (const auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))
|
||||
E = BTE->getSubExpr();
|
||||
// Temporaries with exactly one ctor argument.
|
||||
else if (const auto *FCE = dyn_cast<CXXFunctionalCastExpr>(E))
|
||||
E = FCE->getSubExpr();
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return InnerMatcher.matches(*E, Finder, Builder);
|
||||
}
|
||||
|
||||
// Finds a node if it's a base of an already bound node.
|
||||
AST_MATCHER_P(CXXRecordDecl, baseOfBoundNode, std::string, ID) {
|
||||
return Builder->removeBindings([&](const internal::BoundNodesMap &Nodes) {
|
||||
const auto *Derived = Nodes.getNodeAs<CXXRecordDecl>(ID);
|
||||
return Derived != &Node && !Derived->isDerivedFrom(&Node);
|
||||
});
|
||||
}
|
||||
} // namespace ast_matchers
|
||||
|
||||
namespace tidy {
|
||||
|
||||
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,
|
||||
// depending on the type's destructor and the number of arguments on the
|
||||
// constructor call, this is handled by ignoringTemporaryExpr. Ignore template
|
||||
// instantiations to reduce the number of duplicated warnings.
|
||||
Finder->addMatcher(
|
||||
compoundStmt(
|
||||
hasParent(constructorDecl(ofClass(recordDecl().bind("parent")))),
|
||||
forEach(ignoringTemporaryExpr(
|
||||
constructExpr(hasDeclaration(constructorDecl(ofClass(
|
||||
recordDecl(baseOfBoundNode("parent"))))))
|
||||
.bind("construct"))),
|
||||
unless(hasAncestor(decl(
|
||||
anyOf(recordDecl(ast_matchers::isTemplateInstantiation()),
|
||||
functionDecl(ast_matchers::isTemplateInstantiation())))))),
|
||||
this);
|
||||
}
|
||||
|
||||
void UndelegatedConstructorCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
const auto *E = Result.Nodes.getStmtAs<CXXConstructExpr>("construct");
|
||||
diag(E->getLocStart(), "did you intend to call a delegated constructor? "
|
||||
"A temporary object is created here instead");
|
||||
}
|
||||
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
||||
@@ -1,30 +0,0 @@
|
||||
//===--- UndelegatedConstructor.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_UNDELEGATED_CONSTRUCTOR_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNDELEGATED_CONSTRUCTOR_H
|
||||
|
||||
#include "../ClangTidy.h"
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
|
||||
/// \brief Finds creation of temporary objects in constructors that look like a
|
||||
/// function call to another constructor of the same class. The user most likely
|
||||
/// meant to use a delegating constructor or base class initializer.
|
||||
class UndelegatedConstructorCheck : public ClangTidyCheck {
|
||||
public:
|
||||
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
|
||||
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
|
||||
};
|
||||
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNDELEGATED_CONSTRUCTOR_H
|
||||
@@ -1,86 +0,0 @@
|
||||
//===--- UnusedRAII.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 "UnusedRAII.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
|
||||
using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang {
|
||||
namespace ast_matchers {
|
||||
AST_MATCHER(CXXRecordDecl, hasUserDeclaredDestructor) {
|
||||
// TODO: If the dtor is there but empty we don't want to warn either.
|
||||
return Node.hasDefinition() && Node.hasUserDeclaredDestructor();
|
||||
}
|
||||
} // namespace ast_matchers
|
||||
|
||||
namespace tidy {
|
||||
|
||||
void UnusedRAIICheck::registerMatchers(MatchFinder *Finder) {
|
||||
// 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 = bindTemporaryExpr(unless(has(callExpr()))).bind("temp");
|
||||
Finder->addMatcher(
|
||||
exprWithCleanups(
|
||||
unless(hasAncestor(decl(
|
||||
anyOf(recordDecl(ast_matchers::isTemplateInstantiation()),
|
||||
functionDecl(ast_matchers::isTemplateInstantiation()))))),
|
||||
hasParent(compoundStmt().bind("compound")),
|
||||
hasType(recordDecl(hasUserDeclaredDestructor())),
|
||||
anyOf(has(BindTemp), has(functionalCastExpr(has(BindTemp)))))
|
||||
.bind("expr"),
|
||||
this);
|
||||
}
|
||||
|
||||
void UnusedRAIICheck::check(const MatchFinder::MatchResult &Result) {
|
||||
const auto *E = Result.Nodes.getStmtAs<Expr>("expr");
|
||||
|
||||
// We ignore code expanded from macros to reduce the number of false
|
||||
// positives.
|
||||
if (E->getLocStart().isMacroID())
|
||||
return;
|
||||
|
||||
// Don't emit a warning for the last statement in the surrounding compund
|
||||
// statement.
|
||||
const auto *CS = Result.Nodes.getStmtAs<CompoundStmt>("compound");
|
||||
if (E == CS->body_back())
|
||||
return;
|
||||
|
||||
// Emit a warning.
|
||||
auto D = diag(E->getLocStart(), "object destroyed immediately after "
|
||||
"creation; did you mean to name the object?");
|
||||
const char *Replacement = " give_me_a_name";
|
||||
|
||||
// If this is a default ctor we have to remove the parens or we'll introduce a
|
||||
// most vexing parse.
|
||||
const auto *BTE = Result.Nodes.getStmtAs<CXXBindTemporaryExpr>("temp");
|
||||
if (const auto *TOE = dyn_cast<CXXTemporaryObjectExpr>(BTE->getSubExpr()))
|
||||
if (TOE->getNumArgs() == 0) {
|
||||
D << FixItHint::CreateReplacement(
|
||||
CharSourceRange::getTokenRange(TOE->getParenOrBraceRange()),
|
||||
Replacement);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise just suggest adding a name. To find the place to insert the name
|
||||
// find the first TypeLoc in the children of E, which always points to the
|
||||
// written type.
|
||||
auto Matches =
|
||||
match(expr(hasDescendant(typeLoc().bind("t"))), *E, *Result.Context);
|
||||
const auto *TL = selectFirst<TypeLoc>("t", Matches);
|
||||
D << FixItHint::CreateInsertion(
|
||||
Lexer::getLocForEndOfToken(TL->getLocEnd(), 0, *Result.SourceManager,
|
||||
Result.Context->getLangOpts()),
|
||||
Replacement);
|
||||
}
|
||||
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
||||
@@ -1,47 +0,0 @@
|
||||
//===--- UnusedRAII.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_UNUSED_RAII_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNUSED_RAII_H
|
||||
|
||||
#include "../ClangTidy.h"
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
|
||||
/// \brief Finds temporaries that look like RAII objects.
|
||||
///
|
||||
/// The canonical example for this is a scoped lock.
|
||||
/// \code
|
||||
/// {
|
||||
/// scoped_lock(&global_mutex);
|
||||
/// critical_section();
|
||||
/// }
|
||||
/// \endcode
|
||||
/// The destructor of the scoped_lock is called before the critical_section is
|
||||
/// entered, leaving it unprotected.
|
||||
///
|
||||
/// We apply a number of heuristics to reduce the false positive count of this
|
||||
/// check:
|
||||
/// - Ignore code expanded from macros. Testing frameworks make heavy use of
|
||||
/// this.
|
||||
/// - Ignore types with no user-declared constructor. Those are very unlikely
|
||||
/// to be RAII objects.
|
||||
/// - Ignore objects at the end of a compound statement (doesn't change behavior).
|
||||
/// - Ignore objects returned from a call.
|
||||
class UnusedRAIICheck : public ClangTidyCheck {
|
||||
public:
|
||||
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
|
||||
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
|
||||
};
|
||||
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNUSED_RAII_H
|
||||
@@ -74,8 +74,8 @@ void UseOverride::check(const MatchFinder::MatchResult &Result) {
|
||||
DiagnosticBuilder Diag = diag(
|
||||
Method->getLocation(),
|
||||
OnlyVirtualSpecified
|
||||
? "Prefer using 'override' or (rarely) 'final' instead of 'virtual'"
|
||||
: "Annotate this function with 'override' or (rarely) 'final'");
|
||||
? "Prefer using 'override' or 'final' instead of 'virtual'"
|
||||
: "Use exactly one of 'virtual', 'override' or (rarely) 'final'");
|
||||
|
||||
CharSourceRange FileRange = Lexer::makeFileCharRange(
|
||||
CharSourceRange::getTokenRange(Method->getSourceRange()), Sources,
|
||||
|
||||
@@ -17,7 +17,7 @@ TOOL_NO_EXPORTS = 1
|
||||
include $(CLANG_LEVEL)/../../Makefile.config
|
||||
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
|
||||
USEDLIBS = clangTidy.a clangTidyLLVMModule.a clangTidyGoogleModule.a \
|
||||
clangTidyMiscModule.a clangTidyUtils.a \
|
||||
clangTidyMiscModule.a \
|
||||
clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
|
||||
clangStaticAnalyzerCore.a \
|
||||
clangFormat.a clangASTMatchers.a clangTooling.a clangFrontend.a \
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
set(LLVM_LINK_COMPONENTS support)
|
||||
|
||||
add_clang_library(clangTidyUtils
|
||||
HeaderGuard.cpp
|
||||
|
||||
LINK_LIBS
|
||||
clangAST
|
||||
clangASTMatchers
|
||||
clangBasic
|
||||
clangLex
|
||||
clangTidy
|
||||
)
|
||||
@@ -1,257 +0,0 @@
|
||||
//===--- HeaderGuard.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 "HeaderGuard.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Lex/PPCallbacks.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
|
||||
/// \brief canonicalize a path by removing ./ and ../ components.
|
||||
// FIXME: Consider moving this to llvm::sys::path.
|
||||
static std::string cleanPath(StringRef Path) {
|
||||
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 += '/';
|
||||
NewPath += *I;
|
||||
}
|
||||
}
|
||||
return NewPath.str();
|
||||
}
|
||||
|
||||
namespace {
|
||||
class HeaderGuardPPCallbacks : public PPCallbacks {
|
||||
public:
|
||||
explicit HeaderGuardPPCallbacks(Preprocessor *PP, HeaderGuardCheck *Check)
|
||||
: PP(PP), Check(Check) {}
|
||||
|
||||
void FileChanged(SourceLocation Loc, FileChangeReason Reason,
|
||||
SrcMgr::CharacteristicKind FileType,
|
||||
FileID PrevFID) override {
|
||||
// Record all files we enter. We'll need them to diagnose headers without
|
||||
// guards.
|
||||
SourceManager &SM = PP->getSourceManager();
|
||||
if (Reason == EnterFile && FileType == SrcMgr::C_User) {
|
||||
if (const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Loc))) {
|
||||
std::string FileName = cleanPath(FE->getName());
|
||||
Files[FileName] = FE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDirective *MD) override {
|
||||
if (MD)
|
||||
return;
|
||||
|
||||
// Record #ifndefs that succeeded. We also need the Location of the Name.
|
||||
Ifndefs[MacroNameTok.getIdentifierInfo()] =
|
||||
std::make_pair(Loc, MacroNameTok.getLocation());
|
||||
}
|
||||
|
||||
void MacroDefined(const Token &MacroNameTok,
|
||||
const MacroDirective *MD) override {
|
||||
// Record all defined macros. We store the whole token to get info on the
|
||||
// name later.
|
||||
Macros.emplace_back(MacroNameTok, MD);
|
||||
}
|
||||
|
||||
void Endif(SourceLocation Loc, SourceLocation IfLoc) override {
|
||||
// Record all #endif and the corresponding #ifs (including #ifndefs).
|
||||
EndIfs[IfLoc] = Loc;
|
||||
}
|
||||
|
||||
void EndOfMainFile() override {
|
||||
// Now that we have all this information from the preprocessor, use it!
|
||||
SourceManager &SM = PP->getSourceManager();
|
||||
|
||||
for (const auto &MacroEntry : Macros) {
|
||||
const MacroInfo *MI = MacroEntry.second->getMacroInfo();
|
||||
|
||||
// We use clang's header guard detection. This has the advantage of also
|
||||
// emitting a warning for cases where a pseudo header guard is found but
|
||||
// preceeded by something blocking the header guard optimization.
|
||||
if (!MI->isUsedForHeaderGuard())
|
||||
continue;
|
||||
|
||||
const FileEntry *FE =
|
||||
SM.getFileEntryForID(SM.getFileID(MI->getDefinitionLoc()));
|
||||
std::string FileName = cleanPath(FE->getName());
|
||||
Files.erase(FileName);
|
||||
|
||||
// See if we should check and fix this header guard.
|
||||
if (!Check->shouldFixHeaderGuard(FileName))
|
||||
continue;
|
||||
|
||||
// Look up Locations for this guard.
|
||||
SourceLocation Ifndef =
|
||||
Ifndefs[MacroEntry.first.getIdentifierInfo()].second;
|
||||
SourceLocation Define = MacroEntry.first.getLocation();
|
||||
SourceLocation EndIf =
|
||||
EndIfs[Ifndefs[MacroEntry.first.getIdentifierInfo()].first];
|
||||
|
||||
// If the macro Name is not equal to what we can compute, correct it in
|
||||
// the
|
||||
// #ifndef and #define.
|
||||
StringRef CurHeaderGuard =
|
||||
MacroEntry.first.getIdentifierInfo()->getName();
|
||||
std::string NewGuard =
|
||||
checkHeaderGuardDefinition(Ifndef, Define, FileName, CurHeaderGuard);
|
||||
|
||||
// Now look at the #endif. We want a comment with the header guard. Fix it
|
||||
// at the slightest deviation.
|
||||
if (Check->shouldSuggestEndifComment(FileName))
|
||||
checkEndifComment(EndIf, NewGuard);
|
||||
}
|
||||
|
||||
// Emit warnings for headers that are missing guards.
|
||||
checkGuardlessHeaders();
|
||||
|
||||
// Clear all state.
|
||||
Macros.clear();
|
||||
Files.clear();
|
||||
Ifndefs.clear();
|
||||
EndIfs.clear();
|
||||
}
|
||||
|
||||
/// \brief Look for header guards that don't match the preferred style. Emit
|
||||
/// fix-its and return the suggested header guard (or the original if no
|
||||
/// change was made.
|
||||
std::string checkHeaderGuardDefinition(SourceLocation Ifndef,
|
||||
SourceLocation Define,
|
||||
StringRef FileName,
|
||||
StringRef CurHeaderGuard) {
|
||||
std::string CPPVar = Check->getHeaderGuard(FileName, CurHeaderGuard);
|
||||
std::string CPPVarUnder = CPPVar + '_'; // Allow a trailing underscore.
|
||||
if (Ifndef.isValid() && CurHeaderGuard != CPPVar &&
|
||||
CurHeaderGuard != CPPVarUnder) {
|
||||
Check->diag(Ifndef, "header guard does not follow preferred style")
|
||||
<< FixItHint::CreateReplacement(
|
||||
CharSourceRange::getTokenRange(
|
||||
Ifndef, Ifndef.getLocWithOffset(CurHeaderGuard.size())),
|
||||
CPPVar)
|
||||
<< FixItHint::CreateReplacement(
|
||||
CharSourceRange::getTokenRange(
|
||||
Define, Define.getLocWithOffset(CurHeaderGuard.size())),
|
||||
CPPVar);
|
||||
return CPPVar;
|
||||
}
|
||||
return CurHeaderGuard;
|
||||
}
|
||||
|
||||
/// \brief Checks the comment after the #endif of a header guard and fixes it
|
||||
/// if it doesn't match \c HeaderGuard.
|
||||
void checkEndifComment(SourceLocation EndIf, StringRef HeaderGuard) {
|
||||
const char *EndIfData = PP->getSourceManager().getCharacterData(EndIf);
|
||||
size_t EndIfLen = std::strcspn(EndIfData, "\r\n");
|
||||
|
||||
StringRef EndIfStr(EndIfData, EndIfLen);
|
||||
if (EndIf.isValid() && !EndIfStr.endswith("// " + HeaderGuard.str())) {
|
||||
std::string Correct = "endif // " + HeaderGuard.str();
|
||||
Check->diag(EndIf, "#endif for a header guard should reference the "
|
||||
"guard macro in a comment")
|
||||
<< FixItHint::CreateReplacement(
|
||||
CharSourceRange::getCharRange(EndIf,
|
||||
EndIf.getLocWithOffset(EndIfLen)),
|
||||
Correct);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Looks for files that were visited but didn't have a header guard.
|
||||
/// Emits a warning with fixits suggesting adding one.
|
||||
void checkGuardlessHeaders() {
|
||||
// Look for header files that didn't have a header guard. Emit a warning and
|
||||
// fix-its to add the guard.
|
||||
// TODO: Insert the guard after top comments.
|
||||
for (const auto &FE : Files) {
|
||||
StringRef FileName = FE.getKey();
|
||||
if (!Check->shouldSuggestToAddHeaderGuard(FileName))
|
||||
continue;
|
||||
|
||||
SourceManager &SM = PP->getSourceManager();
|
||||
FileID FID = SM.translateFile(FE.getValue());
|
||||
SourceLocation StartLoc = SM.getLocForStartOfFile(FID);
|
||||
if (StartLoc.isInvalid())
|
||||
continue;
|
||||
|
||||
std::string CPPVar = Check->getHeaderGuard(FileName);
|
||||
std::string CPPVarUnder = CPPVar + '_'; // Allow a trailing underscore.
|
||||
// If there is a header guard macro but it's not in the topmost position
|
||||
// emit a plain warning without fix-its. This often happens when the guard
|
||||
// macro is preceeded by includes.
|
||||
// FIXME: Can we move it into the right spot?
|
||||
bool SeenMacro = false;
|
||||
for (const auto &MacroEntry : Macros) {
|
||||
StringRef Name = MacroEntry.first.getIdentifierInfo()->getName();
|
||||
SourceLocation DefineLoc = MacroEntry.first.getLocation();
|
||||
if ((Name == CPPVar || Name == CPPVarUnder) &&
|
||||
SM.isWrittenInSameFile(StartLoc, DefineLoc)) {
|
||||
Check->diag(
|
||||
DefineLoc,
|
||||
"Header guard after code/includes. Consider moving it up.");
|
||||
SeenMacro = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (SeenMacro)
|
||||
continue;
|
||||
|
||||
Check->diag(StartLoc, "header is missing header guard")
|
||||
<< FixItHint::CreateInsertion(
|
||||
StartLoc, "#ifndef " + CPPVar + "\n#define " + CPPVar + "\n\n")
|
||||
<< FixItHint::CreateInsertion(
|
||||
SM.getLocForEndOfFile(FID),
|
||||
Check->shouldSuggestEndifComment(FileName)
|
||||
? "\n#endif // " + CPPVar + "\n"
|
||||
: "\n#endif\n");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::pair<Token, const MacroDirective *>> Macros;
|
||||
llvm::StringMap<const FileEntry *> Files;
|
||||
std::map<const IdentifierInfo *, std::pair<SourceLocation, SourceLocation>>
|
||||
Ifndefs;
|
||||
std::map<SourceLocation, SourceLocation> EndIfs;
|
||||
|
||||
Preprocessor *PP;
|
||||
HeaderGuardCheck *Check;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void HeaderGuardCheck::registerPPCallbacks(CompilerInstance &Compiler) {
|
||||
Compiler.getPreprocessor().addPPCallbacks(
|
||||
new HeaderGuardPPCallbacks(&Compiler.getPreprocessor(), this));
|
||||
}
|
||||
|
||||
bool HeaderGuardCheck::shouldSuggestEndifComment(StringRef FileName) {
|
||||
return FileName.endswith(".h");
|
||||
}
|
||||
|
||||
bool HeaderGuardCheck::shouldFixHeaderGuard(StringRef FileName) { return true; }
|
||||
|
||||
bool HeaderGuardCheck::shouldSuggestToAddHeaderGuard(StringRef FileName) {
|
||||
return FileName.endswith(".h");
|
||||
}
|
||||
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
||||
@@ -1,41 +0,0 @@
|
||||
//===--- HeaderGuard.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_UTILS_HEADER_GUARD_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_HEADER_GUARD_H
|
||||
|
||||
#include "../ClangTidy.h"
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
|
||||
/// \brief Finds and fixes header guards.
|
||||
class HeaderGuardCheck : public ClangTidyCheck {
|
||||
public:
|
||||
void registerPPCallbacks(CompilerInstance &Compiler) override;
|
||||
|
||||
/// \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);
|
||||
/// \brief Returns true if the checker should suggest changing an existing
|
||||
/// header guard to the string returned by getHeaderGuard.
|
||||
virtual bool shouldFixHeaderGuard(StringRef Filename);
|
||||
/// \brief Returns true if the checker should add a header guard to the file
|
||||
/// if it has none.
|
||||
virtual bool shouldSuggestToAddHeaderGuard(StringRef Filename);
|
||||
/// \brief Get the canonical header guard for a file.
|
||||
virtual std::string getHeaderGuard(StringRef Filename,
|
||||
StringRef OldGuard = StringRef()) = 0;
|
||||
};
|
||||
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_HEADER_GUARD_H
|
||||
@@ -1,12 +0,0 @@
|
||||
##===- clang-tidy/google/Makefile --------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
CLANG_LEVEL := ../../../..
|
||||
LIBRARYNAME := clangTidyUtils
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
@@ -652,10 +652,10 @@ public:
|
||||
HadErrors(HadErrors) {}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<clang::ASTConsumer>
|
||||
CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
|
||||
return llvm::make_unique<CollectEntitiesConsumer>(
|
||||
Entities, PPTracker, CI.getPreprocessor(), InFile, HadErrors);
|
||||
virtual clang::ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef InFile) {
|
||||
return new CollectEntitiesConsumer(Entities, PPTracker,
|
||||
CI.getPreprocessor(), InFile, HadErrors);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -736,8 +736,8 @@ int main(int Argc, const char **Argv) {
|
||||
ClangTool Tool(*Compilations, Headers);
|
||||
Tool.appendArgumentsAdjuster(new AddDependenciesAdjuster(Dependencies));
|
||||
int HadErrors = 0;
|
||||
ModularizeFrontendActionFactory Factory(Entities, *PPTracker, HadErrors);
|
||||
HadErrors |= Tool.run(&Factory);
|
||||
HadErrors |= Tool.run(
|
||||
new ModularizeFrontendActionFactory(Entities, *PPTracker, HadErrors));
|
||||
|
||||
// Create a place to save duplicate entity locations, separate bins per kind.
|
||||
typedef SmallVector<Location, 8> LocationArray;
|
||||
|
||||
@@ -178,10 +178,9 @@ public:
|
||||
ModuleMapCheckerAction(ModuleMapChecker &Checker) : Checker(Checker) {}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef InFile) override {
|
||||
return llvm::make_unique<ModuleMapCheckerConsumer>(Checker,
|
||||
CI.getPreprocessor());
|
||||
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef InFile) {
|
||||
return new ModuleMapCheckerConsumer(Checker, CI.getPreprocessor());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -120,10 +120,9 @@ public:
|
||||
: Ignore(Ignore), CallbackCalls(CallbackCalls) {}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<clang::ASTConsumer>
|
||||
CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
|
||||
return llvm::make_unique<PPTraceConsumer>(Ignore, CallbackCalls,
|
||||
CI.getPreprocessor());
|
||||
virtual clang::ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef InFile) {
|
||||
return new PPTraceConsumer(Ignore, CallbackCalls, CI.getPreprocessor());
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -200,8 +199,8 @@ int main(int Argc, const char **Argv) {
|
||||
|
||||
// Create the tool and run the compilation.
|
||||
ClangTool Tool(*Compilations, SourcePaths);
|
||||
PPTraceFrontendActionFactory Factory(Ignore, CallbackCalls);
|
||||
int HadErrors = Tool.run(&Factory);
|
||||
int HadErrors =
|
||||
Tool.run(new PPTraceFrontendActionFactory(Ignore, CallbackCalls));
|
||||
|
||||
// If we had errors, exit early.
|
||||
if (HadErrors)
|
||||
|
||||
@@ -183,11 +183,11 @@ int main(int argc, const char **argv) {
|
||||
cl::ParseCommandLineOptions(argc, argv);
|
||||
if (!Compilations) {
|
||||
std::string ErrorMessage;
|
||||
Compilations =
|
||||
CompilationDatabase::loadFromDirectory(BuildPath, ErrorMessage);
|
||||
Compilations.reset(
|
||||
CompilationDatabase::loadFromDirectory(BuildPath, ErrorMessage));
|
||||
if (!Compilations)
|
||||
llvm::report_fatal_error(ErrorMessage);
|
||||
}
|
||||
}
|
||||
tooling::RefactoringTool Tool(*Compilations, SourcePaths);
|
||||
ast_matchers::MatchFinder Finder;
|
||||
FixCStrCall Callback(&Tool.getReplacements());
|
||||
|
||||
@@ -37,7 +37,6 @@ set(CLANG_TOOLS_TEST_DEPS
|
||||
# Individual tools we test.
|
||||
clang-apply-replacements
|
||||
clang-modernize
|
||||
clang-rename
|
||||
clang-query
|
||||
clang-tidy
|
||||
modularize
|
||||
|
||||
@@ -60,7 +60,6 @@ lit.site.cfg: FORCE
|
||||
Unit/lit.site.cfg: FORCE
|
||||
@echo "Making Unit/lit.site.cfg for Clang extra tools..."
|
||||
@$(MKDIR) $(dir $@)
|
||||
@$(ECHOPATH) s=@LLVM_LIBS_DIR@=$(LibDir)=g >> lit.tmp
|
||||
@$(ECHOPATH) s=@CLANG_TOOLS_BINARY_DIR@=$(PROJ_OBJ_DIR)/..=g >> lit.tmp
|
||||
@$(ECHOPATH) s=@TARGET_TRIPLE@=$(TARGET_TRIPLE)=g >> lit.tmp
|
||||
@$(ECHOPATH) s=@CLANG_TOOLS_SOURCE_DIR@=$(PROJ_SRC_DIR)/..=g >> lit.tmp
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# -*- Python -*-
|
||||
|
||||
import platform
|
||||
|
||||
import lit.formats
|
||||
|
||||
config.name = "Extra Tools Unit Tests"
|
||||
@@ -14,6 +12,11 @@ if extra_tools_obj_dir is not None:
|
||||
config.test_source_root = extra_tools_obj_dir
|
||||
config.test_exec_root = config.test_source_root
|
||||
|
||||
# Win32 seeks DLLs along %PATH%.
|
||||
if sys.platform in ['win32', 'cygwin'] and os.path.isdir(config.shlibdir):
|
||||
config.environment['PATH'] = os.path.pathsep.join((
|
||||
config.shlibdir, config.environment['PATH']))
|
||||
|
||||
# All GoogleTests are named to have 'Tests' as their suffix. The '.' option is
|
||||
# a special value for GoogleTest indicating that it should look through the
|
||||
# entire testsuite recursively for tests (alternatively, one could provide a
|
||||
@@ -31,24 +34,3 @@ if config.test_exec_root is None:
|
||||
raise SystemExit
|
||||
|
||||
# FIXME: Support out-of-tree builds? See clang/test/Unit/lit.cfg if we care.
|
||||
|
||||
shlibpath_var = ''
|
||||
if platform.system() == 'Linux':
|
||||
shlibpath_var = 'LD_LIBRARY_PATH'
|
||||
elif platform.system() == 'Darwin':
|
||||
shlibpath_var = 'DYLD_LIBRARY_PATH'
|
||||
elif platform.system() == 'Windows':
|
||||
shlibpath_var = 'PATH'
|
||||
|
||||
# Point the dynamic loader at dynamic libraries in 'lib'.
|
||||
llvm_libs_dir = getattr(config, 'llvm_libs_dir', None)
|
||||
if not llvm_libs_dir:
|
||||
lit_config.fatal('No LLVM libs dir set!')
|
||||
shlibpath = os.path.pathsep.join((llvm_libs_dir,
|
||||
config.environment.get(shlibpath_var,'')))
|
||||
|
||||
# Win32 seeks DLLs along %PATH%.
|
||||
if sys.platform in ['win32', 'cygwin'] and os.path.isdir(config.shlibdir):
|
||||
shlibpath = os.path.pathsep.join((config.shlibdir, shlibpath))
|
||||
|
||||
config.environment[shlibpath_var] = shlibpath
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
# Do not edit!
|
||||
config.extra_tools_obj_dir = "@CLANG_TOOLS_BINARY_DIR@/unittests"
|
||||
config.extra_tools_src_dir = "@CLANG_TOOLS_SOURCE_DIR@/unittests"
|
||||
config.llvm_libs_dir = "@LLVM_LIBS_DIR@"
|
||||
config.shlibdir = "@SHLIBDIR@"
|
||||
config.target_triple = "@TARGET_TRIPLE@"
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// RUN: cat %s > %t.cpp
|
||||
// RUN: clang-rename -offset=170 -new-name=hector %t.cpp -i --
|
||||
// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
|
||||
// REQUIRES: shell
|
||||
namespace A {
|
||||
int foo; // CHECK: int hector;
|
||||
}
|
||||
int foo; // CHECK: int foo;
|
||||
int bar = foo; // CHECK: bar = foo;
|
||||
int baz = A::foo; // CHECK: baz = A::hector;
|
||||
void fun1() {
|
||||
struct {
|
||||
int foo; // CHECK: int foo;
|
||||
} b = { 100 };
|
||||
int foo = 100; // CHECK: int foo
|
||||
baz = foo; // CHECK: baz = foo;
|
||||
{
|
||||
extern int foo; // CHECK: int foo;
|
||||
baz = foo; // CHECK: baz = foo;
|
||||
foo = A::foo + baz; // CHECK: foo = A::hector + baz;
|
||||
A::foo = b.foo; // CHECK: A::hector = b.foo;
|
||||
}
|
||||
foo = b.foo; // CHECK: foo = b.foo;
|
||||
}
|
||||
// Use grep -FUbo 'foo;' <file> to get the correct offset of foo when changing
|
||||
// this file.
|
||||
@@ -1,29 +1,21 @@
|
||||
// RUN: clang-tidy --checks='-*,misc-argument-comment' %s -- -std=c++11 | FileCheck %s -implicit-check-not='{{warning:|error:}}'
|
||||
// RUN: clang-tidy --checks='-*,misc-argument-comment' %s -- | FileCheck %s
|
||||
|
||||
// FIXME: clang-tidy should provide a -verify mode to make writing these checks
|
||||
// easier and more accurate.
|
||||
|
||||
void ffff(int xxxx, int yyyy);
|
||||
// CHECK-NOT: warning
|
||||
|
||||
void f(int x, int y);
|
||||
|
||||
void ffff(int xxxx, int yyyy);
|
||||
|
||||
void g() {
|
||||
// CHECK: [[@LINE+5]]:5: warning: argument name 'y' in comment does not match parameter name 'x'
|
||||
// CHECK: :[[@LINE-3]]:12: note: 'x' declared here
|
||||
// CHECK: :8:12: note: 'x' declared here
|
||||
// CHECK: [[@LINE+3]]:14: warning: argument name 'z' in comment does not match parameter name 'y'
|
||||
// CHECK: :[[@LINE-5]]:19: note: 'y' declared here
|
||||
// CHECK: :8:19: note: 'y' declared here
|
||||
// CHECK-NOT: warning
|
||||
f(/*y=*/0, /*z=*/0);
|
||||
}
|
||||
|
||||
struct Closure {};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
Closure *NewCallback(void (*f)(T1, T2), T1 arg1, T2 arg2) { return nullptr; }
|
||||
|
||||
template <typename T1, typename T2>
|
||||
Closure *NewPermanentCallback(void (*f)(T1, T2), T1 arg1, T2 arg2) { return nullptr; }
|
||||
|
||||
void h() {
|
||||
(void)NewCallback(&ffff, /*xxxx=*/11, /*yyyy=*/22);
|
||||
(void)NewPermanentCallback(&ffff, /*xxxx=*/11, /*yyyy=*/22);
|
||||
}
|
||||
// CHECK-NOT: warning
|
||||
|
||||
@@ -105,6 +105,9 @@ void test_templates() {
|
||||
#define CAST(type, value) (type)(value)
|
||||
void macros(double d) {
|
||||
int i = CAST(int, d);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: C-style casts are discouraged. Use static_cast.
|
||||
// CHECK-FIXES: #define CAST(type, value) (type)(value)
|
||||
// CHECK-FIXES: int i = CAST(int, d);
|
||||
}
|
||||
|
||||
enum E { E1 = 1 };
|
||||
|
||||
@@ -1,34 +1,24 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Run clang-tidy in fix mode and verify the result.
|
||||
# Usage:
|
||||
# check_clang_tidy_fix.sh <source-file> <check-name> <temp-file> \
|
||||
# [optional compiler arguments]
|
||||
#
|
||||
# Example:
|
||||
# // RUN: $(dirname %s)/check_clang_tidy_fix.sh %s llvm-include-order %t -isystem $(dirname %s)/Inputs/Headers
|
||||
# // REQUIRES: shell
|
||||
|
||||
INPUT_FILE=$1
|
||||
CHECK_TO_RUN=$2
|
||||
TEMPORARY_FILE=$3.cpp
|
||||
# Feed the rest arguments to clang-tidy after --.
|
||||
shift 3
|
||||
|
||||
set -o errexit
|
||||
|
||||
# Remove the contents of the CHECK lines to avoid CHECKs matching on themselves.
|
||||
# We need to keep the comments to preserve line numbers while avoiding empty
|
||||
# lines which could potentially trigger formatting-related checks.
|
||||
sed 's#// *[A-Z-][A-Z-]*:.*#//#' ${INPUT_FILE} > ${TEMPORARY_FILE}
|
||||
sed 's#// *[A-Z-]\+:.*#//#' ${INPUT_FILE} > ${TEMPORARY_FILE}
|
||||
|
||||
clang-tidy ${TEMPORARY_FILE} -fix --checks="-*,${CHECK_TO_RUN}" \
|
||||
-- --std=c++11 $* > ${TEMPORARY_FILE}.msg 2>&1
|
||||
clang-tidy ${TEMPORARY_FILE} -fix --checks="-*,${CHECK_TO_RUN}" -- --std=c++11 \
|
||||
> ${TEMPORARY_FILE}.msg 2>&1
|
||||
|
||||
FileCheck -input-file=${TEMPORARY_FILE} ${INPUT_FILE} \
|
||||
-check-prefix=CHECK-FIXES -strict-whitespace
|
||||
-check-prefix=CHECK-FIXES -strict-whitespace || exit $?
|
||||
|
||||
if grep -q CHECK-MESSAGES ${INPUT_FILE}; then
|
||||
FileCheck -input-file=${TEMPORARY_FILE}.msg ${INPUT_FILE} \
|
||||
-check-prefix=CHECK-MESSAGES -implicit-check-not="{{warning|error}}:"
|
||||
-check-prefix=CHECK-MESSAGES -implicit-check-not="{{warning|error}}:" \
|
||||
|| exit $?
|
||||
fi
|
||||
|
||||
@@ -9,10 +9,10 @@ struct A {
|
||||
// CHECK-NOT: warning
|
||||
struct B : public A {
|
||||
void placeholder_for_f() {}
|
||||
// CHECK-SANITY: [[@LINE-1]]:8: warning: Annotate this
|
||||
// CHECK: [[@LINE-2]]:8: warning: Annotate this
|
||||
// CHECK-SANITY: [[@LINE-1]]:8: warning: Use exactly
|
||||
// CHECK: [[@LINE-2]]:8: warning: Use exactly
|
||||
void g() {}
|
||||
// CHECK-SANITY: [[@LINE-1]]:8: warning: Annotate this
|
||||
// CHECK-SANITY: [[@LINE-1]]:8: warning: Use exactly
|
||||
// CHECK-NOT: warning:
|
||||
};
|
||||
// CHECK-SANITY-NOT: Suppressed
|
||||
|
||||
@@ -4,57 +4,57 @@
|
||||
void Method(char *) { /* */ }
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: void Method(char * /*unused*/) { /* */ }
|
||||
void Method2(char *) {}
|
||||
void Method2(char *);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: void Method2(char * /*unused*/) {}
|
||||
void Method3(char *, void *) {}
|
||||
// CHECK-FIXES: void Method2(char * /*unused*/);
|
||||
void Method3(char *, void *);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: void Method3(char * /*unused*/, void * /*unused*/) {}
|
||||
void Method4(char *, int /*unused*/) {}
|
||||
// CHECK-FIXES: void Method3(char * /*unused*/, void * /*unused*/);
|
||||
void Method4(char *, int /*unused*/);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: void Method4(char * /*unused*/, int /*unused*/) {}
|
||||
void operator delete[](void *) throw() {}
|
||||
// CHECK-FIXES: void Method4(char * /*unused*/, int /*unused*/);
|
||||
void operator delete[](void *) throw();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: void operator delete[](void * /*unused*/) throw() {}
|
||||
int Method5(int) { return 0; }
|
||||
// CHECK-FIXES: void operator delete[](void * /*unused*/) throw();
|
||||
int Method5(int);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: int Method5(int /*unused*/) { return 0; }
|
||||
// CHECK-FIXES: int Method5(int /*unused*/);
|
||||
void Method6(void (*)(void *)) {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: void Method6(void (* /*unused*/)(void *)) {}
|
||||
template <typename T> void Method7(T) {}
|
||||
template <typename T> void Method7(T);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: template <typename T> void Method7(T /*unused*/) {}
|
||||
// CHECK-FIXES: template <typename T> void Method7(T /*unused*/);
|
||||
|
||||
// Don't warn in macros.
|
||||
#define M void MethodM(int) {}
|
||||
#define M void MethodM(int);
|
||||
M
|
||||
|
||||
void operator delete(void *x) throw() {}
|
||||
void operator delete(void *x) throw();
|
||||
void Method7(char * /*x*/) {}
|
||||
void Method8(char *x) {}
|
||||
void Method8(char *x);
|
||||
typedef void (*TypeM)(int x);
|
||||
void operator delete[](void *x) throw();
|
||||
void operator delete[](void * /*x*/) throw();
|
||||
|
||||
struct X {
|
||||
X operator++(int) {}
|
||||
X operator++(int);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: X operator++(int /*unused*/) {}
|
||||
X operator--(int /*unused*/) {}
|
||||
// CHECK-FIXES: X operator++(int /*unused*/);
|
||||
X operator--(int /*unused*/);
|
||||
|
||||
const int &i;
|
||||
};
|
||||
|
||||
void (*Func1)(void *);
|
||||
void Func2(void (*func)(void *)) {}
|
||||
template <void Func(void *)> void Func3() {}
|
||||
template <void Func(void *)> void Func3();
|
||||
|
||||
template <typename T>
|
||||
struct Y {
|
||||
void foo(T) {}
|
||||
void foo(T);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: void foo(T /*unused*/) {}
|
||||
// CHECK-FIXES: void foo(T /*unused*/);
|
||||
};
|
||||
|
||||
Y<int> y;
|
||||
@@ -70,17 +70,3 @@ struct Derived : public Base {
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: void foo(int /*argname*/);
|
||||
};
|
||||
|
||||
void FDef(int);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: void FDef(int /*n*/);
|
||||
void FDef(int n) {}
|
||||
|
||||
void FDef2(int, int);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: void FDef2(int /*n*/, int /*unused*/);
|
||||
void FDef2(int n, int) {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: void FDef2(int n, int /*unused*/) {}
|
||||
|
||||
void FNoDef(int);
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
// RUN: $(dirname %s)/check_clang_tidy_fix.sh %s llvm-include-order %t -isystem %S/Inputs/Headers
|
||||
// REQUIRES: shell
|
||||
|
||||
// FIXME: Investigating.
|
||||
// XFAIL: win32
|
||||
|
||||
// CHECK-MESSAGES: [[@LINE+2]]:1: warning: #includes are not sorted properly
|
||||
#include "j.h"
|
||||
#include "gtest/foo.h"
|
||||
#include "i.h"
|
||||
#include <s.h>
|
||||
#include "llvm/a.h"
|
||||
#include "clang/b.h"
|
||||
#include "clang-c/c.h" // hi
|
||||
#include "llvm-c/d.h" // -c
|
||||
|
||||
// CHECK-FIXES: #include "j.h"
|
||||
// CHECK-FIXES-NEXT: #include "i.h"
|
||||
// CHECK-FIXES-NEXT: #include "clang-c/c.h" // hi
|
||||
// CHECK-FIXES-NEXT: #include "clang/b.h"
|
||||
// CHECK-FIXES-NEXT: #include "llvm-c/d.h" // -c
|
||||
// CHECK-FIXES-NEXT: #include "llvm/a.h"
|
||||
// CHECK-FIXES-NEXT: #include "gtest/foo.h"
|
||||
// CHECK-FIXES-NEXT: #include <s.h>
|
||||
|
||||
#include "b.h"
|
||||
#ifdef FOO
|
||||
#include "a.h"
|
||||
#endif
|
||||
|
||||
// CHECK-FIXES: #include "b.h"
|
||||
// CHECK-FIXES-NEXT: #ifdef FOO
|
||||
// CHECK-FIXES-NEXT: #include "a.h"
|
||||
// CHECK-FIXES-NEXT: #endif
|
||||
|
||||
// CHECK-MESSAGES: [[@LINE+1]]:1: warning: #includes are not sorted properly
|
||||
#include "b.h"
|
||||
#include "a.h"
|
||||
|
||||
// CHECK-FIXES: #include "a.h"
|
||||
// CHECK-FIXES-NEXT: #include "b.h"
|
||||
@@ -33,6 +33,10 @@ void foo() {
|
||||
#define TESTMACRO if (b || F())
|
||||
|
||||
TESTMACRO {
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: dubious check of 'bool *' against 'nullptr'
|
||||
// Can't fix this.
|
||||
// CHECK-FIXES: #define TESTMACRO if (b || F())
|
||||
// CHECK-FIXES: TESTMACRO {
|
||||
}
|
||||
|
||||
t(b);
|
||||
@@ -77,7 +81,4 @@ void foo() {
|
||||
|
||||
if (d.b)
|
||||
(void)*d.b; // no-warning
|
||||
|
||||
#define CHECK(b) if (b) {}
|
||||
CHECK(c)
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
// RUN: clang-tidy -checks='-*,misc-undelegated-constructor' %s -- -std=c++11 2>&1 | FileCheck %s -implicit-check-not='{{warning:|error:}}'
|
||||
|
||||
struct Ctor;
|
||||
Ctor foo();
|
||||
|
||||
struct Ctor {
|
||||
Ctor();
|
||||
Ctor(int);
|
||||
Ctor(int, int);
|
||||
Ctor(Ctor *i) {
|
||||
Ctor();
|
||||
// CHECK: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? A temporary object is created here instead
|
||||
Ctor(0);
|
||||
// CHECK: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? A temporary object is created here instead
|
||||
Ctor(1, 2);
|
||||
// CHECK: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? A temporary object is created here instead
|
||||
foo();
|
||||
}
|
||||
};
|
||||
|
||||
Ctor::Ctor() {
|
||||
Ctor(1);
|
||||
// CHECK: :[[@LINE-1]]:3: warning: did you intend to call a delegated constructor? A temporary object is created here instead
|
||||
}
|
||||
|
||||
Ctor::Ctor(int i) : Ctor(i, 1) {} // properly delegated.
|
||||
|
||||
struct Dtor {
|
||||
Dtor();
|
||||
Dtor(int);
|
||||
Dtor(int, int);
|
||||
Dtor(Ctor *i) {
|
||||
Dtor();
|
||||
// CHECK: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? A temporary object is created here instead
|
||||
Dtor(0);
|
||||
// CHECK: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? A temporary object is created here instead
|
||||
Dtor(1, 2);
|
||||
// CHECK: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? A temporary object is created here instead
|
||||
}
|
||||
~Dtor();
|
||||
};
|
||||
|
||||
struct Base {};
|
||||
struct Derived : public Base {
|
||||
Derived() { Base(); }
|
||||
// CHECK: :[[@LINE-1]]:15: warning: did you intend to call a delegated constructor? A temporary object is created here instead
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct TDerived : public Base {
|
||||
TDerived() { Base(); }
|
||||
};
|
||||
|
||||
TDerived<int> t;
|
||||
@@ -1,61 +0,0 @@
|
||||
// RUN: $(dirname %s)/check_clang_tidy_fix.sh %s misc-unused-raii %t
|
||||
// REQUIRES: shell
|
||||
|
||||
struct Foo {
|
||||
Foo();
|
||||
Foo(int);
|
||||
Foo(int, int);
|
||||
~Foo();
|
||||
};
|
||||
|
||||
struct Bar {
|
||||
Bar();
|
||||
Foo f;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void qux() {
|
||||
T(42);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct TFoo {
|
||||
TFoo(T);
|
||||
~TFoo();
|
||||
};
|
||||
|
||||
Foo f();
|
||||
|
||||
struct Ctor {
|
||||
Ctor(int);
|
||||
Ctor() {
|
||||
Ctor(0); // TODO: warn here.
|
||||
}
|
||||
};
|
||||
|
||||
void test() {
|
||||
Foo(42);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
|
||||
// CHECK-FIXES: Foo give_me_a_name(42);
|
||||
Foo(23, 42);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
|
||||
// CHECK-FIXES: Foo give_me_a_name(23, 42);
|
||||
Foo();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
|
||||
// CHECK-FIXES: Foo give_me_a_name;
|
||||
TFoo<int>(23);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
|
||||
// CHECK-FIXES: TFoo<int> give_me_a_name(23);
|
||||
|
||||
Bar();
|
||||
f();
|
||||
qux<Foo>();
|
||||
|
||||
#define M Foo();
|
||||
M
|
||||
|
||||
{
|
||||
Foo();
|
||||
}
|
||||
Foo();
|
||||
}
|
||||
@@ -32,11 +32,11 @@ struct Base {
|
||||
struct SimpleCases : public Base {
|
||||
public:
|
||||
virtual ~SimpleCases();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: Prefer using 'override' or (rarely) 'final' instead of 'virtual'
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: Prefer using 'override' or 'final' instead of 'virtual'
|
||||
// CHECK-FIXES: {{^ ~SimpleCases\(\) override;}}
|
||||
|
||||
void a();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Annotate this
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Use exactly
|
||||
// CHECK-FIXES: {{^ void a\(\) override;}}
|
||||
|
||||
void b() override;
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
// CHECK-FIXES: {{^ void c\(\) override;}}
|
||||
|
||||
virtual void d() override;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Annotate this
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Use exactly
|
||||
// CHECK-FIXES: {{^ void d\(\) override;}}
|
||||
|
||||
virtual void e() = 0;
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
// CHECK-FIXES: {{^ bool l\(\) override MUST_USE_RESULT;}}
|
||||
|
||||
virtual void m() override final;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Annotate this
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Use exactly
|
||||
// CHECK-FIXES: {{^ void m\(\) final;}}
|
||||
};
|
||||
|
||||
@@ -98,7 +98,7 @@ struct DefaultedDestructor : public Base {
|
||||
struct FinalSpecified : public Base {
|
||||
public:
|
||||
virtual ~FinalSpecified() final;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: Annotate this
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: Use exactly
|
||||
// CHECK-FIXES: {{^ ~FinalSpecified\(\) final;}}
|
||||
|
||||
void b() final;
|
||||
@@ -106,19 +106,19 @@ public:
|
||||
// CHECK-FIXES: {{^ void b\(\) final;}}
|
||||
|
||||
virtual void d() final;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Annotate this
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Use exactly
|
||||
// CHECK-FIXES: {{^ void d\(\) final;}}
|
||||
|
||||
virtual void e() final = 0;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Annotate this
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Use exactly
|
||||
// CHECK-FIXES: {{^ void e\(\) final = 0;}}
|
||||
|
||||
virtual void j() const final;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Annotate this
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Use exactly
|
||||
// CHECK-FIXES: {{^ void j\(\) const final;}}
|
||||
|
||||
virtual bool l() final MUST_USE_RESULT;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Annotate this
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Use exactly
|
||||
// CHECK-FIXES: {{^ bool l\(\) final MUST_USE_RESULT;}}
|
||||
};
|
||||
|
||||
@@ -129,7 +129,7 @@ public:
|
||||
// CHECK-FIXES: {{^ ~InlineDefinitions\(\) override {}}}
|
||||
|
||||
void a() {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Annotate this
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Use exactly
|
||||
// CHECK-FIXES: {{^ void a\(\) override {}}}
|
||||
|
||||
void b() override {}
|
||||
@@ -141,7 +141,7 @@ public:
|
||||
// CHECK-FIXES: {{^ void c\(\) override {}}}
|
||||
|
||||
virtual void d() override {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Annotate this
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Use exactly
|
||||
// CHECK-FIXES: {{^ void d\(\) override {}}}
|
||||
|
||||
virtual void j() const {}
|
||||
@@ -161,7 +161,7 @@ struct Macros : public Base {
|
||||
// Tests for 'virtual' and 'override' being defined through macros. Basically
|
||||
// give up for now.
|
||||
NOT_VIRTUAL void a() NOT_OVERRIDE;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: Annotate this
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: Use exactly
|
||||
// CHECK-FIXES: {{^ NOT_VIRTUAL void a\(\) override NOT_OVERRIDE;}}
|
||||
|
||||
VIRTUAL void b() NOT_OVERRIDE;
|
||||
@@ -173,7 +173,7 @@ struct Macros : public Base {
|
||||
// CHECK-FIXES: {{^ NOT_VIRTUAL void c\(\) OVERRIDE;}}
|
||||
|
||||
VIRTUAL void d() OVERRIDE;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Annotate this
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Use exactly
|
||||
// CHECK-FIXES: {{^ VIRTUAL void d\(\) OVERRIDE;}}
|
||||
|
||||
#define FUNC(return_type, name) return_type name()
|
||||
@@ -185,7 +185,7 @@ struct Macros : public Base {
|
||||
// CHECK-FIXES: {{^ F}}
|
||||
|
||||
VIRTUAL void g() OVERRIDE final;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Annotate this
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Use exactly
|
||||
// CHECK-FIXES: {{^ VIRTUAL void g\(\) final;}}
|
||||
};
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "clang/Tooling/CommonOptionsParser.h"
|
||||
#include "clang/Tooling/CompilationDatabase.h"
|
||||
#include "clang/Tooling/Refactoring.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
@@ -56,11 +56,11 @@ class ToolTemplateCallback : public MatchFinder::MatchCallback {
|
||||
public:
|
||||
ToolTemplateCallback(Replacements *Replace) : Replace(Replace) {}
|
||||
|
||||
void run(const MatchFinder::MatchResult &Result) override {
|
||||
// TODO: This routine will get called for each thing that the matchers find.
|
||||
// At this point, you can examine the match, and do whatever you want,
|
||||
// including replacing the matched text with other text
|
||||
(void)Replace; // This to prevent an "unused member variable" warning;
|
||||
virtual void run(const MatchFinder::MatchResult &Result) {
|
||||
// TODO: This routine will get called for each thing that the matchers find.
|
||||
// At this point, you can examine the match, and do whatever you want,
|
||||
// including replacing the matched text with other text
|
||||
(void) Replace; // This to prevent an "unused member variable" warning;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -69,20 +69,39 @@ class ToolTemplateCallback : public MatchFinder::MatchCallback {
|
||||
} // end anonymous namespace
|
||||
|
||||
// Set up the command line options
|
||||
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
|
||||
static cl::OptionCategory ToolTemplateCategory("tool-template options");
|
||||
cl::opt<std::string> BuildPath(
|
||||
cl::Positional,
|
||||
cl::desc("<build-path>"));
|
||||
|
||||
cl::list<std::string> SourcePaths(
|
||||
cl::Positional,
|
||||
cl::desc("<source0> [... <sourceN>]"),
|
||||
cl::OneOrMore);
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
llvm::sys::PrintStackTraceOnErrorSignal();
|
||||
CommonOptionsParser OptionsParser(argc, argv, ToolTemplateCategory);
|
||||
RefactoringTool Tool(OptionsParser.getCompilations(),
|
||||
OptionsParser.getSourcePathList());
|
||||
std::unique_ptr<CompilationDatabase> Compilations(
|
||||
FixedCompilationDatabase::loadFromCommandLine(argc, argv));
|
||||
cl::ParseCommandLineOptions(argc, argv);
|
||||
if (!Compilations) { // Couldn't find a compilation DB from the command line
|
||||
std::string ErrorMessage;
|
||||
Compilations.reset(
|
||||
!BuildPath.empty() ?
|
||||
CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage) :
|
||||
CompilationDatabase::autoDetectFromSource(SourcePaths[0], ErrorMessage)
|
||||
);
|
||||
|
||||
// Still no compilation DB? - bail.
|
||||
if (!Compilations)
|
||||
llvm::report_fatal_error(ErrorMessage);
|
||||
}
|
||||
RefactoringTool Tool(*Compilations, SourcePaths);
|
||||
ast_matchers::MatchFinder Finder;
|
||||
ToolTemplateCallback Callback(&Tool.getReplacements());
|
||||
|
||||
// TODO: Put your matchers here.
|
||||
// Use Finder.addMatcher(...) to define the patterns in the AST that you
|
||||
// want to match against. You are not limited to just one matcher!
|
||||
// TODO: Put your matchers here.
|
||||
// Use Finder.addMatcher(...) to define the patterns in the AST that you
|
||||
// want to match against. You are not limited to just one matcher!
|
||||
|
||||
return Tool.run(newFrontendActionFactory(&Finder).get());
|
||||
}
|
||||
|
||||
@@ -7,6 +7,5 @@ endfunction()
|
||||
|
||||
add_subdirectory(clang-apply-replacements)
|
||||
add_subdirectory(clang-modernize)
|
||||
add_subdirectory(clang-rename)
|
||||
add_subdirectory(clang-query)
|
||||
add_subdirectory(clang-tidy)
|
||||
|
||||
@@ -93,8 +93,8 @@ public:
|
||||
};
|
||||
|
||||
struct ConsumerFactory {
|
||||
std::unique_ptr<ASTConsumer> newASTConsumer() {
|
||||
return llvm::make_unique<TimePassingASTConsumer>(&Called);
|
||||
ASTConsumer *newASTConsumer() {
|
||||
return new TimePassingASTConsumer(&Called);
|
||||
}
|
||||
bool Called;
|
||||
};
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
support
|
||||
)
|
||||
|
||||
get_filename_component(CLANG_RENAME_SOURCE_DIR
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../clang-rename REALPATH)
|
||||
include_directories(
|
||||
${CLANG_RENAME_SOURCE_DIR}
|
||||
)
|
||||
|
||||
add_extra_unittest(ClangRenameTests
|
||||
USRLocFindingTest.cpp
|
||||
${CLANG_RENAME_SOURCE_DIR}/USRFinder.cpp
|
||||
${CLANG_RENAME_SOURCE_DIR}/USRFindingAction.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(ClangRenameTests
|
||||
clangAnalysis
|
||||
clangAST
|
||||
clangBasic
|
||||
clangDriver
|
||||
clangEdit
|
||||
clangFrontend
|
||||
clangFrontendTool
|
||||
clangIndex
|
||||
clangLex
|
||||
clangParse
|
||||
clangRewrite
|
||||
clangRewriteFrontend
|
||||
clangSerialization
|
||||
clangSema
|
||||
clangTooling
|
||||
)
|
||||
@@ -1,24 +0,0 @@
|
||||
##===- unittests/clang-rename/Makefile ---------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL = ../../../..
|
||||
include $(CLANG_LEVEL)/../../Makefile.config
|
||||
|
||||
TESTNAME = ClangRenameTests
|
||||
LINK_COMPONENTS := asmparser bitreader support MC MCParser option \
|
||||
TransformUtils
|
||||
USEDLIBS = clangAnalysis.a clangAST.a clangBasic.a clangDriver.a clangEdit.a \
|
||||
clangFrontend.a clangFrontendTool.a clangIndex.a clangLex.a \
|
||||
clangParse.a clangRewrite.a clangRewriteFrontend.a \
|
||||
clangSerialization.a clangSema.a clangTooling.a
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
MAKEFILE_UNITTEST_NO_INCLUDE_COMMON := 1
|
||||
CPP.Flags += -I(PROJ_SRC_DIR)/../../clang-rename
|
||||
include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest
|
||||
@@ -1,84 +0,0 @@
|
||||
#include "USRFindingAction.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include <stdio.h>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
namespace rename {
|
||||
namespace test {
|
||||
|
||||
// Determines if the symbol group invariants hold. To recap, those invariants
|
||||
// are:
|
||||
// (1) All symbols in the same symbol group share the same USR.
|
||||
// (2) Two symbols from two different groups do not share the same USR.
|
||||
static void testOffsetGroups(const char *Code,
|
||||
const std::vector<std::vector<unsigned>> Groups) {
|
||||
std::set<std::string> AllUSRs, CurrUSR;
|
||||
|
||||
for (const auto &Group : Groups) {
|
||||
// Groups the invariants do not hold then the value of USR is also invalid,
|
||||
// but at that point the test has already failed and USR ceases to be
|
||||
// useful.
|
||||
std::string USR;
|
||||
for (const auto &Offset : Group) {
|
||||
USRFindingAction Action(Offset);
|
||||
auto Factory = tooling::newFrontendActionFactory(&Action);
|
||||
EXPECT_TRUE(tooling::runToolOnCode(Factory->create(), Code));
|
||||
const auto &USRs = Action.getUSRs();
|
||||
EXPECT_EQ(1u, USRs.size());
|
||||
USR = USRs[0];
|
||||
CurrUSR.insert(USR);
|
||||
}
|
||||
EXPECT_EQ(1u, CurrUSR.size());
|
||||
CurrUSR.clear();
|
||||
AllUSRs.insert(USR);
|
||||
}
|
||||
|
||||
EXPECT_EQ(Groups.size(), AllUSRs.size());
|
||||
}
|
||||
|
||||
|
||||
TEST(USRLocFinding, FindsVarUSR) {
|
||||
const char VarTest[] = "\n\
|
||||
namespace A {\n\
|
||||
int foo;\n\
|
||||
}\n\
|
||||
int foo;\n\
|
||||
int bar = foo;\n\
|
||||
int baz = A::foo;\n\
|
||||
void fun1() {\n\
|
||||
struct {\n\
|
||||
int foo;\n\
|
||||
} b = { 100 };\n\
|
||||
int foo = 100;\n\
|
||||
baz = foo;\n\
|
||||
{\n\
|
||||
extern int foo;\n\
|
||||
baz = foo;\n\
|
||||
foo = A::foo + baz;\n\
|
||||
A::foo = b.foo;\n\
|
||||
}\n\
|
||||
foo = b.foo;\n\
|
||||
}\n";
|
||||
std::vector<std::vector<unsigned>> VarTestOffsets(3);
|
||||
VarTestOffsets[0].push_back(19);
|
||||
VarTestOffsets[0].push_back(63);
|
||||
VarTestOffsets[0].push_back(205);
|
||||
VarTestOffsets[0].push_back(223);
|
||||
VarTestOffsets[1].push_back(30);
|
||||
VarTestOffsets[1].push_back(45);
|
||||
VarTestOffsets[1].push_back(172);
|
||||
VarTestOffsets[1].push_back(187);
|
||||
VarTestOffsets[2].push_back(129);
|
||||
VarTestOffsets[2].push_back(148);
|
||||
VarTestOffsets[2].push_back(242);
|
||||
|
||||
testOffsetGroups(VarTest, VarTestOffsets);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,57 +28,57 @@ TEST(ClangTidyDiagnosticConsumer, SortsErrors) {
|
||||
EXPECT_EQ("variable []", Errors[1].Message.Message);
|
||||
}
|
||||
|
||||
TEST(GlobList, Empty) {
|
||||
GlobList Filter("");
|
||||
TEST(ChecksFilter, Empty) {
|
||||
ChecksFilter Filter("");
|
||||
|
||||
EXPECT_TRUE(Filter.contains(""));
|
||||
EXPECT_FALSE(Filter.contains("aaa"));
|
||||
EXPECT_TRUE(Filter.isCheckEnabled(""));
|
||||
EXPECT_FALSE(Filter.isCheckEnabled("aaa"));
|
||||
}
|
||||
|
||||
TEST(GlobList, Nothing) {
|
||||
GlobList Filter("-*");
|
||||
TEST(ChecksFilter, Nothing) {
|
||||
ChecksFilter Filter("-*");
|
||||
|
||||
EXPECT_FALSE(Filter.contains(""));
|
||||
EXPECT_FALSE(Filter.contains("a"));
|
||||
EXPECT_FALSE(Filter.contains("-*"));
|
||||
EXPECT_FALSE(Filter.contains("-"));
|
||||
EXPECT_FALSE(Filter.contains("*"));
|
||||
EXPECT_FALSE(Filter.isCheckEnabled(""));
|
||||
EXPECT_FALSE(Filter.isCheckEnabled("a"));
|
||||
EXPECT_FALSE(Filter.isCheckEnabled("-*"));
|
||||
EXPECT_FALSE(Filter.isCheckEnabled("-"));
|
||||
EXPECT_FALSE(Filter.isCheckEnabled("*"));
|
||||
}
|
||||
|
||||
TEST(GlobList, Everything) {
|
||||
GlobList Filter("*");
|
||||
TEST(ChecksFilter, Everything) {
|
||||
ChecksFilter Filter("*");
|
||||
|
||||
EXPECT_TRUE(Filter.contains(""));
|
||||
EXPECT_TRUE(Filter.contains("aaaa"));
|
||||
EXPECT_TRUE(Filter.contains("-*"));
|
||||
EXPECT_TRUE(Filter.contains("-"));
|
||||
EXPECT_TRUE(Filter.contains("*"));
|
||||
EXPECT_TRUE(Filter.isCheckEnabled(""));
|
||||
EXPECT_TRUE(Filter.isCheckEnabled("aaaa"));
|
||||
EXPECT_TRUE(Filter.isCheckEnabled("-*"));
|
||||
EXPECT_TRUE(Filter.isCheckEnabled("-"));
|
||||
EXPECT_TRUE(Filter.isCheckEnabled("*"));
|
||||
}
|
||||
|
||||
TEST(GlobList, Simple) {
|
||||
GlobList Filter("aaa");
|
||||
TEST(ChecksFilter, Simple) {
|
||||
ChecksFilter Filter("aaa");
|
||||
|
||||
EXPECT_TRUE(Filter.contains("aaa"));
|
||||
EXPECT_FALSE(Filter.contains(""));
|
||||
EXPECT_FALSE(Filter.contains("aa"));
|
||||
EXPECT_FALSE(Filter.contains("aaaa"));
|
||||
EXPECT_FALSE(Filter.contains("bbb"));
|
||||
EXPECT_TRUE(Filter.isCheckEnabled("aaa"));
|
||||
EXPECT_FALSE(Filter.isCheckEnabled(""));
|
||||
EXPECT_FALSE(Filter.isCheckEnabled("aa"));
|
||||
EXPECT_FALSE(Filter.isCheckEnabled("aaaa"));
|
||||
EXPECT_FALSE(Filter.isCheckEnabled("bbb"));
|
||||
}
|
||||
|
||||
TEST(GlobList, Complex) {
|
||||
GlobList Filter("*,-a.*,-b.*,a.1.*,-a.1.A.*,-..,-...,-..+,-*$,-*qwe*");
|
||||
TEST(ChecksFilter, Complex) {
|
||||
ChecksFilter Filter("*,-a.*,-b.*,a.1.*,-a.1.A.*,-..,-...,-..+,-*$,-*qwe*");
|
||||
|
||||
EXPECT_TRUE(Filter.contains("aaa"));
|
||||
EXPECT_TRUE(Filter.contains("qqq"));
|
||||
EXPECT_FALSE(Filter.contains("a."));
|
||||
EXPECT_FALSE(Filter.contains("a.b"));
|
||||
EXPECT_FALSE(Filter.contains("b."));
|
||||
EXPECT_FALSE(Filter.contains("b.b"));
|
||||
EXPECT_TRUE(Filter.contains("a.1.b"));
|
||||
EXPECT_FALSE(Filter.contains("a.1.A.a"));
|
||||
EXPECT_FALSE(Filter.contains("qwe"));
|
||||
EXPECT_FALSE(Filter.contains("asdfqweasdf"));
|
||||
EXPECT_TRUE(Filter.contains("asdfqwEasdf"));
|
||||
EXPECT_TRUE(Filter.isCheckEnabled("aaa"));
|
||||
EXPECT_TRUE(Filter.isCheckEnabled("qqq"));
|
||||
EXPECT_FALSE(Filter.isCheckEnabled("a."));
|
||||
EXPECT_FALSE(Filter.isCheckEnabled("a.b"));
|
||||
EXPECT_FALSE(Filter.isCheckEnabled("b."));
|
||||
EXPECT_FALSE(Filter.isCheckEnabled("b.b"));
|
||||
EXPECT_TRUE(Filter.isCheckEnabled("a.1.b"));
|
||||
EXPECT_FALSE(Filter.isCheckEnabled("a.1.A.a"));
|
||||
EXPECT_FALSE(Filter.isCheckEnabled("qwe"));
|
||||
EXPECT_FALSE(Filter.isCheckEnabled("asdfqweasdf"));
|
||||
EXPECT_TRUE(Filter.isCheckEnabled("asdfqwEasdf"));
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
@@ -41,26 +41,22 @@ private:
|
||||
|
||||
template <typename T>
|
||||
std::string runCheckOnCode(StringRef Code,
|
||||
std::vector<ClangTidyError> *Errors = nullptr,
|
||||
const Twine &Filename = "input.cc",
|
||||
ArrayRef<std::string> ExtraArgs = None) {
|
||||
std::vector<ClangTidyError> *Errors = nullptr) {
|
||||
T Check;
|
||||
ClangTidyContext Context(
|
||||
new DefaultOptionsProvider(ClangTidyGlobalOptions(), ClangTidyOptions()));
|
||||
ClangTidyDiagnosticConsumer DiagConsumer(Context);
|
||||
Check.setContext(&Context);
|
||||
std::vector<std::string> ArgCXX11(1, "-std=c++11");
|
||||
ArgCXX11.insert(ArgCXX11.end(), ExtraArgs.begin(), ExtraArgs.end());
|
||||
|
||||
if (!tooling::runToolOnCodeWithArgs(new TestPPAction(Check, &Context), Code,
|
||||
ArgCXX11, Filename))
|
||||
ArgCXX11))
|
||||
return "";
|
||||
ast_matchers::MatchFinder Finder;
|
||||
Check.registerMatchers(&Finder);
|
||||
std::unique_ptr<tooling::FrontendActionFactory> Factory(
|
||||
tooling::newFrontendActionFactory(&Finder));
|
||||
if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, ArgCXX11,
|
||||
Filename))
|
||||
if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, ArgCXX11))
|
||||
return "";
|
||||
DiagConsumer.finish();
|
||||
tooling::Replacements Fixes;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "ClangTidyTest.h"
|
||||
#include "llvm/HeaderGuardCheck.h"
|
||||
#include "llvm/IncludeOrderCheck.h"
|
||||
#include "llvm/NamespaceCommentCheck.h"
|
||||
#include "gtest/gtest.h"
|
||||
@@ -86,49 +85,6 @@ TEST(NamespaceCommentCheckTest, FixWrongComments) {
|
||||
"} // namespace asdf"));
|
||||
}
|
||||
|
||||
// FIXME: It seems this might be incompatible to dos path. Investigating.
|
||||
#if !defined(_WIN32)
|
||||
static std::string runHeaderGuardCheck(StringRef Code, const Twine &Filename) {
|
||||
return test::runCheckOnCode<LLVMHeaderGuardCheck>(
|
||||
Code, /*Errors=*/nullptr, Filename, std::string("-xc++-header"));
|
||||
}
|
||||
|
||||
TEST(LLVMHeaderGuardCheckTest, FixHeaderGuards) {
|
||||
EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n#define LLVM_ADT_FOO_H\n#endif\n",
|
||||
runHeaderGuardCheck("#ifndef FOO\n#define FOO\n#endif\n",
|
||||
"include/llvm/ADT/foo.h"));
|
||||
|
||||
// Allow trailing underscores.
|
||||
EXPECT_EQ("#ifndef LLVM_ADT_FOO_H_\n#define LLVM_ADT_FOO_H_\n#endif\n",
|
||||
runHeaderGuardCheck(
|
||||
"#ifndef LLVM_ADT_FOO_H_\n#define LLVM_ADT_FOO_H_\n#endif\n",
|
||||
"include/llvm/ADT/foo.h"));
|
||||
|
||||
EXPECT_EQ("#ifndef LLVM_CLANG_C_BAR_H\n#define LLVM_CLANG_C_BAR_H\n\n\n#endif\n",
|
||||
runHeaderGuardCheck("", "./include/clang-c/bar.h"));
|
||||
|
||||
EXPECT_EQ("#ifndef LLVM_CLANG_LIB_CODEGEN_C_H\n#define "
|
||||
"LLVM_CLANG_LIB_CODEGEN_C_H\n\n\n#endif\n",
|
||||
runHeaderGuardCheck("", "tools/clang/lib/CodeGen/c.h"));
|
||||
|
||||
EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_X_H\n#define "
|
||||
"LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_X_H\n\n\n#endif\n",
|
||||
runHeaderGuardCheck("", "tools/clang/tools/extra/clang-tidy/x.h"));
|
||||
|
||||
EXPECT_EQ(
|
||||
"int foo;\n#ifndef LLVM_CLANG_BAR_H\n#define LLVM_CLANG_BAR_H\n#endif\n",
|
||||
runHeaderGuardCheck("int foo;\n#ifndef LLVM_CLANG_BAR_H\n"
|
||||
"#define LLVM_CLANG_BAR_H\n#endif\n",
|
||||
"include/clang/bar.h"));
|
||||
|
||||
EXPECT_EQ("#ifndef LLVM_CLANG_BAR_H\n#define LLVM_CLANG_BAR_H\n\n"
|
||||
"int foo;\n#ifndef FOOLOLO\n#define FOOLOLO\n#endif\n\n#endif\n",
|
||||
runHeaderGuardCheck(
|
||||
"int foo;\n#ifndef FOOLOLO\n#define FOOLOLO\n#endif\n",
|
||||
"include/clang/bar.h"));
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace test
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
||||
|
||||
@@ -14,7 +14,7 @@ TESTNAME = ClangTidy
|
||||
LINK_COMPONENTS := asmparser bitreader support MC MCParser option \
|
||||
TransformUtils
|
||||
USEDLIBS = clangTidy.a clangTidyLLVMModule.a clangTidyGoogleModule.a \
|
||||
clangTidyMiscModule.a clangTidy.a clangTidyUtils.a \
|
||||
clangTidyMiscModule.a clangTidy.a \
|
||||
clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
|
||||
clangStaticAnalyzerCore.a \
|
||||
clangFormat.a clangTooling.a clangFrontend.a clangSerialization.a \
|
||||
|
||||
@@ -1086,7 +1086,6 @@ CursorKind.CUDACONSTANT_ATTR = CursorKind(412)
|
||||
CursorKind.CUDADEVICE_ATTR = CursorKind(413)
|
||||
CursorKind.CUDAGLOBAL_ATTR = CursorKind(414)
|
||||
CursorKind.CUDAHOST_ATTR = CursorKind(415)
|
||||
CursorKind.CUDASHARED_ATTR = CursorKind(416)
|
||||
|
||||
###
|
||||
# Preprocessing
|
||||
@@ -1177,23 +1176,15 @@ class Cursor(Structure):
|
||||
"""
|
||||
Return the display name for the entity referenced by this cursor.
|
||||
|
||||
The display name contains extra information that helps identify the
|
||||
cursor, such as the parameters of a function or template or the
|
||||
arguments of a class template specialization.
|
||||
The display name contains extra information that helps identify the cursor,
|
||||
such as the parameters of a function or template or the arguments of a
|
||||
class template specialization.
|
||||
"""
|
||||
if not hasattr(self, '_displayname'):
|
||||
self._displayname = conf.lib.clang_getCursorDisplayName(self)
|
||||
|
||||
return self._displayname
|
||||
|
||||
@property
|
||||
def mangled_name(self):
|
||||
"""Return the mangled name for the entity referenced by this cursor."""
|
||||
if not hasattr(self, '_mangled_name'):
|
||||
self._mangled_name = conf.lib.clang_Cursor_getMangling(self)
|
||||
|
||||
return self._mangled_name
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
"""
|
||||
@@ -2982,11 +2973,6 @@ functionList = [
|
||||
_CXString,
|
||||
_CXString.from_result),
|
||||
|
||||
("clang_Cursor_getMangling",
|
||||
[Cursor],
|
||||
_CXString,
|
||||
_CXString.from_result),
|
||||
|
||||
# ("clang_getCXTUResourceUsage",
|
||||
# [TranslationUnit],
|
||||
# CXTUResourceUsage),
|
||||
|
||||
@@ -252,17 +252,3 @@ def test_referenced():
|
||||
if c.kind == CursorKind.CALL_EXPR:
|
||||
assert c.referenced.spelling == foo.spelling
|
||||
break
|
||||
|
||||
def test_mangled_name():
|
||||
kInputForMangling = """\
|
||||
int foo(int, int);
|
||||
"""
|
||||
tu = get_tu(kInputForMangling, lang='cpp')
|
||||
foo = get_cursor(tu, 'foo')
|
||||
|
||||
# Since libclang does not link in targets, we cannot pass a triple to it
|
||||
# and force the target. To enable this test to pass on all platforms, accept
|
||||
# all valid manglings.
|
||||
# [c-index-test handles this by running the source through clang, emitting
|
||||
# an AST file and running libclang on that AST file]
|
||||
assert foo.mangled_name in ('_Z3fooii', '__Z3fooii', '?foo@@YAHHH')
|
||||
|
||||
@@ -33,43 +33,6 @@ The ``.clang-format`` file uses YAML format:
|
||||
# A comment.
|
||||
...
|
||||
|
||||
The configuration file can consist of several sections each having different
|
||||
``Language:`` parameter denoting the programming language this section of the
|
||||
configuration is targeted at. See the description of the **Language** option
|
||||
below for the list of supported languages. The first section may have no
|
||||
language set, it will set the default style options for all lanugages.
|
||||
Configuration sections for specific language will override options set in the
|
||||
default section.
|
||||
|
||||
When :program:`clang-format` formats a file, it auto-detects the language using
|
||||
the file name. When formatting standard input or a file that doesn't have the
|
||||
extension corresponding to its language, ``-assume-filename=`` option can be
|
||||
used to override the file name :program:`clang-format` uses to detect the
|
||||
language.
|
||||
|
||||
An example of a configuration file for multiple languages:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
# We'll use defaults from the LLVM style, but with 4 columns indentation.
|
||||
BasedOnStyle: LLVM
|
||||
IndentWidth: 4
|
||||
---
|
||||
Language: Cpp
|
||||
# Force pointers to the type for C++.
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
---
|
||||
Language: JavaScript
|
||||
# Use 100 columns for JS.
|
||||
ColumnLimit: 100
|
||||
---
|
||||
Language: Proto
|
||||
# Don't format .proto files.
|
||||
DisableFormat: true
|
||||
...
|
||||
|
||||
An easy way to get a valid ``.clang-format`` file containing all configuration
|
||||
options of a certain predefined style is:
|
||||
|
||||
@@ -170,13 +133,6 @@ the configuration (without a prefix: ``Auto``).
|
||||
If ``true``, ``while (true) continue;`` can be put on a
|
||||
single line.
|
||||
|
||||
**AlwaysBreakAfterDefinitionReturnType** (``bool``)
|
||||
If ``true``, always break after function definition return types.
|
||||
|
||||
More truthfully called 'break before the identifier following the type
|
||||
in a function definition'. PenaltyReturnTypeOnItsOwnLine becomes
|
||||
irrelevant.
|
||||
|
||||
**AlwaysBreakBeforeMultilineStrings** (``bool``)
|
||||
If ``true``, always break before multiline string literals.
|
||||
|
||||
@@ -202,7 +158,7 @@ the configuration (without a prefix: ``Auto``).
|
||||
Like ``Attach``, but break before braces on function, namespace and
|
||||
class definitions.
|
||||
* ``BS_Stroustrup`` (in configuration: ``Stroustrup``)
|
||||
Like ``Attach``, but break before function definitions, and 'else'.
|
||||
Like ``Attach``, but break before function definitions.
|
||||
* ``BS_Allman`` (in configuration: ``Allman``)
|
||||
Always break before braces.
|
||||
* ``BS_GNU`` (in configuration: ``GNU``)
|
||||
@@ -257,7 +213,7 @@ the configuration (without a prefix: ``Auto``).
|
||||
|
||||
**DerivePointerAlignment** (``bool``)
|
||||
If ``true``, analyze the formatted file for the most common
|
||||
alignment of ``&`` and ``*``. ``PointerAlignment`` is then used only as fallback.
|
||||
alignment of & and *. ``PointerAlignment`` is then used only as fallback.
|
||||
|
||||
**DisableFormat** (``bool``)
|
||||
Disables formatting at all.
|
||||
|
||||
@@ -1843,7 +1843,7 @@ iterations. Full unrolling is only possible if the loop trip count is known at
|
||||
compile time. Partial unrolling replicates the loop body within the loop and
|
||||
reduces the trip count.
|
||||
|
||||
If ``unroll(full)`` is specified the unroller will attempt to fully unroll the
|
||||
If ``unroll(enable)`` is specified the unroller will attempt to fully unroll the
|
||||
loop if the trip count is known at compile time. If the loop count is not known
|
||||
or the fully unrolled code size is greater than the limit specified by the
|
||||
`-pragma-unroll-threshold` command line option the loop will be partially
|
||||
@@ -1851,7 +1851,7 @@ unrolled subject to the same limit.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#pragma clang loop unroll(full)
|
||||
#pragma clang loop unroll(enable)
|
||||
for(...) {
|
||||
...
|
||||
}
|
||||
|
||||
@@ -319,16 +319,6 @@ usingDecl()
|
||||
matches using X::x </pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('usingDirectiveDecl0')"><a name="usingDirectiveDecl0Anchor">usingDirectiveDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingDirectiveDecl.html">UsingDirectiveDecl</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="usingDirectiveDecl0"><pre>Matches using namespace declarations.
|
||||
|
||||
Given
|
||||
namespace X { int x; }
|
||||
using namespace X;
|
||||
usingDirectiveDecl()
|
||||
matches using namespace X </pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('varDecl0')"><a name="varDecl0Anchor">varDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="varDecl0"><pre>Matches variable declarations.
|
||||
|
||||
@@ -365,14 +355,6 @@ nestedNameSpecifier()
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('CUDAKernelCallExpr0')"><a name="CUDAKernelCallExpr0Anchor">CUDAKernelCallExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CUDAKernelCallExpr.html">CUDAKernelCallExpr</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="CUDAKernelCallExpr0"><pre>Matches CUDA kernel call expression.
|
||||
|
||||
Example matches,
|
||||
kernel<<<i,j>>>();
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('arraySubscriptExpr0')"><a name="arraySubscriptExpr0Anchor">arraySubscriptExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="arraySubscriptExpr0"><pre>Matches array subscript expressions.
|
||||
|
||||
@@ -729,7 +711,7 @@ Given
|
||||
int a[] = { 1, 2 };
|
||||
struct B { int x, y; };
|
||||
B b = { 5, 6 };
|
||||
initListExpr()
|
||||
initList()
|
||||
matches "{ 1, 2 }" and "{ 5, 6 }"
|
||||
</pre></td></tr>
|
||||
|
||||
@@ -894,18 +876,6 @@ Example matches "abcd", L"abcd"
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('substNonTypeTemplateParmExpr0')"><a name="substNonTypeTemplateParmExpr0Anchor">substNonTypeTemplateParmExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1SubstNonTypeTemplateParmExpr.html">SubstNonTypeTemplateParmExpr</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="substNonTypeTemplateParmExpr0"><pre>Matches substitutions of non-type template parameters.
|
||||
|
||||
Given
|
||||
template <int N>
|
||||
struct A { static const int n = N; };
|
||||
struct B : public A<42> {};
|
||||
substNonTypeTemplateParmExpr()
|
||||
matches "N" in the right-hand side of "static const int n = N;"
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('switchCase0')"><a name="switchCase0Anchor">switchCase</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1SwitchCase.html">SwitchCase</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="switchCase0"><pre>Matches case and default statements inside switch statements.
|
||||
|
||||
@@ -1299,7 +1269,6 @@ Given
|
||||
int a[] = { 2, 3 }
|
||||
int b[42];
|
||||
int c[a[0]];
|
||||
}
|
||||
variableArrayType()
|
||||
matches "int c[a[0]]"
|
||||
</pre></td></tr>
|
||||
@@ -1412,6 +1381,26 @@ constructorDecl(hasAnyConstructorInitializer(isWritten()))
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('hasOverloadedOperatorName0')"><a name="hasOverloadedOperatorName0Anchor">hasOverloadedOperatorName</a></td><td>StringRef Name</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="hasOverloadedOperatorName0"><pre>Matches overloaded operator names.
|
||||
|
||||
Matches overloaded operator names specified in strings without the
|
||||
"operator" prefix: e.g. "<<".
|
||||
|
||||
Given:
|
||||
class A { int operator*(); };
|
||||
const A &operator<<(const A &a, const A &b);
|
||||
A a;
|
||||
a << a; <-- This matches
|
||||
|
||||
operatorCallExpr(hasOverloadedOperatorName("<<"))) matches the specified
|
||||
line and recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
|
||||
the declaration of A.
|
||||
|
||||
Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>>
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('isConst0')"><a name="isConst0Anchor">isConst</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isConst0"><pre>Matches if the given method declaration is const.
|
||||
|
||||
@@ -1481,7 +1470,7 @@ operatorCallExpr(hasOverloadedOperatorName("<<"))) matches the specified
|
||||
line and recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
|
||||
the declaration of A.
|
||||
|
||||
Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>
|
||||
Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>>
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
@@ -1612,30 +1601,10 @@ and reference to that variable declaration within a compound statement.
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('hasCudaDeviceAttr0')"><a name="hasCudaDeviceAttr0Anchor">hasCudaDeviceAttr</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="hasCudaDeviceAttr0"><pre>Matches declaration that has CUDA device attribute.
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('equalsNode0')"><a name="equalsNode0Anchor">equalsNode</a></td><td>Decl *Node</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="equalsNode0"><pre>Matches if a node equals another node.
|
||||
|
||||
Given
|
||||
__attribute__((device)) void f() { ... }
|
||||
matches the function declaration of f.
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('hasCudaGlobalAttr0')"><a name="hasCudaGlobalAttr0Anchor">hasCudaGlobalAttr</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="hasCudaGlobalAttr0"><pre>Matches declaration that has CUDA global attribute.
|
||||
|
||||
Given
|
||||
__attribute__((global)) void f() { ... }
|
||||
matches the function declaration of f.
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('hasCudaHostAttr0')"><a name="hasCudaHostAttr0Anchor">hasCudaHostAttr</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="hasCudaHostAttr0"><pre>Matches declaration that has CUDA host attribute.
|
||||
|
||||
Given
|
||||
__attribute__((host)) void f() { ... }
|
||||
matches the function declaration of f.
|
||||
Decl has pointer identity in the AST.
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
@@ -1698,26 +1667,6 @@ Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Charac
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('hasOverloadedOperatorName0')"><a name="hasOverloadedOperatorName0Anchor">hasOverloadedOperatorName</a></td><td>StringRef Name</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="hasOverloadedOperatorName0"><pre>Matches overloaded operator names.
|
||||
|
||||
Matches overloaded operator names specified in strings without the
|
||||
"operator" prefix: e.g. "<<".
|
||||
|
||||
Given:
|
||||
class A { int operator*(); };
|
||||
const A &operator<<(const A &a, const A &b);
|
||||
A a;
|
||||
a << a; <-- This matches
|
||||
|
||||
operatorCallExpr(hasOverloadedOperatorName("<<"))) matches the specified
|
||||
line and recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
|
||||
the declaration of A.
|
||||
|
||||
Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isDefinition2')"><a name="isDefinition2Anchor">isDefinition</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isDefinition2"><pre>Matches if a declaration has a body attached.
|
||||
|
||||
@@ -1733,17 +1682,6 @@ Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDec
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isDeleted0')"><a name="isDeleted0Anchor">isDeleted</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isDeleted0"><pre>Matches deleted function declarations.
|
||||
|
||||
Given:
|
||||
void Func();
|
||||
void DeletedFunc() = delete;
|
||||
functionDecl(isDeleted())
|
||||
matches the declaration of DeletedFunc, but not Func.
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isExplicitTemplateSpecialization0')"><a name="isExplicitTemplateSpecialization0Anchor">isExplicitTemplateSpecialization</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization0"><pre>Matches explicit template specializations of function, class, or
|
||||
static member variable template instantiations.
|
||||
@@ -1962,6 +1900,14 @@ and reference to that variable declaration within a compound statement.
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('equalsNode1')"><a name="equalsNode1Anchor">equalsNode</a></td><td>Stmt *Node</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="equalsNode1"><pre>Matches if a node equals another node.
|
||||
|
||||
Stmt has pointer identity in the AST.
|
||||
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>></td><td class="name" onclick="toggle('isDefinition0')"><a name="isDefinition0Anchor">isDefinition</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isDefinition0"><pre>Matches if a declaration has a body attached.
|
||||
|
||||
@@ -2604,7 +2550,7 @@ given matcher.
|
||||
|
||||
Example matches y.x() (matcher = callExpr(callee(methodDecl(hasName("x")))))
|
||||
class Y { public: void x(); };
|
||||
void z() { Y y; y.x(); }
|
||||
void z() { Y y; y.x();
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
@@ -3502,7 +3448,6 @@ Example matches X &x and const X &y
|
||||
void a(X b) {
|
||||
X &x = b;
|
||||
const X &y = b;
|
||||
}
|
||||
};
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ Modules are modeled as if each submodule were a separate translation unit, and a
|
||||
|
||||
.. note::
|
||||
|
||||
This behavior is currently only approximated when building a module with submodules. Entities within a submodule that has already been built are visible when building later submodules in that module. This can lead to fragile modules that depend on the build order used for the submodules of the module, and should not be relied upon. This behavior is subject to change.
|
||||
This behavior is currently only approximated when building a module. Entities within a submodule that has already been built are visible when building later submodules in that module. This can lead to fragile modules that depend on the build order used for the submodules of the module, and should not be relied upon.
|
||||
|
||||
As an example, in C, this implies that if two structs are defined in different submodules with the same name, those two types are distinct types (but may be *compatible* types if their definitions match. In C++, two structs defined with the same name in different submodules are the *same* type, and must be equivalent under C++'s One Definition Rule.
|
||||
|
||||
@@ -216,8 +216,6 @@ As an example, in C, this implies that if two structs are defined in different s
|
||||
|
||||
Clang currently only performs minimal checking for violations of the One Definition Rule.
|
||||
|
||||
If any submodule of a module is imported into any part of a program, the entire top-level module is considered to be part of the program. As a consequence of this, Clang may diagnose conflicts between an entity declared in an unimported submodule and an entity declared in the current translation unit, and Clang may inline or devirtualize based on knowledge from unimported submodules.
|
||||
|
||||
Macros
|
||||
------
|
||||
|
||||
|
||||
@@ -55,7 +55,16 @@ Major New Features
|
||||
would return true when the attribute spelling was known, regardless of whether
|
||||
the attribute was available to the specific target. Clang now returns true
|
||||
only when the attribute pertains to the current compilation target.
|
||||
|
||||
|
||||
- Clang 3.5 now has parsing and semantic-analysis support for all OpenMP 3.1
|
||||
pragmas (except atomics and ordered). LLVM's OpenMP runtime library,
|
||||
originally developed by Intel, has been modified to work on ARM, PowerPC,
|
||||
as well as X86. Code generation support is minimal at this point and will
|
||||
continue to be developed for 3.6, along with the rest of OpenMP 3.1.
|
||||
Support for OpenMP 4.0 features, such as SIMD and target accelerator
|
||||
directives, is also in progress. Contributors to this work include AMD,
|
||||
Argonne National Lab., IBM, Intel, Texas Instruments, University of Houston
|
||||
and many others.
|
||||
|
||||
Improvements to Clang's diagnostics
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -67,6 +76,65 @@ about them. The improvements since the 3.4 release include:
|
||||
- GCC compatibility: Clang displays a warning on unsupported gcc
|
||||
optimization flags instead of an error.
|
||||
|
||||
- New warning `-Wabsolute-value`: Clang warns about incorrect or useless usage
|
||||
of the absolute functions (`abs`, `fabsf`, etc).
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <stdlib.h>
|
||||
void foo() {
|
||||
unsigned int i=0;
|
||||
abs(i);
|
||||
}
|
||||
|
||||
returns
|
||||
`warning: taking the absolute value of unsigned type 'unsigned int' has no effect [-Wabsolute-value]`
|
||||
|
||||
or
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <stdlib.h>
|
||||
void plop() {
|
||||
long long i=0;
|
||||
abs(i);
|
||||
}
|
||||
|
||||
returns
|
||||
`warning: absolute value function 'abs' given an argument of type 'long long' but has parameter of type 'int' which may cause truncation of value [-Wabsolute-value] use function 'llabs' instead`
|
||||
|
||||
- New warning `-Wtautological-pointer-compare`:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#include <stddef.h>
|
||||
void foo() {
|
||||
int arr[5];
|
||||
int x;
|
||||
// warn on these conditionals
|
||||
if (foo);
|
||||
if (arr);
|
||||
if (&x);
|
||||
if (foo == NULL);
|
||||
if (arr == NULL);
|
||||
if (&x == NULL);
|
||||
}
|
||||
|
||||
returns
|
||||
`warning: comparison of address of 'x' equal to a null pointer is always false [-Wtautological-pointer-compare]`
|
||||
|
||||
- New warning `-Wtautological-undefined-compare`:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#include <stddef.h>
|
||||
void f(int &x) {
|
||||
if (&x == nullptr) { }
|
||||
}
|
||||
|
||||
returns
|
||||
`warning: reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to false [-Wtautological-undefined-compare]`
|
||||
|
||||
- ...
|
||||
|
||||
New Compiler Flags
|
||||
@@ -100,7 +168,8 @@ passes via three new flags: `-Rpass`, `-Rpass-missed` and `-Rpass-analysis`.
|
||||
These flags take a POSIX regular expression which indicates the name
|
||||
of the pass (or passes) that should emit optimization remarks.
|
||||
|
||||
The option `-u` is forwarded to the linker on gnutools toolchains.
|
||||
Options `-u` and `-z` are forwarded to the linker on gnutools toolchains.
|
||||
|
||||
|
||||
New Pragmas in Clang
|
||||
-----------------------
|
||||
@@ -111,29 +180,12 @@ interleaving, and unrolling to be enabled or disabled. Vector width as well
|
||||
as interleave and unrolling count can be manually specified. See language
|
||||
extensions for details.
|
||||
|
||||
Clang now supports the `#pragma unroll` and `#pragma nounroll` directives to
|
||||
specify loop unrolling optimization hints. Placed just prior to the desired
|
||||
loop, `#pragma unroll` directs the loop unroller to attempt to fully unroll the
|
||||
loop. The pragma may also be specified with a positive integer parameter
|
||||
indicating the desired unroll count: `#pragma unroll _value_`. The unroll count
|
||||
parameter can be optionally enclosed in parentheses. The directive `#pragma
|
||||
nounroll` indicates that the loop should not be unrolled.
|
||||
|
||||
Windows Support
|
||||
---------------
|
||||
|
||||
Clang's support for building native Windows programs, compatible with Visual
|
||||
C++, has improved significantly since the previous release. This includes
|
||||
correctly passing non-trivial objects by value, record layout, basic debug info,
|
||||
`Address Sanitizer <AddressSanitizer.html>`_ support, RTTI, name mangling,
|
||||
DLL attributes, and many many bug fixes. See
|
||||
`MSVC Compatibility <MSVCCompatibility.html>`_ for details.
|
||||
|
||||
While still considered experimental, Clang's Windows support is good enough
|
||||
that Clang can self-host on Windows, and projects such as Chromium and Firefox
|
||||
have been built successfully using the
|
||||
`/fallback <UsersManual.html#the-fallback-option>`_ option.
|
||||
|
||||
Clang now supports the `#pragma unroll` directive to specify loop unrolling
|
||||
optimization hints. Placed just prior to the desired loop, `#pragma unroll`
|
||||
directs the loop unroller to attempt to fully unroll the loop. The pragma may
|
||||
also be specified with a positive integer parameter indicating the desired
|
||||
unroll count: `#pragma unroll _value_`. The unroll count parameter can be
|
||||
optionally enclosed in parentheses.
|
||||
|
||||
C Language Changes in Clang
|
||||
---------------------------
|
||||
@@ -165,6 +217,13 @@ OpenCL C Language Changes in Clang
|
||||
|
||||
...
|
||||
|
||||
OpenMP C/C++ Language Changes in Clang
|
||||
--------------------------------------
|
||||
|
||||
- `Status of supported OpenMP constructs
|
||||
<https://github.com/clang-omp/clang/wiki/Status-of-supported-OpenMP-constructs>`_.
|
||||
|
||||
|
||||
Internal API Changes
|
||||
--------------------
|
||||
|
||||
@@ -182,6 +241,16 @@ libclang
|
||||
Static Analyzer
|
||||
---------------
|
||||
|
||||
Check for code testing a variable for 0 after using it as a denominator.
|
||||
This new checker, alpha.core.TestAfterDivZero, catches issues like this:
|
||||
|
||||
.. code:: c
|
||||
|
||||
int sum = ...
|
||||
int avg = sum / count; // potential division by zero...
|
||||
if (count == 0) { ... } // ...caught here
|
||||
|
||||
|
||||
The `-analyzer-config` options are now passed from scan-build through to
|
||||
ccc-analyzer and then to Clang.
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user