summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy/cppcoreguidelines
diff options
context:
space:
mode:
authorJonas Toth <jonas.toth@gmail.com>2017-10-18 16:14:15 +0000
committerJonas Toth <jonas.toth@gmail.com>2017-10-18 16:14:15 +0000
commitc9aea86e6af2bc1f7414f69f31428cf49273bf62 (patch)
treeeb9d59a48d895e2799a488c3b416a79a7d66bc89 /clang-tools-extra/clang-tidy/cppcoreguidelines
parent13ce95b77f54aa4a7ff01a46a5faaa85001755a6 (diff)
downloadbcm5719-llvm-c9aea86e6af2bc1f7414f69f31428cf49273bf62.tar.gz
bcm5719-llvm-c9aea86e6af2bc1f7414f69f31428cf49273bf62.zip
[clang-tidy] introduce legacy resource functions to 'cppcoreguidelines-owning-memory'
Summary: This patch introduces support for legacy C-style resource functions that must obey the 'owner<>' semantics. - added legacy creators like malloc,fopen,... - added legacy consumers like free,fclose,... This helps codes that mostly benefit from owner: Legacy, C-Style code that isn't feasable to port directly to RAII but needs a step in between to identify actual resource management and just using the resources. Reviewers: aaron.ballman, alexfh, hokein Reviewed By: aaron.ballman Subscribers: nemanjai, JDevlieghere, xazax.hun, kbarton Differential Revision: https://reviews.llvm.org/D38396 llvm-svn: 316092
Diffstat (limited to 'clang-tools-extra/clang-tidy/cppcoreguidelines')
-rw-r--r--clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp74
-rw-r--r--clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.h21
2 files changed, 91 insertions, 4 deletions
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
index ac3d92c98ac..6c86e053b14 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
@@ -22,6 +22,21 @@ namespace clang {
namespace tidy {
namespace cppcoreguidelines {
+// FIXME: Copied from 'NoMallocCheck.cpp'. Has to be refactored into 'util' or
+// something like that.
+namespace {
+Matcher<FunctionDecl> hasAnyListedName(const std::string &FunctionNames) {
+ const std::vector<std::string> NameList =
+ utils::options::parseStringList(FunctionNames);
+ return hasAnyName(std::vector<StringRef>(NameList.begin(), NameList.end()));
+}
+} // namespace
+
+void OwningMemoryCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "LegacyResourceProducers", LegacyResourceProducers);
+ Options.store(Opts, "LegacyResourceConsumers", LegacyResourceConsumers);
+}
+
/// Match common cases, where the owner semantic is relevant, like function
/// calls, delete expressions and others.
void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) {
@@ -30,10 +45,31 @@ void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) {
const auto OwnerDecl = typeAliasTemplateDecl(hasName("::gsl::owner"));
const auto IsOwnerType = hasType(OwnerDecl);
+
+ const auto LegacyCreatorFunctions = hasAnyListedName(LegacyResourceProducers);
+ const auto LegacyConsumerFunctions =
+ hasAnyListedName(LegacyResourceConsumers);
+
+ // Legacy functions that are use for resource management but cannot be
+ // updated to use `gsl::owner<>`, like standard C memory management.
+ const auto CreatesLegacyOwner =
+ callExpr(callee(functionDecl(LegacyCreatorFunctions)));
+ // C-style functions like `::malloc()` sometimes create owners as void*
+ // which is expected to be cast to the correct type in C++. This case
+ // must be catched explicitly.
+ const auto LegacyOwnerCast =
+ castExpr(hasSourceExpression(CreatesLegacyOwner));
+ // Functions that do manual resource management but cannot be updated to use
+ // owner. Best example is `::free()`.
+ const auto LegacyOwnerConsumers = functionDecl(LegacyConsumerFunctions);
+
const auto CreatesOwner =
- anyOf(cxxNewExpr(), callExpr(callee(functionDecl(
- returns(qualType(hasDeclaration(OwnerDecl)))))));
- const auto ConsideredOwner = anyOf(IsOwnerType, CreatesOwner);
+ anyOf(cxxNewExpr(),
+ callExpr(callee(
+ functionDecl(returns(qualType(hasDeclaration(OwnerDecl)))))),
+ CreatesLegacyOwner, LegacyOwnerCast);
+
+ const auto ConsideredOwner = eachOf(IsOwnerType, CreatesOwner);
// Find delete expressions that delete non-owners.
Finder->addMatcher(
@@ -43,6 +79,21 @@ void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) {
.bind("delete_expr"),
this);
+ // Ignoring the implicit casts is vital because the legacy owners do not work
+ // with the 'owner<>' annotation and therefore always implicitly cast to the
+ // legacy type (even 'void *').
+ //
+ // Furthermore, legacy owner functions are assumed to use raw pointers for
+ // resources. This check assumes that all pointer arguments of a legacy
+ // functions shall be 'gsl::owner<>'.
+ Finder->addMatcher(
+ callExpr(
+ allOf(callee(LegacyOwnerConsumers),
+ hasAnyArgument(allOf(unless(ignoringImpCasts(ConsideredOwner)),
+ hasType(pointerType())))))
+ .bind("legacy_consumer"),
+ this);
+
// Matching assignment to owners, with the rhs not being an owner nor creating
// one.
Finder->addMatcher(binaryOperator(allOf(matchers::isAssignmentOperator(),
@@ -133,6 +184,7 @@ void OwningMemoryCheck::check(const MatchFinder::MatchResult &Result) {
bool CheckExecuted = false;
CheckExecuted |= handleDeletion(Nodes);
+ CheckExecuted |= handleLegacyConsumers(Nodes);
CheckExecuted |= handleExpectedOwner(Nodes);
CheckExecuted |= handleAssignmentAndInit(Nodes);
CheckExecuted |= handleAssignmentFromNewOwner(Nodes);
@@ -168,6 +220,22 @@ bool OwningMemoryCheck::handleDeletion(const BoundNodes &Nodes) {
return false;
}
+bool OwningMemoryCheck::handleLegacyConsumers(const BoundNodes &Nodes) {
+ // Result of matching for legacy consumer-functions like `::free()`.
+ const auto *LegacyConsumer = Nodes.getNodeAs<CallExpr>("legacy_consumer");
+
+ // FIXME: `freopen` should be handled seperately because it takes the filename
+ // as a pointer, which should not be an owner. The argument that is an owner
+ // is known and the false positive coming from the filename can be avoided.
+ if (LegacyConsumer) {
+ diag(LegacyConsumer->getLocStart(),
+ "calling legacy resource function without passing a 'gsl::owner<>'")
+ << LegacyConsumer->getSourceRange();
+ return true;
+ }
+ return false;
+}
+
bool OwningMemoryCheck::handleExpectedOwner(const BoundNodes &Nodes) {
// Result of function call matchers.
const auto *ExpectedOwner = Nodes.getNodeAs<Expr>("expected_owner_argument");
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.h
index 60c40bc710b..e68e4c09b12 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.h
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.h
@@ -24,17 +24,36 @@ namespace cppcoreguidelines {
class OwningMemoryCheck : public ClangTidyCheck {
public:
OwningMemoryCheck(StringRef Name, ClangTidyContext *Context)
- : ClangTidyCheck(Name, Context) {}
+ : ClangTidyCheck(Name, Context),
+ LegacyResourceProducers(Options.get(
+ "LegacyResourceProducers", "::malloc;::aligned_alloc;::realloc;"
+ "::calloc;::fopen;::freopen;::tmpfile")),
+ LegacyResourceConsumers(Options.get(
+ "LegacyResourceConsumers", "::free;::realloc;::freopen;::fclose")) {
+ }
+
+ /// Make configuration of checker discoverable.
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
private:
bool handleDeletion(const ast_matchers::BoundNodes &Nodes);
+ bool handleLegacyConsumers(const ast_matchers::BoundNodes &Nodes);
bool handleExpectedOwner(const ast_matchers::BoundNodes &Nodes);
bool handleAssignmentAndInit(const ast_matchers::BoundNodes &Nodes);
bool handleAssignmentFromNewOwner(const ast_matchers::BoundNodes &Nodes);
bool handleReturnValues(const ast_matchers::BoundNodes &Nodes);
bool handleOwnerMembers(const ast_matchers::BoundNodes &Nodes);
+
+ /// List of old C-style functions that create resources.
+ /// Defaults to
+ /// `::malloc;::aligned_alloc;::realloc;::calloc;::fopen;::freopen;::tmpfile`.
+ const std::string LegacyResourceProducers;
+ /// List of old C-style functions that consume or release resources.
+ /// Defaults to `::free;::realloc;::freopen;::fclose`.
+ const std::string LegacyResourceConsumers;
};
} // namespace cppcoreguidelines
OpenPOWER on IntegriCloud