Compare commits
239 Commits
mpi-gpu
...
llvmorg-3.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e354bf82ba | ||
|
|
651925a496 | ||
|
|
628944dbd8 | ||
|
|
4e4e391da8 | ||
|
|
b6574c9047 | ||
|
|
be4dc0e165 | ||
|
|
6a9d7718ed | ||
|
|
fa81086df9 | ||
|
|
6c5819e34b | ||
|
|
07f06bbd97 | ||
|
|
9b24c0ffae | ||
|
|
9abeb69615 | ||
|
|
39ba7e0552 | ||
|
|
d31f4c6106 | ||
|
|
ea9e182ade | ||
|
|
dffdec69e1 | ||
|
|
f03c72a577 | ||
|
|
28be27a04e | ||
|
|
92215b0dd0 | ||
|
|
9ef730ae0a | ||
|
|
2d9a3bee4c | ||
|
|
ef1c6718fd | ||
|
|
b20996e713 | ||
|
|
e228322c1c | ||
|
|
4c9e37fcc4 | ||
|
|
9ed146d6a8 | ||
|
|
7a61678035 | ||
|
|
64e66b01b2 | ||
|
|
6e3c56e785 | ||
|
|
37c07a6294 | ||
|
|
085abb5d1d | ||
|
|
92f45d1333 | ||
|
|
7e841d753b | ||
|
|
18bc2ed14a | ||
|
|
93e02253d6 | ||
|
|
973b3c6f29 | ||
|
|
1d2a9aa20d | ||
|
|
f0625368ba | ||
|
|
50c62001ca | ||
|
|
e4301bee75 | ||
|
|
8cdf2c90f0 | ||
|
|
b29f5b907f | ||
|
|
8f588dd56e | ||
|
|
4be2d4c3af | ||
|
|
f10332cab5 | ||
|
|
bb8359ff25 | ||
|
|
d8ce57ff2f | ||
|
|
7585cbd858 | ||
|
|
8340bdc9d2 | ||
|
|
e6401e289e | ||
|
|
75d716d345 | ||
|
|
df22cb2bc3 | ||
|
|
40ddbe66df | ||
|
|
901f3d19d8 | ||
|
|
e4565b26dc | ||
|
|
30d2ca75b2 | ||
|
|
84a7df7eaf | ||
|
|
2234ce5751 | ||
|
|
88c94367bf | ||
|
|
81624a1b81 | ||
|
|
55bcb7bea7 | ||
|
|
6b412de086 | ||
|
|
5cf014d867 | ||
|
|
9d2aa79b33 | ||
|
|
0dae6cdb69 | ||
|
|
6d4022f7f6 | ||
|
|
372b086a97 | ||
|
|
1486635524 | ||
|
|
728f55c9ac | ||
|
|
5ef6392a23 | ||
|
|
de7b942bde | ||
|
|
639afbbbf9 | ||
|
|
7ed3d6575a | ||
|
|
685924c788 | ||
|
|
b2d7415042 | ||
|
|
08c8744ae8 | ||
|
|
f5bcfc4fc2 | ||
|
|
d2d30b50c1 | ||
|
|
d51f07da55 | ||
|
|
08d315f5c5 | ||
|
|
e9f61a123a | ||
|
|
f6bf66347d | ||
|
|
2646c1259d | ||
|
|
cc13b7042d | ||
|
|
64f980a01b | ||
|
|
3f173e827a | ||
|
|
7863d07ace | ||
|
|
24b3307b8a | ||
|
|
b16d386b54 | ||
|
|
4feb6fe3a3 | ||
|
|
2c03fbfd18 | ||
|
|
a33f8c9ee0 | ||
|
|
2a46c56ee9 | ||
|
|
492e5db50e | ||
|
|
a90d20129d | ||
|
|
6c9c1dcd65 | ||
|
|
6f9000213b | ||
|
|
4ce9a1a5f5 | ||
|
|
942a2456ac | ||
|
|
3449325506 | ||
|
|
2bace4c6ed | ||
|
|
55b9030c31 | ||
|
|
0cb1d7aac0 | ||
|
|
3915840558 | ||
|
|
e222c9e1a4 | ||
|
|
a5166ef900 | ||
|
|
98def3001e | ||
|
|
1c81157a21 | ||
|
|
322fcb0c9b | ||
|
|
aacbb87535 | ||
|
|
06d5a61a5d | ||
|
|
971e92b417 | ||
|
|
4b156f75c9 | ||
|
|
a49d21edfb | ||
|
|
2bf62cbd91 | ||
|
|
484f12f661 | ||
|
|
f015491478 | ||
|
|
fc44467537 | ||
|
|
c740b0f251 | ||
|
|
d355b771d6 | ||
|
|
08cbe67bbf | ||
|
|
3b19a92b75 | ||
|
|
40a62e6d56 | ||
|
|
42bd5807a3 | ||
|
|
85e644f424 | ||
|
|
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-apply-replacements)
|
||||||
add_subdirectory(clang-modernize)
|
add_subdirectory(clang-modernize)
|
||||||
add_subdirectory(clang-rename)
|
|
||||||
add_subdirectory(modularize)
|
add_subdirectory(modularize)
|
||||||
add_subdirectory(module-map-checker)
|
add_subdirectory(module-map-checker)
|
||||||
add_subdirectory(remove-cstr-calls)
|
add_subdirectory(remove-cstr-calls)
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ include $(CLANG_LEVEL)/../../Makefile.config
|
|||||||
|
|
||||||
PARALLEL_DIRS := remove-cstr-calls tool-template modularize \
|
PARALLEL_DIRS := remove-cstr-calls tool-template modularize \
|
||||||
module-map-checker pp-trace
|
module-map-checker pp-trace
|
||||||
DIRS := clang-apply-replacements clang-modernize clang-rename clang-tidy \
|
DIRS := clang-apply-replacements clang-modernize clang-tidy clang-query \
|
||||||
clang-query unittests
|
unittests
|
||||||
|
|
||||||
include $(CLANG_LEVEL)/Makefile
|
include $(CLANG_LEVEL)/Makefile
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ int AddOverrideTransform::apply(const CompilationDatabase &Database,
|
|||||||
// Make Fixer available to handleBeginSource().
|
// Make Fixer available to handleBeginSource().
|
||||||
this->Fixer = &Fixer;
|
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";
|
llvm::errs() << "Error encountered during translation.\n";
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,8 +116,7 @@ private:
|
|||||||
// checking for equality because it can also be part of the preamble if the
|
// checking for equality because it can also be part of the preamble if the
|
||||||
// preamble is the whole file.
|
// preamble is the whole file.
|
||||||
unsigned Preamble =
|
unsigned Preamble =
|
||||||
Lexer::ComputePreamble(SM.getBuffer(Guard.FID)->getBuffer(), LangOpts)
|
Lexer::ComputePreamble(SM.getBuffer(Guard.FID), LangOpts).first;
|
||||||
.first;
|
|
||||||
unsigned IfndefOffset = SM.getFileOffset(Guard.IfndefLoc);
|
unsigned IfndefOffset = SM.getFileOffset(Guard.IfndefLoc);
|
||||||
if (IfndefOffset > (Preamble + 1))
|
if (IfndefOffset > (Preamble + 1))
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -49,8 +49,7 @@ private:
|
|||||||
FactoryAdaptor(MatchFinder &Finder, Transform &Owner)
|
FactoryAdaptor(MatchFinder &Finder, Transform &Owner)
|
||||||
: Finder(Finder), Owner(Owner) {}
|
: Finder(Finder), Owner(Owner) {}
|
||||||
|
|
||||||
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &,
|
ASTConsumer *CreateASTConsumer(CompilerInstance &, StringRef) {
|
||||||
StringRef) {
|
|
||||||
return Finder.newASTConsumer();
|
return Finder.newASTConsumer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,9 +128,8 @@ Transform::addReplacementForCurrentTU(const clang::tooling::Replacement &R) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<FrontendActionFactory>
|
FrontendActionFactory *Transform::createActionFactory(MatchFinder &Finder) {
|
||||||
Transform::createActionFactory(MatchFinder &Finder) {
|
return new ActionFactory(Finder, /*Owner=*/ *this);
|
||||||
return llvm::make_unique<ActionFactory>(Finder, /*Owner=*/*this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Version Version::getFromString(llvm::StringRef VersionStr) {
|
Version Version::getFromString(llvm::StringRef VersionStr) {
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ protected:
|
|||||||
///
|
///
|
||||||
/// The factory returned by this function is responsible for calling back to
|
/// The factory returned by this function is responsible for calling back to
|
||||||
/// Transform to call handleBeginSource() and handleEndSource().
|
/// Transform to call handleBeginSource() and handleEndSource().
|
||||||
std::unique_ptr<clang::tooling::FrontendActionFactory>
|
clang::tooling::FrontendActionFactory *
|
||||||
createActionFactory(clang::ast_matchers::MatchFinder &Finder);
|
createActionFactory(clang::ast_matchers::MatchFinder &Finder);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ int LoopConvertTransform::apply(const CompilationDatabase &Database,
|
|||||||
LFK_PseudoArray, /*Owner=*/ *this);
|
LFK_PseudoArray, /*Owner=*/ *this);
|
||||||
Finder.addMatcher(makePseudoArrayLoopMatcher(), &PseudoarrrayLoopFixer);
|
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";
|
llvm::errs() << "Error encountered during translation.\n";
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ int PassByValueTransform::apply(const tooling::CompilationDatabase &Database,
|
|||||||
// make the replacer available to handleBeginSource()
|
// make the replacer available to handleBeginSource()
|
||||||
this->Replacer = &Replacer;
|
this->Replacer = &Replacer;
|
||||||
|
|
||||||
if (Tool.run(createActionFactory(Finder).get())) {
|
if (Tool.run(createActionFactory(Finder))) {
|
||||||
llvm::errs() << "Error encountered during translation.\n";
|
llvm::errs() << "Error encountered during translation.\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ ReplaceAutoPtrTransform::apply(const CompilationDatabase &Database,
|
|||||||
Finder.addMatcher(makeAutoPtrUsingDeclMatcher(), &Replacer);
|
Finder.addMatcher(makeAutoPtrUsingDeclMatcher(), &Replacer);
|
||||||
Finder.addMatcher(makeTransferOwnershipExprMatcher(), &Fixer);
|
Finder.addMatcher(makeTransferOwnershipExprMatcher(), &Fixer);
|
||||||
|
|
||||||
if (Tool.run(createActionFactory(Finder).get())) {
|
if (Tool.run(createActionFactory(Finder))) {
|
||||||
llvm::errs() << "Error encountered during translation.\n";
|
llvm::errs() << "Error encountered during translation.\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ int UseAutoTransform::apply(const clang::tooling::CompilationDatabase &Database,
|
|||||||
Finder.addMatcher(makeIteratorDeclMatcher(), &ReplaceIterators);
|
Finder.addMatcher(makeIteratorDeclMatcher(), &ReplaceIterators);
|
||||||
Finder.addMatcher(makeDeclWithNewMatcher(), &ReplaceNew);
|
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";
|
llvm::errs() << "Error encountered during translation.\n";
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ int UseNullptrTransform::apply(const CompilationDatabase &Database,
|
|||||||
NullptrFixer Fixer(AcceptedChanges, MacroNames, /*Owner=*/ *this);
|
NullptrFixer Fixer(AcceptedChanges, MacroNames, /*Owner=*/ *this);
|
||||||
|
|
||||||
Finder.addMatcher(makeCastSequenceMatcher(), &Fixer);
|
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";
|
llvm::errs() << "Error encountered during translation.\n";
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -248,15 +248,14 @@ static CompilerVersions handleSupportedCompilers(const char *ProgName,
|
|||||||
return RequiredVersions;
|
return RequiredVersions;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<CompilationDatabase>
|
CompilationDatabase *autoDetectCompilations(std::string &ErrorMessage) {
|
||||||
autoDetectCompilations(std::string &ErrorMessage) {
|
|
||||||
// Auto-detect a compilation database from BuildPath.
|
// Auto-detect a compilation database from BuildPath.
|
||||||
if (BuildPath.getNumOccurrences() > 0)
|
if (BuildPath.getNumOccurrences() > 0)
|
||||||
return CompilationDatabase::autoDetectFromDirectory(BuildPath,
|
return CompilationDatabase::autoDetectFromDirectory(BuildPath,
|
||||||
ErrorMessage);
|
ErrorMessage);
|
||||||
// Try to auto-detect a compilation database from the first source.
|
// Try to auto-detect a compilation database from the first source.
|
||||||
if (!SourcePaths.empty()) {
|
if (!SourcePaths.empty()) {
|
||||||
if (std::unique_ptr<CompilationDatabase> Compilations =
|
if (CompilationDatabase *Compilations =
|
||||||
CompilationDatabase::autoDetectFromSource(SourcePaths[0],
|
CompilationDatabase::autoDetectFromSource(SourcePaths[0],
|
||||||
ErrorMessage)) {
|
ErrorMessage)) {
|
||||||
// FIXME: just pass SourcePaths[0] once getCompileCommands supports
|
// 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
|
// If no compilation database can be detected from source then we create a
|
||||||
// fixed compilation database with c++11 support.
|
// fixed compilation database with c++11 support.
|
||||||
std::string CommandLine[] = { "-std=c++11" };
|
std::string CommandLine[] = { "-std=c++11" };
|
||||||
return llvm::make_unique<FixedCompilationDatabase>(".", CommandLine);
|
return new FixedCompilationDatabase(".", CommandLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorMessage = "Could not determine sources to transform";
|
ErrorMessage = "Could not determine sources to transform";
|
||||||
@@ -335,7 +334,7 @@ int main(int argc, const char **argv) {
|
|||||||
|
|
||||||
if (!Compilations) {
|
if (!Compilations) {
|
||||||
std::string ErrorMessage;
|
std::string ErrorMessage;
|
||||||
Compilations = autoDetectCompilations(ErrorMessage);
|
Compilations.reset(autoDetectCompilations(ErrorMessage));
|
||||||
if (!Compilations) {
|
if (!Compilations) {
|
||||||
llvm::errs() << llvm::sys::path::filename(argv[0]) << ": " << ErrorMessage
|
llvm::errs() << llvm::sys::path::filename(argv[0]) << ": " << ErrorMessage
|
||||||
<< "\n";
|
<< "\n";
|
||||||
|
|||||||
@@ -157,12 +157,23 @@ QueryRef makeInvalidQueryFromDiagnostics(const Diagnostics &Diag) {
|
|||||||
return new InvalidQuery(OS.str());
|
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
|
} // namespace
|
||||||
|
|
||||||
QueryRef QueryParser::completeMatcherExpression() {
|
QueryRef QueryParser::completeMatcherExpression() {
|
||||||
std::vector<MatcherCompletion> Comps = Parser::completeExpression(
|
std::vector<MatcherCompletion> Comps = Parser::completeExpression(
|
||||||
StringRef(Begin, End - Begin), CompletionPos - Begin, nullptr,
|
StringRef(Begin, End - Begin), CompletionPos - Begin);
|
||||||
&QS.NamedValues);
|
|
||||||
for (std::vector<MatcherCompletion>::iterator I = Comps.begin(),
|
for (std::vector<MatcherCompletion>::iterator I = Comps.begin(),
|
||||||
E = Comps.end();
|
E = Comps.end();
|
||||||
I != E; ++I) {
|
I != E; ++I) {
|
||||||
@@ -183,6 +194,8 @@ QueryRef QueryParser::doParse() {
|
|||||||
.Case("unlet", PQK_Unlet)
|
.Case("unlet", PQK_Unlet)
|
||||||
.Default(PQK_Invalid);
|
.Default(PQK_Invalid);
|
||||||
|
|
||||||
|
QuerySessionSema S(QS);
|
||||||
|
|
||||||
switch (QKind) {
|
switch (QKind) {
|
||||||
case PQK_NoOp:
|
case PQK_NoOp:
|
||||||
return new NoOpQuery;
|
return new NoOpQuery;
|
||||||
@@ -201,8 +214,8 @@ QueryRef QueryParser::doParse() {
|
|||||||
|
|
||||||
Diagnostics Diag;
|
Diagnostics Diag;
|
||||||
ast_matchers::dynamic::VariantValue Value;
|
ast_matchers::dynamic::VariantValue Value;
|
||||||
if (!Parser::parseExpression(StringRef(Begin, End - Begin), nullptr,
|
if (!Parser::parseExpression(StringRef(Begin, End - Begin), &S, &Value,
|
||||||
&QS.NamedValues, &Value, &Diag)) {
|
&Diag)) {
|
||||||
return makeInvalidQueryFromDiagnostics(Diag);
|
return makeInvalidQueryFromDiagnostics(Diag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,7 +228,7 @@ QueryRef QueryParser::doParse() {
|
|||||||
|
|
||||||
Diagnostics Diag;
|
Diagnostics Diag;
|
||||||
Optional<DynTypedMatcher> Matcher = Parser::parseMatcherExpression(
|
Optional<DynTypedMatcher> Matcher = Parser::parseMatcherExpression(
|
||||||
StringRef(Begin, End - Begin), nullptr, &QS.NamedValues, &Diag);
|
StringRef(Begin, End - Begin), &S, &Diag);
|
||||||
if (!Matcher) {
|
if (!Matcher) {
|
||||||
return makeInvalidQueryFromDiagnostics(Diag);
|
return makeInvalidQueryFromDiagnostics(Diag);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
#include "QueryParser.h"
|
#include "QueryParser.h"
|
||||||
#include "QuerySession.h"
|
#include "QuerySession.h"
|
||||||
#include "clang/Frontend/ASTUnit.h"
|
#include "clang/Frontend/ASTUnit.h"
|
||||||
#include "clang/Tooling/CommonOptionsParser.h"
|
#include "clang/Tooling/CompilationDatabase.h"
|
||||||
#include "clang/Tooling/Tooling.h"
|
#include "clang/Tooling/Tooling.h"
|
||||||
#include "llvm/LineEditor/LineEditor.h"
|
#include "llvm/LineEditor/LineEditor.h"
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
@@ -46,30 +46,45 @@ using namespace clang::query;
|
|||||||
using namespace clang::tooling;
|
using namespace clang::tooling;
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
|
static cl::opt<std::string> BuildPath("b", cl::desc("Specify build path"),
|
||||||
static cl::OptionCategory ClangQueryCategory("clang-query options");
|
cl::value_desc("<path>"));
|
||||||
|
|
||||||
static cl::list<std::string> Commands("c", cl::desc("Specify command to run"),
|
static cl::list<std::string> Commands("c", cl::desc("Specify command to run"),
|
||||||
cl::value_desc("command"),
|
cl::value_desc("<command>"));
|
||||||
cl::cat(ClangQueryCategory));
|
|
||||||
|
|
||||||
static cl::list<std::string> CommandFiles("f",
|
static cl::list<std::string> CommandFiles("f",
|
||||||
cl::desc("Read commands from file"),
|
cl::desc("Read commands from file"),
|
||||||
cl::value_desc("file"),
|
cl::value_desc("<file>"));
|
||||||
cl::cat(ClangQueryCategory));
|
|
||||||
|
static cl::list<std::string> SourcePaths(cl::Positional,
|
||||||
|
cl::desc("<source0> [... <sourceN>]"),
|
||||||
|
cl::OneOrMore);
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
int main(int argc, const char **argv) {
|
||||||
llvm::sys::PrintStackTraceOnErrorSignal();
|
llvm::sys::PrintStackTraceOnErrorSignal();
|
||||||
|
cl::ParseCommandLineOptions(argc, argv);
|
||||||
CommonOptionsParser OptionsParser(argc, argv, ClangQueryCategory);
|
|
||||||
|
|
||||||
if (!Commands.empty() && !CommandFiles.empty()) {
|
if (!Commands.empty() && !CommandFiles.empty()) {
|
||||||
llvm::errs() << argv[0] << ": cannot specify both -c and -f\n";
|
llvm::errs() << argv[0] << ": cannot specify both -c and -f\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClangTool Tool(OptionsParser.getCompilations(),
|
std::unique_ptr<CompilationDatabase> Compilations(
|
||||||
OptionsParser.getSourcePathList());
|
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;
|
std::vector<std::unique_ptr<ASTUnit>> ASTs;
|
||||||
if (Tool.buildASTs(ASTs) != 0)
|
if (Tool.buildASTs(ASTs) != 0)
|
||||||
return 1;
|
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(llvm)
|
||||||
add_subdirectory(google)
|
add_subdirectory(google)
|
||||||
add_subdirectory(misc)
|
add_subdirectory(misc)
|
||||||
add_subdirectory(utils)
|
|
||||||
|
|||||||
@@ -179,10 +179,10 @@ private:
|
|||||||
|
|
||||||
class ClangTidyASTConsumer : public MultiplexConsumer {
|
class ClangTidyASTConsumer : public MultiplexConsumer {
|
||||||
public:
|
public:
|
||||||
ClangTidyASTConsumer(std::vector<std::unique_ptr<ASTConsumer>> Consumers,
|
ClangTidyASTConsumer(const SmallVectorImpl<ASTConsumer *> &Consumers,
|
||||||
std::unique_ptr<ast_matchers::MatchFinder> Finder,
|
std::unique_ptr<ast_matchers::MatchFinder> Finder,
|
||||||
std::vector<std::unique_ptr<ClangTidyCheck>> Checks)
|
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)) {}
|
Checks(std::move(Checks)) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -203,8 +203,8 @@ ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<clang::ASTConsumer>
|
|
||||||
ClangTidyASTConsumerFactory::CreateASTConsumer(
|
clang::ASTConsumer *ClangTidyASTConsumerFactory::CreateASTConsumer(
|
||||||
clang::CompilerInstance &Compiler, StringRef File) {
|
clang::CompilerInstance &Compiler, StringRef File) {
|
||||||
// FIXME: Move this to a separate method, so that CreateASTConsumer doesn't
|
// FIXME: Move this to a separate method, so that CreateASTConsumer doesn't
|
||||||
// modify Compiler.
|
// modify Compiler.
|
||||||
@@ -213,7 +213,7 @@ ClangTidyASTConsumerFactory::CreateASTConsumer(
|
|||||||
Context.setASTContext(&Compiler.getASTContext());
|
Context.setASTContext(&Compiler.getASTContext());
|
||||||
|
|
||||||
std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
|
std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
|
||||||
GlobList &Filter = Context.getChecksFilter();
|
ChecksFilter &Filter = Context.getChecksFilter();
|
||||||
CheckFactories->createChecks(Filter, Checks);
|
CheckFactories->createChecks(Filter, Checks);
|
||||||
|
|
||||||
std::unique_ptr<ast_matchers::MatchFinder> Finder(
|
std::unique_ptr<ast_matchers::MatchFinder> Finder(
|
||||||
@@ -224,7 +224,7 @@ ClangTidyASTConsumerFactory::CreateASTConsumer(
|
|||||||
Check->registerPPCallbacks(Compiler);
|
Check->registerPPCallbacks(Compiler);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<ASTConsumer>> Consumers;
|
SmallVector<ASTConsumer *, 2> Consumers;
|
||||||
if (!Checks.empty())
|
if (!Checks.empty())
|
||||||
Consumers.push_back(Finder->newASTConsumer());
|
Consumers.push_back(Finder->newASTConsumer());
|
||||||
|
|
||||||
@@ -240,23 +240,22 @@ ClangTidyASTConsumerFactory::CreateASTConsumer(
|
|||||||
AnalyzerOptions->AnalysisDiagOpt = PD_NONE;
|
AnalyzerOptions->AnalysisDiagOpt = PD_NONE;
|
||||||
AnalyzerOptions->AnalyzeNestedBlocks = true;
|
AnalyzerOptions->AnalyzeNestedBlocks = true;
|
||||||
AnalyzerOptions->eagerlyAssumeBinOpBifurcation = true;
|
AnalyzerOptions->eagerlyAssumeBinOpBifurcation = true;
|
||||||
std::unique_ptr<ento::AnalysisASTConsumer> AnalysisConsumer =
|
ento::AnalysisASTConsumer *AnalysisConsumer = ento::CreateAnalysisConsumer(
|
||||||
ento::CreateAnalysisConsumer(
|
|
||||||
Compiler.getPreprocessor(), Compiler.getFrontendOpts().OutputFile,
|
Compiler.getPreprocessor(), Compiler.getFrontendOpts().OutputFile,
|
||||||
AnalyzerOptions, Compiler.getFrontendOpts().Plugins);
|
AnalyzerOptions, Compiler.getFrontendOpts().Plugins);
|
||||||
AnalysisConsumer->AddDiagnosticConsumer(
|
AnalysisConsumer->AddDiagnosticConsumer(
|
||||||
new AnalyzerDiagnosticConsumer(Context));
|
new AnalyzerDiagnosticConsumer(Context));
|
||||||
Consumers.push_back(std::move(AnalysisConsumer));
|
Consumers.push_back(AnalysisConsumer);
|
||||||
}
|
}
|
||||||
return llvm::make_unique<ClangTidyASTConsumer>(
|
return new ClangTidyASTConsumer(Consumers, std::move(Finder),
|
||||||
std::move(Consumers), std::move(Finder), std::move(Checks));
|
std::move(Checks));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
ClangTidyASTConsumerFactory::getCheckNames(GlobList &Filter) {
|
ClangTidyASTConsumerFactory::getCheckNames(ChecksFilter &Filter) {
|
||||||
std::vector<std::string> CheckNames;
|
std::vector<std::string> CheckNames;
|
||||||
for (const auto &CheckFactory : *CheckFactories) {
|
for (const auto &CheckFactory : *CheckFactories) {
|
||||||
if (Filter.contains(CheckFactory.first))
|
if (Filter.isCheckEnabled(CheckFactory.first))
|
||||||
CheckNames.push_back(CheckFactory.first);
|
CheckNames.push_back(CheckFactory.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,7 +267,7 @@ ClangTidyASTConsumerFactory::getCheckNames(GlobList &Filter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClangTidyASTConsumerFactory::CheckersList
|
ClangTidyASTConsumerFactory::CheckersList
|
||||||
ClangTidyASTConsumerFactory::getCheckersControlList(GlobList &Filter) {
|
ClangTidyASTConsumerFactory::getCheckersControlList(ChecksFilter &Filter) {
|
||||||
CheckersList List;
|
CheckersList List;
|
||||||
|
|
||||||
bool AnalyzerChecksEnabled = false;
|
bool AnalyzerChecksEnabled = false;
|
||||||
@@ -276,7 +275,7 @@ ClangTidyASTConsumerFactory::getCheckersControlList(GlobList &Filter) {
|
|||||||
std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
|
std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
|
||||||
AnalyzerChecksEnabled =
|
AnalyzerChecksEnabled =
|
||||||
AnalyzerChecksEnabled ||
|
AnalyzerChecksEnabled ||
|
||||||
(!CheckName.startswith("debug") && Filter.contains(Checker));
|
(!CheckName.startswith("debug") && Filter.isCheckEnabled(Checker));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AnalyzerChecksEnabled) {
|
if (AnalyzerChecksEnabled) {
|
||||||
@@ -291,7 +290,7 @@ ClangTidyASTConsumerFactory::getCheckersControlList(GlobList &Filter) {
|
|||||||
std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
|
std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
|
||||||
|
|
||||||
if (CheckName.startswith("core") ||
|
if (CheckName.startswith("core") ||
|
||||||
(!CheckName.startswith("debug") && Filter.contains(Checker)))
|
(!CheckName.startswith("debug") && Filter.isCheckEnabled(Checker)))
|
||||||
List.push_back(std::make_pair(CheckName, true));
|
List.push_back(std::make_pair(CheckName, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -332,14 +331,15 @@ ClangTidyStats runClangTidy(ClangTidyOptionsProvider *OptionsProvider,
|
|||||||
|
|
||||||
class ActionFactory : public FrontendActionFactory {
|
class ActionFactory : public FrontendActionFactory {
|
||||||
public:
|
public:
|
||||||
ActionFactory(ClangTidyContext &Context) : ConsumerFactory(Context) {}
|
ActionFactory(ClangTidyASTConsumerFactory *ConsumerFactory)
|
||||||
FrontendAction *create() override { return new Action(&ConsumerFactory); }
|
: ConsumerFactory(ConsumerFactory) {}
|
||||||
|
FrontendAction *create() override { return new Action(ConsumerFactory); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Action : public ASTFrontendAction {
|
class Action : public ASTFrontendAction {
|
||||||
public:
|
public:
|
||||||
Action(ClangTidyASTConsumerFactory *Factory) : Factory(Factory) {}
|
Action(ClangTidyASTConsumerFactory *Factory) : Factory(Factory) {}
|
||||||
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
|
ASTConsumer *CreateASTConsumer(CompilerInstance &Compiler,
|
||||||
StringRef File) override {
|
StringRef File) override {
|
||||||
return Factory->CreateASTConsumer(Compiler, File);
|
return Factory->CreateASTConsumer(Compiler, File);
|
||||||
}
|
}
|
||||||
@@ -348,11 +348,10 @@ ClangTidyStats runClangTidy(ClangTidyOptionsProvider *OptionsProvider,
|
|||||||
ClangTidyASTConsumerFactory *Factory;
|
ClangTidyASTConsumerFactory *Factory;
|
||||||
};
|
};
|
||||||
|
|
||||||
ClangTidyASTConsumerFactory ConsumerFactory;
|
ClangTidyASTConsumerFactory *ConsumerFactory;
|
||||||
};
|
};
|
||||||
|
|
||||||
ActionFactory Factory(Context);
|
Tool.run(new ActionFactory(new ClangTidyASTConsumerFactory(Context)));
|
||||||
Tool.run(&Factory);
|
|
||||||
*Errors = Context.getErrors();
|
*Errors = Context.getErrors();
|
||||||
return Context.getStats();
|
return Context.getStats();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,15 +99,15 @@ public:
|
|||||||
ClangTidyASTConsumerFactory(ClangTidyContext &Context);
|
ClangTidyASTConsumerFactory(ClangTidyContext &Context);
|
||||||
|
|
||||||
/// \brief Returns an ASTConsumer that runs the specified clang-tidy checks.
|
/// \brief Returns an ASTConsumer that runs the specified clang-tidy checks.
|
||||||
std::unique_ptr<clang::ASTConsumer>
|
clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &Compiler,
|
||||||
CreateASTConsumer(clang::CompilerInstance &Compiler, StringRef File);
|
StringRef File);
|
||||||
|
|
||||||
/// \brief Get the list of enabled checks.
|
/// \brief Get the list of enabled checks.
|
||||||
std::vector<std::string> getCheckNames(GlobList &Filter);
|
std::vector<std::string> getCheckNames(ChecksFilter &Filter);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::vector<std::pair<std::string, bool> > CheckersList;
|
typedef std::vector<std::pair<std::string, bool> > CheckersList;
|
||||||
CheckersList getCheckersControlList(GlobList &Filter);
|
CheckersList getCheckersControlList(ChecksFilter &Filter);
|
||||||
|
|
||||||
ClangTidyContext &Context;
|
ClangTidyContext &Context;
|
||||||
std::unique_ptr<ClangTidyCheckFactories> CheckFactories;
|
std::unique_ptr<ClangTidyCheckFactories> CheckFactories;
|
||||||
|
|||||||
@@ -146,18 +146,18 @@ static llvm::Regex ConsumeGlob(StringRef &GlobList) {
|
|||||||
return llvm::Regex(RegexText);
|
return llvm::Regex(RegexText);
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobList::GlobList(StringRef Globs)
|
ChecksFilter::ChecksFilter(StringRef GlobList)
|
||||||
: Positive(!ConsumeNegativeIndicator(Globs)),
|
: Positive(!ConsumeNegativeIndicator(GlobList)),
|
||||||
Regex(ConsumeGlob(Globs)),
|
Regex(ConsumeGlob(GlobList)),
|
||||||
NextGlob(Globs.empty() ? nullptr : new GlobList(Globs)) {}
|
NextFilter(GlobList.empty() ? nullptr : new ChecksFilter(GlobList)) {}
|
||||||
|
|
||||||
bool GlobList::contains(StringRef S, bool Contains) {
|
bool ChecksFilter::isCheckEnabled(StringRef Name, bool Enabled) {
|
||||||
if (Regex.match(S))
|
if (Regex.match(Name))
|
||||||
Contains = Positive;
|
Enabled = Positive;
|
||||||
|
|
||||||
if (NextGlob)
|
if (NextFilter)
|
||||||
Contains = NextGlob->contains(S, Contains);
|
Enabled = NextFilter->isCheckEnabled(Name, Enabled);
|
||||||
return Contains;
|
return Enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClangTidyContext::ClangTidyContext(ClangTidyOptionsProvider *OptionsProvider)
|
ClangTidyContext::ClangTidyContext(ClangTidyOptionsProvider *OptionsProvider)
|
||||||
@@ -202,7 +202,7 @@ void ClangTidyContext::setSourceManager(SourceManager *SourceMgr) {
|
|||||||
|
|
||||||
void ClangTidyContext::setCurrentFile(StringRef File) {
|
void ClangTidyContext::setCurrentFile(StringRef File) {
|
||||||
CurrentFile = File;
|
CurrentFile = File;
|
||||||
CheckFilter.reset(new GlobList(getOptions().Checks));
|
CheckFilter.reset(new ChecksFilter(getOptions().Checks));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangTidyContext::setASTContext(ASTContext *Context) {
|
void ClangTidyContext::setASTContext(ASTContext *Context) {
|
||||||
@@ -217,7 +217,7 @@ const ClangTidyOptions &ClangTidyContext::getOptions() const {
|
|||||||
return OptionsProvider->getOptions(CurrentFile);
|
return OptionsProvider->getOptions(CurrentFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobList &ClangTidyContext::getChecksFilter() {
|
ChecksFilter &ClangTidyContext::getChecksFilter() {
|
||||||
assert(CheckFilter != nullptr);
|
assert(CheckFilter != nullptr);
|
||||||
return *CheckFilter;
|
return *CheckFilter;
|
||||||
}
|
}
|
||||||
@@ -248,7 +248,7 @@ ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx)
|
|||||||
void ClangTidyDiagnosticConsumer::finalizeLastError() {
|
void ClangTidyDiagnosticConsumer::finalizeLastError() {
|
||||||
if (!Errors.empty()) {
|
if (!Errors.empty()) {
|
||||||
ClangTidyError &Error = Errors.back();
|
ClangTidyError &Error = Errors.back();
|
||||||
if (!Context.getChecksFilter().contains(Error.CheckName) &&
|
if (!Context.getChecksFilter().isCheckEnabled(Error.CheckName) &&
|
||||||
Error.DiagLevel != ClangTidyError::Error) {
|
Error.DiagLevel != ClangTidyError::Error) {
|
||||||
++Context.Stats.ErrorsIgnoredCheckFilter;
|
++Context.Stats.ErrorsIgnoredCheckFilter;
|
||||||
Errors.pop_back();
|
Errors.pop_back();
|
||||||
|
|||||||
@@ -65,25 +65,24 @@ struct ClangTidyError {
|
|||||||
Level DiagLevel;
|
Level DiagLevel;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Read-only set of strings represented as a list of positive and
|
/// \brief Filters checks by name.
|
||||||
/// negative globs. Positive globs add all matched strings to the set, negative
|
class ChecksFilter {
|
||||||
/// globs remove them in the order of appearance in the list.
|
|
||||||
class GlobList {
|
|
||||||
public:
|
public:
|
||||||
/// \brief \p GlobList is a comma-separated list of globs (only '*'
|
/// \brief \p GlobList is a comma-separated list of globs (only '*'
|
||||||
/// metacharacter is supported) with optional '-' prefix to denote exclusion.
|
/// 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
|
/// \brief Returns \c true if the check with the specified \p Name should be
|
||||||
/// matching glob's Positive flag.
|
/// enabled. The result is the last matching glob's Positive flag. If \p Name
|
||||||
bool contains(StringRef S) { return contains(S, false); }
|
/// is not matched by any globs, the check is not enabled.
|
||||||
|
bool isCheckEnabled(StringRef Name) { return isCheckEnabled(Name, false); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool contains(StringRef S, bool Contains);
|
bool isCheckEnabled(StringRef Name, bool Enabled);
|
||||||
|
|
||||||
bool Positive;
|
bool Positive;
|
||||||
llvm::Regex Regex;
|
llvm::Regex Regex;
|
||||||
std::unique_ptr<GlobList> NextGlob;
|
std::unique_ptr<ChecksFilter> NextFilter;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Contains displayed and ignored diagnostic counters for a ClangTidy
|
/// \brief Contains displayed and ignored diagnostic counters for a ClangTidy
|
||||||
@@ -146,7 +145,7 @@ public:
|
|||||||
StringRef getCheckName(unsigned DiagnosticID) const;
|
StringRef getCheckName(unsigned DiagnosticID) const;
|
||||||
|
|
||||||
/// \brief Returns check filter for the \c CurrentFile.
|
/// \brief Returns check filter for the \c CurrentFile.
|
||||||
GlobList &getChecksFilter();
|
ChecksFilter &getChecksFilter();
|
||||||
|
|
||||||
/// \brief Returns global options.
|
/// \brief Returns global options.
|
||||||
const ClangTidyGlobalOptions &getGlobalOptions() const;
|
const ClangTidyGlobalOptions &getGlobalOptions() const;
|
||||||
@@ -180,7 +179,7 @@ private:
|
|||||||
std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
|
std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
|
||||||
|
|
||||||
std::string CurrentFile;
|
std::string CurrentFile;
|
||||||
std::unique_ptr<GlobList> CheckFilter;
|
std::unique_ptr<ChecksFilter> CheckFilter;
|
||||||
|
|
||||||
ClangTidyStats Stats;
|
ClangTidyStats Stats;
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,10 @@ void ClangTidyCheckFactories::addCheckFactory(StringRef Name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ClangTidyCheckFactories::createChecks(
|
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) {
|
for (const auto &Factory : Factories) {
|
||||||
if (Filter.contains(Factory.first)) {
|
if (Filter.isCheckEnabled(Factory.first)) {
|
||||||
ClangTidyCheck *Check = Factory.second->createCheck();
|
ClangTidyCheck *Check = Factory.second->createCheck();
|
||||||
Check->setName(Factory.first);
|
Check->setName(Factory.first);
|
||||||
Checks.emplace_back(Check);
|
Checks.emplace_back(Check);
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ public:
|
|||||||
/// store them in \p Checks.
|
/// store them in \p Checks.
|
||||||
///
|
///
|
||||||
/// The caller takes ownership of the return \c ClangTidyChecks.
|
/// The caller takes ownership of the return \c ClangTidyChecks.
|
||||||
void createChecks(GlobList &Filter,
|
void createChecks(ChecksFilter &Filter,
|
||||||
std::vector<std::unique_ptr<ClangTidyCheck>> &Checks);
|
std::vector<std::unique_ptr<ClangTidyCheck>> &Checks);
|
||||||
|
|
||||||
typedef std::map<std::string, CheckFactoryBase *> FactoryMap;
|
typedef std::map<std::string, CheckFactoryBase *> FactoryMap;
|
||||||
|
|||||||
@@ -11,6 +11,6 @@ CLANG_LEVEL := ../../..
|
|||||||
LIBRARYNAME := clangTidy
|
LIBRARYNAME := clangTidy
|
||||||
include $(CLANG_LEVEL)/../../Makefile.config
|
include $(CLANG_LEVEL)/../../Makefile.config
|
||||||
|
|
||||||
DIRS = utils llvm google misc tool
|
DIRS = llvm google misc tool
|
||||||
|
|
||||||
include $(CLANG_LEVEL)/Makefile
|
include $(CLANG_LEVEL)/Makefile
|
||||||
|
|||||||
@@ -60,12 +60,6 @@ bool pointedTypesAreEqual(QualType SourceType, QualType DestType) {
|
|||||||
void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
|
void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
|
||||||
const auto *CastExpr = Result.Nodes.getNodeAs<CStyleCastExpr>("cast");
|
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
|
// Casting to void is an idiomatic way to mute "unused variable" and similar
|
||||||
// warnings.
|
// warnings.
|
||||||
if (CastExpr->getTypeAsWritten()->isVoidType())
|
if (CastExpr->getTypeAsWritten()->isVoidType())
|
||||||
@@ -75,6 +69,8 @@ void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
|
|||||||
CastExpr->getSubExprAsWritten()->getType().getCanonicalType();
|
CastExpr->getSubExprAsWritten()->getType().getCanonicalType();
|
||||||
QualType DestType = CastExpr->getTypeAsWritten().getCanonicalType();
|
QualType DestType = CastExpr->getTypeAsWritten().getCanonicalType();
|
||||||
|
|
||||||
|
auto ParenRange = CharSourceRange::getTokenRange(CastExpr->getLParenLoc(),
|
||||||
|
CastExpr->getRParenLoc());
|
||||||
if (SourceType == DestType) {
|
if (SourceType == DestType) {
|
||||||
diag(CastExpr->getLocStart(), "Redundant cast to the same type.")
|
diag(CastExpr->getLocStart(), "Redundant cast to the same type.")
|
||||||
<< FixItHint::CreateRemoval(ParenRange);
|
<< FixItHint::CreateRemoval(ParenRange);
|
||||||
@@ -88,6 +84,8 @@ void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
|
|||||||
|
|
||||||
auto ReplaceWithCast = [&](StringRef CastType) {
|
auto ReplaceWithCast = [&](StringRef CastType) {
|
||||||
diag_builder << ("Use " + CastType + ".").str();
|
diag_builder << ("Use " + CastType + ".").str();
|
||||||
|
if (ParenRange.getBegin().isMacroID() || ParenRange.getEnd().isMacroID())
|
||||||
|
return;
|
||||||
|
|
||||||
const Expr *SubExpr = CastExpr->getSubExprAsWritten()->IgnoreImpCasts();
|
const Expr *SubExpr = CastExpr->getSubExprAsWritten()->IgnoreImpCasts();
|
||||||
std::string CastText = (CastType + "<" + DestTypeString + ">").str();
|
std::string CastText = (CastType + "<" + DestTypeString + ">").str();
|
||||||
|
|||||||
@@ -20,6 +20,15 @@ namespace ast_matchers {
|
|||||||
AST_MATCHER(DeclRefExpr, hasExplicitTemplateArgs) {
|
AST_MATCHER(DeclRefExpr, hasExplicitTemplateArgs) {
|
||||||
return Node.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 ast_matchers
|
||||||
|
|
||||||
namespace tidy {
|
namespace tidy {
|
||||||
@@ -33,10 +42,10 @@ ExplicitMakePairCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
|
|||||||
callExpr(unless(hasAncestor(decl(anyOf(
|
callExpr(unless(hasAncestor(decl(anyOf(
|
||||||
recordDecl(ast_matchers::isTemplateInstantiation()),
|
recordDecl(ast_matchers::isTemplateInstantiation()),
|
||||||
functionDecl(ast_matchers::isTemplateInstantiation()))))),
|
functionDecl(ast_matchers::isTemplateInstantiation()))))),
|
||||||
callee(expr(ignoringParenImpCasts(
|
calleeIgnoringParenImpCasts(
|
||||||
declRefExpr(hasExplicitTemplateArgs(),
|
declRefExpr(hasExplicitTemplateArgs(),
|
||||||
to(functionDecl(hasName("::std::make_pair"))))
|
to(functionDecl(hasName("::std::make_pair"))))
|
||||||
.bind("declref"))))).bind("call"),
|
.bind("declref"))).bind("call"),
|
||||||
this);
|
this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,14 +37,6 @@ void NamedParameterCheck::check(const MatchFinder::MatchResult &Result) {
|
|||||||
if (Function->isImplicit())
|
if (Function->isImplicit())
|
||||||
return;
|
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: Handle overloads.
|
||||||
// TODO: We could check that all redeclarations use the same name for
|
// TODO: We could check that all redeclarations use the same name for
|
||||||
// arguments in the same position.
|
// arguments in the same position.
|
||||||
@@ -78,34 +70,25 @@ void NamedParameterCheck::check(const MatchFinder::MatchResult &Result) {
|
|||||||
"all parameters should be named in a function");
|
"all parameters should be named in a function");
|
||||||
|
|
||||||
for (auto P : UnnamedParams) {
|
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
|
// If the method is overridden, try to copy the name from the base method
|
||||||
// into the overrider.
|
// into the overrider.
|
||||||
|
const ParmVarDecl *Parm = P.first->getParamDecl(P.second);
|
||||||
const auto *M = dyn_cast<CXXMethodDecl>(P.first);
|
const auto *M = dyn_cast<CXXMethodDecl>(P.first);
|
||||||
if (M && M->size_overridden_methods() > 0) {
|
if (M && M->size_overridden_methods() > 0) {
|
||||||
const ParmVarDecl *OtherParm =
|
const ParmVarDecl *OtherParm =
|
||||||
(*M->begin_overridden_methods())->getParamDecl(P.second);
|
(*M->begin_overridden_methods())->getParamDecl(P.second);
|
||||||
StringRef Name = OtherParm->getName();
|
std::string Name = OtherParm->getNameAsString();
|
||||||
if (!Name.empty())
|
if (!Name.empty()) {
|
||||||
NewName = Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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(),
|
D << FixItHint::CreateInsertion(Parm->getLocation(),
|
||||||
" /*" + NewName.str() + "*/");
|
" /*" + Name + "*/");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
set(LLVM_LINK_COMPONENTS support)
|
||||||
|
|
||||||
add_clang_library(clangTidyLLVMModule
|
add_clang_library(clangTidyLLVMModule
|
||||||
HeaderGuardCheck.cpp
|
|
||||||
IncludeOrderCheck.cpp
|
IncludeOrderCheck.cpp
|
||||||
LLVMTidyModule.cpp
|
LLVMTidyModule.cpp
|
||||||
NamespaceCommentCheck.cpp
|
NamespaceCommentCheck.cpp
|
||||||
@@ -13,6 +12,4 @@ add_clang_library(clangTidyLLVMModule
|
|||||||
clangBasic
|
clangBasic
|
||||||
clangLex
|
clangLex
|
||||||
clangTidy
|
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 {
|
namespace {
|
||||||
class IncludeOrderPPCallbacks : public PPCallbacks {
|
class IncludeOrderPPCallbacks : public PPCallbacks {
|
||||||
public:
|
public:
|
||||||
explicit IncludeOrderPPCallbacks(ClangTidyCheck &Check, SourceManager &SM)
|
explicit IncludeOrderPPCallbacks(IncludeOrderCheck &Check) : Check(Check) {}
|
||||||
: LookForMainModule(true), Check(Check), SM(SM) {}
|
|
||||||
|
|
||||||
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
|
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
|
||||||
StringRef FileName, bool IsAngled,
|
StringRef FileName, bool IsAngled,
|
||||||
CharSourceRange FilenameRange, const FileEntry *File,
|
CharSourceRange FilenameRange, const FileEntry *File,
|
||||||
StringRef SearchPath, StringRef RelativePath,
|
StringRef SearchPath, StringRef RelativePath,
|
||||||
const Module *Imported) override;
|
const Module *Imported) override {
|
||||||
void EndOfMainFile() 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:
|
private:
|
||||||
struct IncludeDirective {
|
IncludeOrderCheck &Check;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void IncludeOrderCheck::registerPPCallbacks(CompilerInstance &Compiler) {
|
void IncludeOrderCheck::registerPPCallbacks(CompilerInstance &Compiler) {
|
||||||
Compiler.getPreprocessor().addPPCallbacks(
|
Compiler.getPreprocessor()
|
||||||
new IncludeOrderPPCallbacks(*this, Compiler.getSourceManager()));
|
.addPPCallbacks(new IncludeOrderPPCallbacks(*this));
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace tidy
|
} // namespace tidy
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#include "../ClangTidy.h"
|
#include "../ClangTidy.h"
|
||||||
#include "../ClangTidyModule.h"
|
#include "../ClangTidyModule.h"
|
||||||
#include "../ClangTidyModuleRegistry.h"
|
#include "../ClangTidyModuleRegistry.h"
|
||||||
#include "HeaderGuardCheck.h"
|
|
||||||
#include "IncludeOrderCheck.h"
|
#include "IncludeOrderCheck.h"
|
||||||
#include "NamespaceCommentCheck.h"
|
#include "NamespaceCommentCheck.h"
|
||||||
#include "TwineLocalCheck.h"
|
#include "TwineLocalCheck.h"
|
||||||
@@ -21,8 +20,6 @@ namespace tidy {
|
|||||||
class LLVMModule : public ClangTidyModule {
|
class LLVMModule : public ClangTidyModule {
|
||||||
public:
|
public:
|
||||||
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
|
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
|
||||||
CheckFactories.addCheckFactory(
|
|
||||||
"llvm-header-guard", new ClangTidyCheckFactory<LLVMHeaderGuardCheck>());
|
|
||||||
CheckFactories.addCheckFactory(
|
CheckFactories.addCheckFactory(
|
||||||
"llvm-include-order", new ClangTidyCheckFactory<IncludeOrderCheck>());
|
"llvm-include-order", new ClangTidyCheckFactory<IncludeOrderCheck>());
|
||||||
CheckFactories.addCheckFactory(
|
CheckFactories.addCheckFactory(
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "ArgumentCommentCheck.h"
|
#include "ArgumentCommentCheck.h"
|
||||||
|
#include "../ClangTidy.h"
|
||||||
|
#include "../ClangTidyModule.h"
|
||||||
|
#include "../ClangTidyModuleRegistry.h"
|
||||||
#include "clang/AST/ASTContext.h"
|
#include "clang/AST/ASTContext.h"
|
||||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||||
#include "clang/Lex/Lexer.h"
|
#include "clang/Lex/Lexer.h"
|
||||||
@@ -22,15 +25,7 @@ ArgumentCommentCheck::ArgumentCommentCheck()
|
|||||||
: IdentRE("^(/\\* *)([_A-Za-z][_A-Za-z0-9]*)( *= *\\*/)$") {}
|
: IdentRE("^(/\\* *)([_A-Za-z][_A-Za-z0-9]*)( *= *\\*/)$") {}
|
||||||
|
|
||||||
void ArgumentCommentCheck::registerMatchers(MatchFinder *Finder) {
|
void ArgumentCommentCheck::registerMatchers(MatchFinder *Finder) {
|
||||||
Finder->addMatcher(
|
Finder->addMatcher(callExpr(unless(operatorCallExpr())).bind("expr"), this);
|
||||||
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(constructExpr().bind("expr"), this);
|
Finder->addMatcher(constructExpr().bind("expr"), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,10 +81,10 @@ ArgumentCommentCheck::isLikelyTypo(llvm::ArrayRef<ParmVarDecl *> Params,
|
|||||||
if (ThisED >= UpperBound)
|
if (ThisED >= UpperBound)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (unsigned I = 0, E = Params.size(); I != E; ++I) {
|
for (const auto &Param : Params) {
|
||||||
if (I == ArgIndex)
|
if (&Param - Params.begin() == ArgIndex)
|
||||||
continue;
|
continue;
|
||||||
IdentifierInfo *II = Params[I]->getIdentifier();
|
IdentifierInfo *II = Param->getIdentifier();
|
||||||
if (!II)
|
if (!II)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ AST_MATCHER(QualType, isBoolean) { return Node->isBooleanType(); }
|
|||||||
namespace tidy {
|
namespace tidy {
|
||||||
|
|
||||||
void BoolPointerImplicitConversion::registerMatchers(MatchFinder *Finder) {
|
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
|
// Look for ifs that have an implicit bool* to bool conversion in the
|
||||||
// condition. Filter negations.
|
// condition. Filter negations.
|
||||||
Finder->addMatcher(
|
Finder->addMatcher(
|
||||||
@@ -35,8 +32,7 @@ void BoolPointerImplicitConversion::registerMatchers(MatchFinder *Finder) {
|
|||||||
hasSourceExpression(expr(
|
hasSourceExpression(expr(
|
||||||
hasType(pointerType(pointee(isBoolean()))),
|
hasType(pointerType(pointee(isBoolean()))),
|
||||||
ignoringParenImpCasts(declRefExpr().bind("expr")))),
|
ignoringParenImpCasts(declRefExpr().bind("expr")))),
|
||||||
isPointerToBoolean())))),
|
isPointerToBoolean()))))).bind("if"),
|
||||||
unless(InTemplateInstantiation)).bind("if"),
|
|
||||||
this);
|
this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,10 +41,6 @@ BoolPointerImplicitConversion::check(const MatchFinder::MatchResult &Result) {
|
|||||||
auto *If = Result.Nodes.getStmtAs<IfStmt>("if");
|
auto *If = Result.Nodes.getStmtAs<IfStmt>("if");
|
||||||
auto *Var = Result.Nodes.getStmtAs<DeclRefExpr>("expr");
|
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.
|
// 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
|
// 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
|
// avoids false positives for checks of the pointer for nullptr before it is
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ add_clang_library(clangTidyMiscModule
|
|||||||
MiscTidyModule.cpp
|
MiscTidyModule.cpp
|
||||||
RedundantSmartptrGet.cpp
|
RedundantSmartptrGet.cpp
|
||||||
SwappedArgumentsCheck.cpp
|
SwappedArgumentsCheck.cpp
|
||||||
UndelegatedConstructor.cpp
|
|
||||||
UnusedRAII.cpp
|
|
||||||
UseOverride.cpp
|
UseOverride.cpp
|
||||||
|
|
||||||
LINK_LIBS
|
LINK_LIBS
|
||||||
|
|||||||
@@ -14,8 +14,6 @@
|
|||||||
#include "BoolPointerImplicitConversion.h"
|
#include "BoolPointerImplicitConversion.h"
|
||||||
#include "RedundantSmartptrGet.h"
|
#include "RedundantSmartptrGet.h"
|
||||||
#include "SwappedArgumentsCheck.h"
|
#include "SwappedArgumentsCheck.h"
|
||||||
#include "UndelegatedConstructor.h"
|
|
||||||
#include "UnusedRAII.h"
|
|
||||||
#include "UseOverride.h"
|
#include "UseOverride.h"
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
@@ -36,12 +34,6 @@ public:
|
|||||||
CheckFactories.addCheckFactory(
|
CheckFactories.addCheckFactory(
|
||||||
"misc-swapped-arguments",
|
"misc-swapped-arguments",
|
||||||
new ClangTidyCheckFactory<SwappedArgumentsCheck>());
|
new ClangTidyCheckFactory<SwappedArgumentsCheck>());
|
||||||
CheckFactories.addCheckFactory(
|
|
||||||
"misc-undelegated-constructor",
|
|
||||||
new ClangTidyCheckFactory<UndelegatedConstructorCheck>());
|
|
||||||
CheckFactories.addCheckFactory(
|
|
||||||
"misc-unused-raii",
|
|
||||||
new ClangTidyCheckFactory<UnusedRAIICheck>());
|
|
||||||
CheckFactories.addCheckFactory(
|
CheckFactories.addCheckFactory(
|
||||||
"misc-use-override",
|
"misc-use-override",
|
||||||
new ClangTidyCheckFactory<UseOverride>());
|
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(
|
DiagnosticBuilder Diag = diag(
|
||||||
Method->getLocation(),
|
Method->getLocation(),
|
||||||
OnlyVirtualSpecified
|
OnlyVirtualSpecified
|
||||||
? "Prefer using 'override' or (rarely) 'final' instead of 'virtual'"
|
? "Prefer using 'override' or 'final' instead of 'virtual'"
|
||||||
: "Annotate this function with 'override' or (rarely) 'final'");
|
: "Use exactly one of 'virtual', 'override' or (rarely) 'final'");
|
||||||
|
|
||||||
CharSourceRange FileRange = Lexer::makeFileCharRange(
|
CharSourceRange FileRange = Lexer::makeFileCharRange(
|
||||||
CharSourceRange::getTokenRange(Method->getSourceRange()), Sources,
|
CharSourceRange::getTokenRange(Method->getSourceRange()), Sources,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ TOOL_NO_EXPORTS = 1
|
|||||||
include $(CLANG_LEVEL)/../../Makefile.config
|
include $(CLANG_LEVEL)/../../Makefile.config
|
||||||
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
|
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
|
||||||
USEDLIBS = clangTidy.a clangTidyLLVMModule.a clangTidyGoogleModule.a \
|
USEDLIBS = clangTidy.a clangTidyLLVMModule.a clangTidyGoogleModule.a \
|
||||||
clangTidyMiscModule.a clangTidyUtils.a \
|
clangTidyMiscModule.a \
|
||||||
clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
|
clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
|
||||||
clangStaticAnalyzerCore.a \
|
clangStaticAnalyzerCore.a \
|
||||||
clangFormat.a clangASTMatchers.a clangTooling.a clangFrontend.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) {}
|
HadErrors(HadErrors) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<clang::ASTConsumer>
|
virtual clang::ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
|
||||||
CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
|
StringRef InFile) {
|
||||||
return llvm::make_unique<CollectEntitiesConsumer>(
|
return new CollectEntitiesConsumer(Entities, PPTracker,
|
||||||
Entities, PPTracker, CI.getPreprocessor(), InFile, HadErrors);
|
CI.getPreprocessor(), InFile, HadErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -736,8 +736,8 @@ int main(int Argc, const char **Argv) {
|
|||||||
ClangTool Tool(*Compilations, Headers);
|
ClangTool Tool(*Compilations, Headers);
|
||||||
Tool.appendArgumentsAdjuster(new AddDependenciesAdjuster(Dependencies));
|
Tool.appendArgumentsAdjuster(new AddDependenciesAdjuster(Dependencies));
|
||||||
int HadErrors = 0;
|
int HadErrors = 0;
|
||||||
ModularizeFrontendActionFactory Factory(Entities, *PPTracker, HadErrors);
|
HadErrors |= Tool.run(
|
||||||
HadErrors |= Tool.run(&Factory);
|
new ModularizeFrontendActionFactory(Entities, *PPTracker, HadErrors));
|
||||||
|
|
||||||
// Create a place to save duplicate entity locations, separate bins per kind.
|
// Create a place to save duplicate entity locations, separate bins per kind.
|
||||||
typedef SmallVector<Location, 8> LocationArray;
|
typedef SmallVector<Location, 8> LocationArray;
|
||||||
|
|||||||
@@ -178,10 +178,9 @@ public:
|
|||||||
ModuleMapCheckerAction(ModuleMapChecker &Checker) : Checker(Checker) {}
|
ModuleMapCheckerAction(ModuleMapChecker &Checker) : Checker(Checker) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
|
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
|
||||||
StringRef InFile) override {
|
StringRef InFile) {
|
||||||
return llvm::make_unique<ModuleMapCheckerConsumer>(Checker,
|
return new ModuleMapCheckerConsumer(Checker, CI.getPreprocessor());
|
||||||
CI.getPreprocessor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -120,10 +120,9 @@ public:
|
|||||||
: Ignore(Ignore), CallbackCalls(CallbackCalls) {}
|
: Ignore(Ignore), CallbackCalls(CallbackCalls) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<clang::ASTConsumer>
|
virtual clang::ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
|
||||||
CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
|
StringRef InFile) {
|
||||||
return llvm::make_unique<PPTraceConsumer>(Ignore, CallbackCalls,
|
return new PPTraceConsumer(Ignore, CallbackCalls, CI.getPreprocessor());
|
||||||
CI.getPreprocessor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -200,8 +199,8 @@ int main(int Argc, const char **Argv) {
|
|||||||
|
|
||||||
// Create the tool and run the compilation.
|
// Create the tool and run the compilation.
|
||||||
ClangTool Tool(*Compilations, SourcePaths);
|
ClangTool Tool(*Compilations, SourcePaths);
|
||||||
PPTraceFrontendActionFactory Factory(Ignore, CallbackCalls);
|
int HadErrors =
|
||||||
int HadErrors = Tool.run(&Factory);
|
Tool.run(new PPTraceFrontendActionFactory(Ignore, CallbackCalls));
|
||||||
|
|
||||||
// If we had errors, exit early.
|
// If we had errors, exit early.
|
||||||
if (HadErrors)
|
if (HadErrors)
|
||||||
|
|||||||
@@ -183,8 +183,8 @@ int main(int argc, const char **argv) {
|
|||||||
cl::ParseCommandLineOptions(argc, argv);
|
cl::ParseCommandLineOptions(argc, argv);
|
||||||
if (!Compilations) {
|
if (!Compilations) {
|
||||||
std::string ErrorMessage;
|
std::string ErrorMessage;
|
||||||
Compilations =
|
Compilations.reset(
|
||||||
CompilationDatabase::loadFromDirectory(BuildPath, ErrorMessage);
|
CompilationDatabase::loadFromDirectory(BuildPath, ErrorMessage));
|
||||||
if (!Compilations)
|
if (!Compilations)
|
||||||
llvm::report_fatal_error(ErrorMessage);
|
llvm::report_fatal_error(ErrorMessage);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ set(CLANG_TOOLS_TEST_DEPS
|
|||||||
# Individual tools we test.
|
# Individual tools we test.
|
||||||
clang-apply-replacements
|
clang-apply-replacements
|
||||||
clang-modernize
|
clang-modernize
|
||||||
clang-rename
|
|
||||||
clang-query
|
clang-query
|
||||||
clang-tidy
|
clang-tidy
|
||||||
modularize
|
modularize
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ lit.site.cfg: FORCE
|
|||||||
Unit/lit.site.cfg: FORCE
|
Unit/lit.site.cfg: FORCE
|
||||||
@echo "Making Unit/lit.site.cfg for Clang extra tools..."
|
@echo "Making Unit/lit.site.cfg for Clang extra tools..."
|
||||||
@$(MKDIR) $(dir $@)
|
@$(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=@CLANG_TOOLS_BINARY_DIR@=$(PROJ_OBJ_DIR)/..=g >> lit.tmp
|
||||||
@$(ECHOPATH) s=@TARGET_TRIPLE@=$(TARGET_TRIPLE)=g >> lit.tmp
|
@$(ECHOPATH) s=@TARGET_TRIPLE@=$(TARGET_TRIPLE)=g >> lit.tmp
|
||||||
@$(ECHOPATH) s=@CLANG_TOOLS_SOURCE_DIR@=$(PROJ_SRC_DIR)/..=g >> lit.tmp
|
@$(ECHOPATH) s=@CLANG_TOOLS_SOURCE_DIR@=$(PROJ_SRC_DIR)/..=g >> lit.tmp
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# -*- Python -*-
|
# -*- Python -*-
|
||||||
|
|
||||||
import platform
|
|
||||||
|
|
||||||
import lit.formats
|
import lit.formats
|
||||||
|
|
||||||
config.name = "Extra Tools Unit Tests"
|
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_source_root = extra_tools_obj_dir
|
||||||
config.test_exec_root = config.test_source_root
|
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
|
# 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
|
# a special value for GoogleTest indicating that it should look through the
|
||||||
# entire testsuite recursively for tests (alternatively, one could provide a
|
# entire testsuite recursively for tests (alternatively, one could provide a
|
||||||
@@ -31,24 +34,3 @@ if config.test_exec_root is None:
|
|||||||
raise SystemExit
|
raise SystemExit
|
||||||
|
|
||||||
# FIXME: Support out-of-tree builds? See clang/test/Unit/lit.cfg if we care.
|
# 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!
|
# Do not edit!
|
||||||
config.extra_tools_obj_dir = "@CLANG_TOOLS_BINARY_DIR@/unittests"
|
config.extra_tools_obj_dir = "@CLANG_TOOLS_BINARY_DIR@/unittests"
|
||||||
config.extra_tools_src_dir = "@CLANG_TOOLS_SOURCE_DIR@/unittests"
|
config.extra_tools_src_dir = "@CLANG_TOOLS_SOURCE_DIR@/unittests"
|
||||||
config.llvm_libs_dir = "@LLVM_LIBS_DIR@"
|
|
||||||
config.shlibdir = "@SHLIBDIR@"
|
config.shlibdir = "@SHLIBDIR@"
|
||||||
config.target_triple = "@TARGET_TRIPLE@"
|
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
|
// FIXME: clang-tidy should provide a -verify mode to make writing these checks
|
||||||
// easier and more accurate.
|
// easier and more accurate.
|
||||||
|
|
||||||
void ffff(int xxxx, int yyyy);
|
// CHECK-NOT: warning
|
||||||
|
|
||||||
void f(int x, int y);
|
void f(int x, int y);
|
||||||
|
|
||||||
|
void ffff(int xxxx, int yyyy);
|
||||||
|
|
||||||
void g() {
|
void g() {
|
||||||
// CHECK: [[@LINE+5]]:5: warning: argument name 'y' in comment does not match parameter name 'x'
|
// 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+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
|
// CHECK-NOT: warning
|
||||||
f(/*y=*/0, /*z=*/0);
|
f(/*y=*/0, /*z=*/0);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Closure {};
|
// CHECK-NOT: warning
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -105,6 +105,9 @@ void test_templates() {
|
|||||||
#define CAST(type, value) (type)(value)
|
#define CAST(type, value) (type)(value)
|
||||||
void macros(double d) {
|
void macros(double d) {
|
||||||
int i = CAST(int, 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 };
|
enum E { E1 = 1 };
|
||||||
|
|||||||
@@ -1,34 +1,24 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# Run clang-tidy in fix mode and verify the result.
|
# 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
|
INPUT_FILE=$1
|
||||||
CHECK_TO_RUN=$2
|
CHECK_TO_RUN=$2
|
||||||
TEMPORARY_FILE=$3.cpp
|
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.
|
# 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
|
# We need to keep the comments to preserve line numbers while avoiding empty
|
||||||
# lines which could potentially trigger formatting-related checks.
|
# 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}" \
|
clang-tidy ${TEMPORARY_FILE} -fix --checks="-*,${CHECK_TO_RUN}" -- --std=c++11 \
|
||||||
-- --std=c++11 $* > ${TEMPORARY_FILE}.msg 2>&1
|
> ${TEMPORARY_FILE}.msg 2>&1
|
||||||
|
|
||||||
FileCheck -input-file=${TEMPORARY_FILE} ${INPUT_FILE} \
|
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
|
if grep -q CHECK-MESSAGES ${INPUT_FILE}; then
|
||||||
FileCheck -input-file=${TEMPORARY_FILE}.msg ${INPUT_FILE} \
|
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
|
fi
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ struct A {
|
|||||||
// CHECK-NOT: warning
|
// CHECK-NOT: warning
|
||||||
struct B : public A {
|
struct B : public A {
|
||||||
void placeholder_for_f() {}
|
void placeholder_for_f() {}
|
||||||
// CHECK-SANITY: [[@LINE-1]]:8: warning: Annotate this
|
// CHECK-SANITY: [[@LINE-1]]:8: warning: Use exactly
|
||||||
// CHECK: [[@LINE-2]]:8: warning: Annotate this
|
// CHECK: [[@LINE-2]]:8: warning: Use exactly
|
||||||
void g() {}
|
void g() {}
|
||||||
// CHECK-SANITY: [[@LINE-1]]:8: warning: Annotate this
|
// CHECK-SANITY: [[@LINE-1]]:8: warning: Use exactly
|
||||||
// CHECK-NOT: warning:
|
// CHECK-NOT: warning:
|
||||||
};
|
};
|
||||||
// CHECK-SANITY-NOT: Suppressed
|
// CHECK-SANITY-NOT: Suppressed
|
||||||
|
|||||||
@@ -4,57 +4,57 @@
|
|||||||
void Method(char *) { /* */ }
|
void Method(char *) { /* */ }
|
||||||
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: all parameters should be named in a function
|
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: all parameters should be named in a function
|
||||||
// CHECK-FIXES: void Method(char * /*unused*/) { /* */ }
|
// 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-MESSAGES: :[[@LINE-1]]:20: warning: all parameters should be named in a function
|
||||||
// CHECK-FIXES: void Method2(char * /*unused*/) {}
|
// CHECK-FIXES: void Method2(char * /*unused*/);
|
||||||
void Method3(char *, void *) {}
|
void Method3(char *, void *);
|
||||||
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: all parameters should be named in a function
|
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: all parameters should be named in a function
|
||||||
// CHECK-FIXES: void Method3(char * /*unused*/, void * /*unused*/) {}
|
// CHECK-FIXES: void Method3(char * /*unused*/, void * /*unused*/);
|
||||||
void Method4(char *, int /*unused*/) {}
|
void Method4(char *, int /*unused*/);
|
||||||
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: all parameters should be named in a function
|
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: all parameters should be named in a function
|
||||||
// CHECK-FIXES: void Method4(char * /*unused*/, int /*unused*/) {}
|
// CHECK-FIXES: void Method4(char * /*unused*/, int /*unused*/);
|
||||||
void operator delete[](void *) throw() {}
|
void operator delete[](void *) throw();
|
||||||
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: all parameters should be named in a function
|
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: all parameters should be named in a function
|
||||||
// CHECK-FIXES: void operator delete[](void * /*unused*/) throw() {}
|
// CHECK-FIXES: void operator delete[](void * /*unused*/) throw();
|
||||||
int Method5(int) { return 0; }
|
int Method5(int);
|
||||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: all parameters should be named in a function
|
// 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 *)) {}
|
void Method6(void (*)(void *)) {}
|
||||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: all parameters should be named in a function
|
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: all parameters should be named in a function
|
||||||
// CHECK-FIXES: void Method6(void (* /*unused*/)(void *)) {}
|
// 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-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.
|
// Don't warn in macros.
|
||||||
#define M void MethodM(int) {}
|
#define M void MethodM(int);
|
||||||
M
|
M
|
||||||
|
|
||||||
void operator delete(void *x) throw() {}
|
void operator delete(void *x) throw();
|
||||||
void Method7(char * /*x*/) {}
|
void Method7(char * /*x*/) {}
|
||||||
void Method8(char *x) {}
|
void Method8(char *x);
|
||||||
typedef void (*TypeM)(int x);
|
typedef void (*TypeM)(int x);
|
||||||
void operator delete[](void *x) throw();
|
void operator delete[](void *x) throw();
|
||||||
void operator delete[](void * /*x*/) throw();
|
void operator delete[](void * /*x*/) throw();
|
||||||
|
|
||||||
struct X {
|
struct X {
|
||||||
X operator++(int) {}
|
X operator++(int);
|
||||||
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: all parameters should be named in a function
|
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: all parameters should be named in a function
|
||||||
// CHECK-FIXES: X operator++(int /*unused*/) {}
|
// CHECK-FIXES: X operator++(int /*unused*/);
|
||||||
X operator--(int /*unused*/) {}
|
X operator--(int /*unused*/);
|
||||||
|
|
||||||
const int &i;
|
const int &i;
|
||||||
};
|
};
|
||||||
|
|
||||||
void (*Func1)(void *);
|
void (*Func1)(void *);
|
||||||
void Func2(void (*func)(void *)) {}
|
void Func2(void (*func)(void *)) {}
|
||||||
template <void Func(void *)> void Func3() {}
|
template <void Func(void *)> void Func3();
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct Y {
|
struct Y {
|
||||||
void foo(T) {}
|
void foo(T);
|
||||||
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: all parameters should be named in a function
|
// 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;
|
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-MESSAGES: :[[@LINE-1]]:15: warning: all parameters should be named in a function
|
||||||
// CHECK-FIXES: void foo(int /*argname*/);
|
// 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())
|
#define TESTMACRO if (b || F())
|
||||||
|
|
||||||
TESTMACRO {
|
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);
|
t(b);
|
||||||
@@ -77,7 +81,4 @@ void foo() {
|
|||||||
|
|
||||||
if (d.b)
|
if (d.b)
|
||||||
(void)*d.b; // no-warning
|
(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 {
|
struct SimpleCases : public Base {
|
||||||
public:
|
public:
|
||||||
virtual ~SimpleCases();
|
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;}}
|
// CHECK-FIXES: {{^ ~SimpleCases\(\) override;}}
|
||||||
|
|
||||||
void a();
|
void a();
|
||||||
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Annotate this
|
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Use exactly
|
||||||
// CHECK-FIXES: {{^ void a\(\) override;}}
|
// CHECK-FIXES: {{^ void a\(\) override;}}
|
||||||
|
|
||||||
void b() override;
|
void b() override;
|
||||||
@@ -48,7 +48,7 @@ public:
|
|||||||
// CHECK-FIXES: {{^ void c\(\) override;}}
|
// CHECK-FIXES: {{^ void c\(\) override;}}
|
||||||
|
|
||||||
virtual void d() 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;}}
|
// CHECK-FIXES: {{^ void d\(\) override;}}
|
||||||
|
|
||||||
virtual void e() = 0;
|
virtual void e() = 0;
|
||||||
@@ -76,7 +76,7 @@ public:
|
|||||||
// CHECK-FIXES: {{^ bool l\(\) override MUST_USE_RESULT;}}
|
// CHECK-FIXES: {{^ bool l\(\) override MUST_USE_RESULT;}}
|
||||||
|
|
||||||
virtual void m() override final;
|
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;}}
|
// CHECK-FIXES: {{^ void m\(\) final;}}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ struct DefaultedDestructor : public Base {
|
|||||||
struct FinalSpecified : public Base {
|
struct FinalSpecified : public Base {
|
||||||
public:
|
public:
|
||||||
virtual ~FinalSpecified() final;
|
virtual ~FinalSpecified() final;
|
||||||
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: Annotate this
|
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: Use exactly
|
||||||
// CHECK-FIXES: {{^ ~FinalSpecified\(\) final;}}
|
// CHECK-FIXES: {{^ ~FinalSpecified\(\) final;}}
|
||||||
|
|
||||||
void b() final;
|
void b() final;
|
||||||
@@ -106,19 +106,19 @@ public:
|
|||||||
// CHECK-FIXES: {{^ void b\(\) final;}}
|
// CHECK-FIXES: {{^ void b\(\) final;}}
|
||||||
|
|
||||||
virtual void d() 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;}}
|
// CHECK-FIXES: {{^ void d\(\) final;}}
|
||||||
|
|
||||||
virtual void e() final = 0;
|
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;}}
|
// CHECK-FIXES: {{^ void e\(\) final = 0;}}
|
||||||
|
|
||||||
virtual void j() const final;
|
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;}}
|
// CHECK-FIXES: {{^ void j\(\) const final;}}
|
||||||
|
|
||||||
virtual bool l() final MUST_USE_RESULT;
|
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;}}
|
// CHECK-FIXES: {{^ bool l\(\) final MUST_USE_RESULT;}}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ public:
|
|||||||
// CHECK-FIXES: {{^ ~InlineDefinitions\(\) override {}}}
|
// CHECK-FIXES: {{^ ~InlineDefinitions\(\) override {}}}
|
||||||
|
|
||||||
void a() {}
|
void a() {}
|
||||||
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Annotate this
|
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Use exactly
|
||||||
// CHECK-FIXES: {{^ void a\(\) override {}}}
|
// CHECK-FIXES: {{^ void a\(\) override {}}}
|
||||||
|
|
||||||
void b() override {}
|
void b() override {}
|
||||||
@@ -141,7 +141,7 @@ public:
|
|||||||
// CHECK-FIXES: {{^ void c\(\) override {}}}
|
// CHECK-FIXES: {{^ void c\(\) override {}}}
|
||||||
|
|
||||||
virtual void d() 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 {}}}
|
// CHECK-FIXES: {{^ void d\(\) override {}}}
|
||||||
|
|
||||||
virtual void j() const {}
|
virtual void j() const {}
|
||||||
@@ -161,7 +161,7 @@ struct Macros : public Base {
|
|||||||
// Tests for 'virtual' and 'override' being defined through macros. Basically
|
// Tests for 'virtual' and 'override' being defined through macros. Basically
|
||||||
// give up for now.
|
// give up for now.
|
||||||
NOT_VIRTUAL void a() NOT_OVERRIDE;
|
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;}}
|
// CHECK-FIXES: {{^ NOT_VIRTUAL void a\(\) override NOT_OVERRIDE;}}
|
||||||
|
|
||||||
VIRTUAL void b() NOT_OVERRIDE;
|
VIRTUAL void b() NOT_OVERRIDE;
|
||||||
@@ -173,7 +173,7 @@ struct Macros : public Base {
|
|||||||
// CHECK-FIXES: {{^ NOT_VIRTUAL void c\(\) OVERRIDE;}}
|
// CHECK-FIXES: {{^ NOT_VIRTUAL void c\(\) OVERRIDE;}}
|
||||||
|
|
||||||
VIRTUAL void d() 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;}}
|
// CHECK-FIXES: {{^ VIRTUAL void d\(\) OVERRIDE;}}
|
||||||
|
|
||||||
#define FUNC(return_type, name) return_type name()
|
#define FUNC(return_type, name) return_type name()
|
||||||
@@ -185,7 +185,7 @@ struct Macros : public Base {
|
|||||||
// CHECK-FIXES: {{^ F}}
|
// CHECK-FIXES: {{^ F}}
|
||||||
|
|
||||||
VIRTUAL void g() OVERRIDE final;
|
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;}}
|
// CHECK-FIXES: {{^ VIRTUAL void g\(\) final;}}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
#include "clang/Basic/SourceManager.h"
|
#include "clang/Basic/SourceManager.h"
|
||||||
#include "clang/Frontend/FrontendActions.h"
|
#include "clang/Frontend/FrontendActions.h"
|
||||||
#include "clang/Lex/Lexer.h"
|
#include "clang/Lex/Lexer.h"
|
||||||
#include "clang/Tooling/CommonOptionsParser.h"
|
#include "clang/Tooling/CompilationDatabase.h"
|
||||||
#include "clang/Tooling/Refactoring.h"
|
#include "clang/Tooling/Refactoring.h"
|
||||||
#include "clang/Tooling/Tooling.h"
|
#include "clang/Tooling/Tooling.h"
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
@@ -56,11 +56,11 @@ class ToolTemplateCallback : public MatchFinder::MatchCallback {
|
|||||||
public:
|
public:
|
||||||
ToolTemplateCallback(Replacements *Replace) : Replace(Replace) {}
|
ToolTemplateCallback(Replacements *Replace) : Replace(Replace) {}
|
||||||
|
|
||||||
void run(const MatchFinder::MatchResult &Result) override {
|
virtual void run(const MatchFinder::MatchResult &Result) {
|
||||||
// TODO: This routine will get called for each thing that the matchers find.
|
// 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,
|
// At this point, you can examine the match, and do whatever you want,
|
||||||
// including replacing the matched text with other text
|
// including replacing the matched text with other text
|
||||||
(void)Replace; // This to prevent an "unused member variable" warning;
|
(void) Replace; // This to prevent an "unused member variable" warning;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -69,20 +69,39 @@ class ToolTemplateCallback : public MatchFinder::MatchCallback {
|
|||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
||||||
// Set up the command line options
|
// Set up the command line options
|
||||||
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
|
cl::opt<std::string> BuildPath(
|
||||||
static cl::OptionCategory ToolTemplateCategory("tool-template options");
|
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) {
|
int main(int argc, const char **argv) {
|
||||||
llvm::sys::PrintStackTraceOnErrorSignal();
|
llvm::sys::PrintStackTraceOnErrorSignal();
|
||||||
CommonOptionsParser OptionsParser(argc, argv, ToolTemplateCategory);
|
std::unique_ptr<CompilationDatabase> Compilations(
|
||||||
RefactoringTool Tool(OptionsParser.getCompilations(),
|
FixedCompilationDatabase::loadFromCommandLine(argc, argv));
|
||||||
OptionsParser.getSourcePathList());
|
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;
|
ast_matchers::MatchFinder Finder;
|
||||||
ToolTemplateCallback Callback(&Tool.getReplacements());
|
ToolTemplateCallback Callback(&Tool.getReplacements());
|
||||||
|
|
||||||
// TODO: Put your matchers here.
|
// TODO: Put your matchers here.
|
||||||
// Use Finder.addMatcher(...) to define the patterns in the AST that you
|
// Use Finder.addMatcher(...) to define the patterns in the AST that you
|
||||||
// want to match against. You are not limited to just one matcher!
|
// want to match against. You are not limited to just one matcher!
|
||||||
|
|
||||||
return Tool.run(newFrontendActionFactory(&Finder).get());
|
return Tool.run(newFrontendActionFactory(&Finder).get());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,5 @@ endfunction()
|
|||||||
|
|
||||||
add_subdirectory(clang-apply-replacements)
|
add_subdirectory(clang-apply-replacements)
|
||||||
add_subdirectory(clang-modernize)
|
add_subdirectory(clang-modernize)
|
||||||
add_subdirectory(clang-rename)
|
|
||||||
add_subdirectory(clang-query)
|
add_subdirectory(clang-query)
|
||||||
add_subdirectory(clang-tidy)
|
add_subdirectory(clang-tidy)
|
||||||
|
|||||||
@@ -93,8 +93,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ConsumerFactory {
|
struct ConsumerFactory {
|
||||||
std::unique_ptr<ASTConsumer> newASTConsumer() {
|
ASTConsumer *newASTConsumer() {
|
||||||
return llvm::make_unique<TimePassingASTConsumer>(&Called);
|
return new TimePassingASTConsumer(&Called);
|
||||||
}
|
}
|
||||||
bool 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);
|
EXPECT_EQ("variable []", Errors[1].Message.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(GlobList, Empty) {
|
TEST(ChecksFilter, Empty) {
|
||||||
GlobList Filter("");
|
ChecksFilter Filter("");
|
||||||
|
|
||||||
EXPECT_TRUE(Filter.contains(""));
|
EXPECT_TRUE(Filter.isCheckEnabled(""));
|
||||||
EXPECT_FALSE(Filter.contains("aaa"));
|
EXPECT_FALSE(Filter.isCheckEnabled("aaa"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(GlobList, Nothing) {
|
TEST(ChecksFilter, Nothing) {
|
||||||
GlobList Filter("-*");
|
ChecksFilter Filter("-*");
|
||||||
|
|
||||||
EXPECT_FALSE(Filter.contains(""));
|
EXPECT_FALSE(Filter.isCheckEnabled(""));
|
||||||
EXPECT_FALSE(Filter.contains("a"));
|
EXPECT_FALSE(Filter.isCheckEnabled("a"));
|
||||||
EXPECT_FALSE(Filter.contains("-*"));
|
EXPECT_FALSE(Filter.isCheckEnabled("-*"));
|
||||||
EXPECT_FALSE(Filter.contains("-"));
|
EXPECT_FALSE(Filter.isCheckEnabled("-"));
|
||||||
EXPECT_FALSE(Filter.contains("*"));
|
EXPECT_FALSE(Filter.isCheckEnabled("*"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(GlobList, Everything) {
|
TEST(ChecksFilter, Everything) {
|
||||||
GlobList Filter("*");
|
ChecksFilter Filter("*");
|
||||||
|
|
||||||
EXPECT_TRUE(Filter.contains(""));
|
EXPECT_TRUE(Filter.isCheckEnabled(""));
|
||||||
EXPECT_TRUE(Filter.contains("aaaa"));
|
EXPECT_TRUE(Filter.isCheckEnabled("aaaa"));
|
||||||
EXPECT_TRUE(Filter.contains("-*"));
|
EXPECT_TRUE(Filter.isCheckEnabled("-*"));
|
||||||
EXPECT_TRUE(Filter.contains("-"));
|
EXPECT_TRUE(Filter.isCheckEnabled("-"));
|
||||||
EXPECT_TRUE(Filter.contains("*"));
|
EXPECT_TRUE(Filter.isCheckEnabled("*"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(GlobList, Simple) {
|
TEST(ChecksFilter, Simple) {
|
||||||
GlobList Filter("aaa");
|
ChecksFilter Filter("aaa");
|
||||||
|
|
||||||
EXPECT_TRUE(Filter.contains("aaa"));
|
EXPECT_TRUE(Filter.isCheckEnabled("aaa"));
|
||||||
EXPECT_FALSE(Filter.contains(""));
|
EXPECT_FALSE(Filter.isCheckEnabled(""));
|
||||||
EXPECT_FALSE(Filter.contains("aa"));
|
EXPECT_FALSE(Filter.isCheckEnabled("aa"));
|
||||||
EXPECT_FALSE(Filter.contains("aaaa"));
|
EXPECT_FALSE(Filter.isCheckEnabled("aaaa"));
|
||||||
EXPECT_FALSE(Filter.contains("bbb"));
|
EXPECT_FALSE(Filter.isCheckEnabled("bbb"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(GlobList, Complex) {
|
TEST(ChecksFilter, Complex) {
|
||||||
GlobList Filter("*,-a.*,-b.*,a.1.*,-a.1.A.*,-..,-...,-..+,-*$,-*qwe*");
|
ChecksFilter Filter("*,-a.*,-b.*,a.1.*,-a.1.A.*,-..,-...,-..+,-*$,-*qwe*");
|
||||||
|
|
||||||
EXPECT_TRUE(Filter.contains("aaa"));
|
EXPECT_TRUE(Filter.isCheckEnabled("aaa"));
|
||||||
EXPECT_TRUE(Filter.contains("qqq"));
|
EXPECT_TRUE(Filter.isCheckEnabled("qqq"));
|
||||||
EXPECT_FALSE(Filter.contains("a."));
|
EXPECT_FALSE(Filter.isCheckEnabled("a."));
|
||||||
EXPECT_FALSE(Filter.contains("a.b"));
|
EXPECT_FALSE(Filter.isCheckEnabled("a.b"));
|
||||||
EXPECT_FALSE(Filter.contains("b."));
|
EXPECT_FALSE(Filter.isCheckEnabled("b."));
|
||||||
EXPECT_FALSE(Filter.contains("b.b"));
|
EXPECT_FALSE(Filter.isCheckEnabled("b.b"));
|
||||||
EXPECT_TRUE(Filter.contains("a.1.b"));
|
EXPECT_TRUE(Filter.isCheckEnabled("a.1.b"));
|
||||||
EXPECT_FALSE(Filter.contains("a.1.A.a"));
|
EXPECT_FALSE(Filter.isCheckEnabled("a.1.A.a"));
|
||||||
EXPECT_FALSE(Filter.contains("qwe"));
|
EXPECT_FALSE(Filter.isCheckEnabled("qwe"));
|
||||||
EXPECT_FALSE(Filter.contains("asdfqweasdf"));
|
EXPECT_FALSE(Filter.isCheckEnabled("asdfqweasdf"));
|
||||||
EXPECT_TRUE(Filter.contains("asdfqwEasdf"));
|
EXPECT_TRUE(Filter.isCheckEnabled("asdfqwEasdf"));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
|||||||
@@ -41,26 +41,22 @@ private:
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::string runCheckOnCode(StringRef Code,
|
std::string runCheckOnCode(StringRef Code,
|
||||||
std::vector<ClangTidyError> *Errors = nullptr,
|
std::vector<ClangTidyError> *Errors = nullptr) {
|
||||||
const Twine &Filename = "input.cc",
|
|
||||||
ArrayRef<std::string> ExtraArgs = None) {
|
|
||||||
T Check;
|
T Check;
|
||||||
ClangTidyContext Context(
|
ClangTidyContext Context(
|
||||||
new DefaultOptionsProvider(ClangTidyGlobalOptions(), ClangTidyOptions()));
|
new DefaultOptionsProvider(ClangTidyGlobalOptions(), ClangTidyOptions()));
|
||||||
ClangTidyDiagnosticConsumer DiagConsumer(Context);
|
ClangTidyDiagnosticConsumer DiagConsumer(Context);
|
||||||
Check.setContext(&Context);
|
Check.setContext(&Context);
|
||||||
std::vector<std::string> ArgCXX11(1, "-std=c++11");
|
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,
|
if (!tooling::runToolOnCodeWithArgs(new TestPPAction(Check, &Context), Code,
|
||||||
ArgCXX11, Filename))
|
ArgCXX11))
|
||||||
return "";
|
return "";
|
||||||
ast_matchers::MatchFinder Finder;
|
ast_matchers::MatchFinder Finder;
|
||||||
Check.registerMatchers(&Finder);
|
Check.registerMatchers(&Finder);
|
||||||
std::unique_ptr<tooling::FrontendActionFactory> Factory(
|
std::unique_ptr<tooling::FrontendActionFactory> Factory(
|
||||||
tooling::newFrontendActionFactory(&Finder));
|
tooling::newFrontendActionFactory(&Finder));
|
||||||
if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, ArgCXX11,
|
if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, ArgCXX11))
|
||||||
Filename))
|
|
||||||
return "";
|
return "";
|
||||||
DiagConsumer.finish();
|
DiagConsumer.finish();
|
||||||
tooling::Replacements Fixes;
|
tooling::Replacements Fixes;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#include "ClangTidyTest.h"
|
#include "ClangTidyTest.h"
|
||||||
#include "llvm/HeaderGuardCheck.h"
|
|
||||||
#include "llvm/IncludeOrderCheck.h"
|
#include "llvm/IncludeOrderCheck.h"
|
||||||
#include "llvm/NamespaceCommentCheck.h"
|
#include "llvm/NamespaceCommentCheck.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
@@ -86,49 +85,6 @@ TEST(NamespaceCommentCheckTest, FixWrongComments) {
|
|||||||
"} // namespace asdf"));
|
"} // 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 test
|
||||||
} // namespace tidy
|
} // namespace tidy
|
||||||
} // namespace clang
|
} // namespace clang
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ TESTNAME = ClangTidy
|
|||||||
LINK_COMPONENTS := asmparser bitreader support MC MCParser option \
|
LINK_COMPONENTS := asmparser bitreader support MC MCParser option \
|
||||||
TransformUtils
|
TransformUtils
|
||||||
USEDLIBS = clangTidy.a clangTidyLLVMModule.a clangTidyGoogleModule.a \
|
USEDLIBS = clangTidy.a clangTidyLLVMModule.a clangTidyGoogleModule.a \
|
||||||
clangTidyMiscModule.a clangTidy.a clangTidyUtils.a \
|
clangTidyMiscModule.a clangTidy.a \
|
||||||
clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
|
clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
|
||||||
clangStaticAnalyzerCore.a \
|
clangStaticAnalyzerCore.a \
|
||||||
clangFormat.a clangTooling.a clangFrontend.a clangSerialization.a \
|
clangFormat.a clangTooling.a clangFrontend.a clangSerialization.a \
|
||||||
|
|||||||
@@ -1086,7 +1086,6 @@ CursorKind.CUDACONSTANT_ATTR = CursorKind(412)
|
|||||||
CursorKind.CUDADEVICE_ATTR = CursorKind(413)
|
CursorKind.CUDADEVICE_ATTR = CursorKind(413)
|
||||||
CursorKind.CUDAGLOBAL_ATTR = CursorKind(414)
|
CursorKind.CUDAGLOBAL_ATTR = CursorKind(414)
|
||||||
CursorKind.CUDAHOST_ATTR = CursorKind(415)
|
CursorKind.CUDAHOST_ATTR = CursorKind(415)
|
||||||
CursorKind.CUDASHARED_ATTR = CursorKind(416)
|
|
||||||
|
|
||||||
###
|
###
|
||||||
# Preprocessing
|
# Preprocessing
|
||||||
@@ -1177,23 +1176,15 @@ class Cursor(Structure):
|
|||||||
"""
|
"""
|
||||||
Return the display name for the entity referenced by this cursor.
|
Return the display name for the entity referenced by this cursor.
|
||||||
|
|
||||||
The display name contains extra information that helps identify the
|
The display name contains extra information that helps identify the cursor,
|
||||||
cursor, such as the parameters of a function or template or the
|
such as the parameters of a function or template or the arguments of a
|
||||||
arguments of a class template specialization.
|
class template specialization.
|
||||||
"""
|
"""
|
||||||
if not hasattr(self, '_displayname'):
|
if not hasattr(self, '_displayname'):
|
||||||
self._displayname = conf.lib.clang_getCursorDisplayName(self)
|
self._displayname = conf.lib.clang_getCursorDisplayName(self)
|
||||||
|
|
||||||
return self._displayname
|
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
|
@property
|
||||||
def location(self):
|
def location(self):
|
||||||
"""
|
"""
|
||||||
@@ -2982,11 +2973,6 @@ functionList = [
|
|||||||
_CXString,
|
_CXString,
|
||||||
_CXString.from_result),
|
_CXString.from_result),
|
||||||
|
|
||||||
("clang_Cursor_getMangling",
|
|
||||||
[Cursor],
|
|
||||||
_CXString,
|
|
||||||
_CXString.from_result),
|
|
||||||
|
|
||||||
# ("clang_getCXTUResourceUsage",
|
# ("clang_getCXTUResourceUsage",
|
||||||
# [TranslationUnit],
|
# [TranslationUnit],
|
||||||
# CXTUResourceUsage),
|
# CXTUResourceUsage),
|
||||||
|
|||||||
@@ -252,17 +252,3 @@ def test_referenced():
|
|||||||
if c.kind == CursorKind.CALL_EXPR:
|
if c.kind == CursorKind.CALL_EXPR:
|
||||||
assert c.referenced.spelling == foo.spelling
|
assert c.referenced.spelling == foo.spelling
|
||||||
break
|
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.
|
# 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
|
An easy way to get a valid ``.clang-format`` file containing all configuration
|
||||||
options of a certain predefined style is:
|
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
|
If ``true``, ``while (true) continue;`` can be put on a
|
||||||
single line.
|
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``)
|
**AlwaysBreakBeforeMultilineStrings** (``bool``)
|
||||||
If ``true``, always break before multiline string literals.
|
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
|
Like ``Attach``, but break before braces on function, namespace and
|
||||||
class definitions.
|
class definitions.
|
||||||
* ``BS_Stroustrup`` (in configuration: ``Stroustrup``)
|
* ``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``)
|
* ``BS_Allman`` (in configuration: ``Allman``)
|
||||||
Always break before braces.
|
Always break before braces.
|
||||||
* ``BS_GNU`` (in configuration: ``GNU``)
|
* ``BS_GNU`` (in configuration: ``GNU``)
|
||||||
@@ -257,7 +213,7 @@ the configuration (without a prefix: ``Auto``).
|
|||||||
|
|
||||||
**DerivePointerAlignment** (``bool``)
|
**DerivePointerAlignment** (``bool``)
|
||||||
If ``true``, analyze the formatted file for the most common
|
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``)
|
**DisableFormat** (``bool``)
|
||||||
Disables formatting at all.
|
Disables formatting at all.
|
||||||
|
|||||||
@@ -1780,17 +1780,15 @@ it causes the instantiation of ``twice`` and ``thrice`` with an ``int`` type; of
|
|||||||
these two instantiations, ``twice`` will be optimized (because its definition
|
these two instantiations, ``twice`` will be optimized (because its definition
|
||||||
was outside the region) and ``thrice`` will not be optimized.
|
was outside the region) and ``thrice`` will not be optimized.
|
||||||
|
|
||||||
|
.. _langext-pragma-loop:
|
||||||
|
|
||||||
Extensions for loop hint optimizations
|
Extensions for loop hint optimizations
|
||||||
======================================
|
======================================
|
||||||
|
|
||||||
The ``#pragma clang loop`` directive is used to specify hints for optimizing the
|
The ``#pragma clang loop`` directive is used to specify hints for optimizing the
|
||||||
subsequent for, while, do-while, or c++11 range-based for loop. The directive
|
subsequent for, while, do-while, or c++11 range-based for loop. The directive
|
||||||
provides options for vectorization, interleaving, and unrolling. Loop hints can
|
provides options for vectorization and interleaving. Loop hints can be specified
|
||||||
be specified before any loop and will be ignored if the optimization is not safe
|
before any loop and will be ignored if the optimization is not safe to apply.
|
||||||
to apply.
|
|
||||||
|
|
||||||
Vectorization and Interleaving
|
|
||||||
------------------------------
|
|
||||||
|
|
||||||
A vectorized loop performs multiple iterations of the original loop
|
A vectorized loop performs multiple iterations of the original loop
|
||||||
in parallel using vector instructions. The instruction set of the target
|
in parallel using vector instructions. The instruction set of the target
|
||||||
@@ -1833,46 +1831,6 @@ width/count of the set of target architectures supported by your application.
|
|||||||
Specifying a width/count of 1 disables the optimization, and is equivalent to
|
Specifying a width/count of 1 disables the optimization, and is equivalent to
|
||||||
``vectorize(disable)`` or ``interleave(disable)``.
|
``vectorize(disable)`` or ``interleave(disable)``.
|
||||||
|
|
||||||
Loop Unrolling
|
|
||||||
--------------
|
|
||||||
|
|
||||||
Unrolling a loop reduces the loop control overhead and exposes more
|
|
||||||
opportunities for ILP. Loops can be fully or partially unrolled. Full unrolling
|
|
||||||
eliminates the loop and replaces it with an enumerated sequence of loop
|
|
||||||
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
|
|
||||||
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
|
|
||||||
unrolled subject to the same limit.
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
#pragma clang loop unroll(full)
|
|
||||||
for(...) {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
The unroll count can be specified explicitly with ``unroll_count(_value_)`` where
|
|
||||||
_value_ is a positive integer. If this value is greater than the trip count the
|
|
||||||
loop will be fully unrolled. Otherwise the loop is partially unrolled subject
|
|
||||||
to the `-pragma-unroll-threshold` limit.
|
|
||||||
|
|
||||||
.. code-block:: c++
|
|
||||||
|
|
||||||
#pragma clang loop unroll_count(8)
|
|
||||||
for(...) {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
Unrolling of a loop can be prevented by specifying ``unroll(disable)``.
|
|
||||||
|
|
||||||
Additional Information
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
For convenience multiple loop hints can be specified on a single line.
|
For convenience multiple loop hints can be specified on a single line.
|
||||||
|
|
||||||
.. code-block:: c++
|
.. code-block:: c++
|
||||||
|
|||||||
@@ -319,16 +319,6 @@ usingDecl()
|
|||||||
matches using X::x </pre></td></tr>
|
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>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.
|
<tr><td colspan="4" class="doc" id="varDecl0"><pre>Matches variable declarations.
|
||||||
|
|
||||||
@@ -365,14 +355,6 @@ nestedNameSpecifier()
|
|||||||
</pre></td></tr>
|
</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>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.
|
<tr><td colspan="4" class="doc" id="arraySubscriptExpr0"><pre>Matches array subscript expressions.
|
||||||
|
|
||||||
@@ -729,7 +711,7 @@ Given
|
|||||||
int a[] = { 1, 2 };
|
int a[] = { 1, 2 };
|
||||||
struct B { int x, y; };
|
struct B { int x, y; };
|
||||||
B b = { 5, 6 };
|
B b = { 5, 6 };
|
||||||
initListExpr()
|
initList()
|
||||||
matches "{ 1, 2 }" and "{ 5, 6 }"
|
matches "{ 1, 2 }" and "{ 5, 6 }"
|
||||||
</pre></td></tr>
|
</pre></td></tr>
|
||||||
|
|
||||||
@@ -894,18 +876,6 @@ Example matches "abcd", L"abcd"
|
|||||||
</pre></td></tr>
|
</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>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.
|
<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 a[] = { 2, 3 }
|
||||||
int b[42];
|
int b[42];
|
||||||
int c[a[0]];
|
int c[a[0]];
|
||||||
}
|
|
||||||
variableArrayType()
|
variableArrayType()
|
||||||
matches "int c[a[0]]"
|
matches "int c[a[0]]"
|
||||||
</pre></td></tr>
|
</pre></td></tr>
|
||||||
@@ -1412,6 +1381,26 @@ constructorDecl(hasAnyConstructorInitializer(isWritten()))
|
|||||||
</pre></td></tr>
|
</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>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.
|
<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
|
line and recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
|
||||||
the declaration of A.
|
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>
|
</pre></td></tr>
|
||||||
|
|
||||||
|
|
||||||
@@ -1612,30 +1601,10 @@ and reference to that variable declaration within a compound statement.
|
|||||||
</pre></td></tr>
|
</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>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="hasCudaDeviceAttr0"><pre>Matches declaration that has CUDA device attribute.
|
<tr><td colspan="4" class="doc" id="equalsNode0"><pre>Matches if a node equals another node.
|
||||||
|
|
||||||
Given
|
Decl has pointer identity in the AST.
|
||||||
__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.
|
|
||||||
</pre></td></tr>
|
</pre></td></tr>
|
||||||
|
|
||||||
|
|
||||||
@@ -1698,26 +1667,6 @@ Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Charac
|
|||||||
</pre></td></tr>
|
</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>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.
|
<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>
|
</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>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
|
<tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization0"><pre>Matches explicit template specializations of function, class, or
|
||||||
static member variable template instantiations.
|
static member variable template instantiations.
|
||||||
@@ -1962,6 +1900,14 @@ and reference to that variable declaration within a compound statement.
|
|||||||
</pre></td></tr>
|
</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>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.
|
<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")))))
|
Example matches y.x() (matcher = callExpr(callee(methodDecl(hasName("x")))))
|
||||||
class Y { public: void x(); };
|
class Y { public: void x(); };
|
||||||
void z() { Y y; y.x(); }
|
void z() { Y y; y.x();
|
||||||
</pre></td></tr>
|
</pre></td></tr>
|
||||||
|
|
||||||
|
|
||||||
@@ -3502,7 +3448,6 @@ Example matches X &x and const X &y
|
|||||||
void a(X b) {
|
void a(X b) {
|
||||||
X &x = b;
|
X &x = b;
|
||||||
const X &y = b;
|
const X &y = b;
|
||||||
}
|
|
||||||
};
|
};
|
||||||
</pre></td></tr>
|
</pre></td></tr>
|
||||||
|
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ Modules are modeled as if each submodule were a separate translation unit, and a
|
|||||||
|
|
||||||
.. note::
|
.. 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.
|
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.
|
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
|
Macros
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
=====================================
|
=======================
|
||||||
Clang 3.5 (In-Progress) Release Notes
|
Clang 3.5 Release Notes
|
||||||
=====================================
|
=======================
|
||||||
|
|
||||||
.. contents::
|
.. contents::
|
||||||
:local:
|
:local:
|
||||||
@@ -8,12 +8,6 @@ Clang 3.5 (In-Progress) Release Notes
|
|||||||
|
|
||||||
Written by the `LLVM Team <http://llvm.org/>`_
|
Written by the `LLVM Team <http://llvm.org/>`_
|
||||||
|
|
||||||
.. warning::
|
|
||||||
|
|
||||||
These are in-progress notes for the upcoming Clang 3.5 release. You may
|
|
||||||
prefer the `Clang 3.4 Release Notes
|
|
||||||
<http://llvm.org/releases/3.4/tools/clang/docs/ReleaseNotes.html>`_.
|
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
============
|
============
|
||||||
|
|
||||||
@@ -56,6 +50,15 @@ Major New Features
|
|||||||
the attribute was available to the specific target. Clang now returns true
|
the attribute was available to the specific target. Clang now returns true
|
||||||
only when the attribute pertains to the current compilation target.
|
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
|
Improvements to Clang's diagnostics
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@@ -67,6 +70,74 @@ about them. The improvements since the 3.4 release include:
|
|||||||
- GCC compatibility: Clang displays a warning on unsupported gcc
|
- GCC compatibility: Clang displays a warning on unsupported gcc
|
||||||
optimization flags instead of an error.
|
optimization flags instead of an error.
|
||||||
|
|
||||||
|
- Remarks system: Clang supports `-R` flags for enabling remarks. These are
|
||||||
|
diagnostic messages that provide information about the compilation process,
|
||||||
|
but don't suggest that a problem has been detected. As such, they cannot
|
||||||
|
be upgraded to errors with `-Werror` or `-Rerror`. A `-Reverything` flag
|
||||||
|
is provided (paralleling `-Weverything`) to turn on all remarks.
|
||||||
|
|
||||||
|
- New remark `-Rpass`: Clang provides information about decisions made by
|
||||||
|
optimization passes during compilation. See :ref:`opt_rpass`.
|
||||||
|
|
||||||
|
- 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
|
New Compiler Flags
|
||||||
@@ -100,70 +171,50 @@ passes via three new flags: `-Rpass`, `-Rpass-missed` and `-Rpass-analysis`.
|
|||||||
These flags take a POSIX regular expression which indicates the name
|
These flags take a POSIX regular expression which indicates the name
|
||||||
of the pass (or passes) that should emit optimization remarks.
|
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
|
New Pragmas in Clang
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
Loop optimization hints can be specified using the new `#pragma clang loop`
|
Loop optimization hints can be specified using the new `#pragma clang loop`
|
||||||
directive just prior to the desired loop. The directive allows vectorization,
|
directive just prior to the desired loop. The directive allows vectorization and
|
||||||
interleaving, and unrolling to be enabled or disabled. Vector width as well
|
interleaving to be enabled or disabled. Vector width as well as interleave count
|
||||||
as interleave and unrolling count can be manually specified. See language
|
can be manually specified. See :ref:`langext-pragma-loop` for details.
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
C Language Changes in Clang
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
C11 Feature Support
|
|
||||||
^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
C++ Language Changes in Clang
|
C++ Language Changes in Clang
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
- ...
|
- Reference parameters and return values from functions are more aggressively
|
||||||
|
assumed to refer to valid objects when optimizing. Clang will attempt to
|
||||||
|
issue a warning by default if it sees null checks being performed on
|
||||||
|
references, and `-fsanitize=null` can be used to detect null references
|
||||||
|
being formed at runtime.
|
||||||
|
|
||||||
C++11 Feature Support
|
C++17 Feature Support
|
||||||
^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
...
|
Clang has experimental support for some proposed C++1z (tentatively, C++17)
|
||||||
|
features. This support can be enabled using the `-std=c++1z` flag. The
|
||||||
|
supported features are:
|
||||||
|
|
||||||
Objective-C Language Changes in Clang
|
- `static_assert(expr)` with no message
|
||||||
-------------------------------------
|
|
||||||
|
|
||||||
...
|
- `for (identifier : range)` as a synonym for `for (auto &&identifier : range)`
|
||||||
|
|
||||||
OpenCL C Language Changes in Clang
|
- `template<template<...> typename>` as a synonym for `template<template<...> class>`
|
||||||
----------------------------------
|
|
||||||
|
Additionally, trigraphs are not recognized by default in this mode.
|
||||||
|
`-ftrigraphs` can be used if you need to parse legacy code that uses trigraphs.
|
||||||
|
Note that these features may be changed or removed in future Clang releases
|
||||||
|
without notice.
|
||||||
|
|
||||||
|
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
|
Internal API Changes
|
||||||
--------------------
|
--------------------
|
||||||
@@ -172,16 +223,22 @@ These are major API changes that have happened since the 3.4 release of
|
|||||||
Clang. If upgrading an external codebase that uses Clang as a library,
|
Clang. If upgrading an external codebase that uses Clang as a library,
|
||||||
this section should help get you past the largest hurdles of upgrading.
|
this section should help get you past the largest hurdles of upgrading.
|
||||||
|
|
||||||
...
|
- Clang uses `std::unique_ptr<T>` in many places where it used to use
|
||||||
|
raw `T *` pointers.
|
||||||
libclang
|
|
||||||
--------
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
Static Analyzer
|
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-block:: 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
|
The `-analyzer-config` options are now passed from scan-build through to
|
||||||
ccc-analyzer and then to Clang.
|
ccc-analyzer and then to Clang.
|
||||||
|
|
||||||
@@ -192,25 +249,6 @@ instead of `report-XXXXXX.html`, scan-build/clang analyzer generate
|
|||||||
|
|
||||||
List the function/method name in the index page of scan-build.
|
List the function/method name in the index page of scan-build.
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
Core Analysis Improvements
|
|
||||||
==========================
|
|
||||||
|
|
||||||
- ...
|
|
||||||
|
|
||||||
New Issues Found
|
|
||||||
================
|
|
||||||
|
|
||||||
- ...
|
|
||||||
|
|
||||||
Python Binding Changes
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
The following methods have been added:
|
|
||||||
|
|
||||||
- ...
|
|
||||||
|
|
||||||
Significant Known Problems
|
Significant Known Problems
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user