diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp')
-rw-r--r-- | clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp b/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp new file mode 100644 index 00000000000..48eee8e6949 --- /dev/null +++ b/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp @@ -0,0 +1,74 @@ +//===--- DefaultOperatorNewCheck.cpp - clang-tidy --------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "DefaultOperatorNewAlignmentCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace cert { + +AST_MATCHER(CXXNewExpr, isPlacementNew) { + return Node.getNumPlacementArgs() > 0; +} + +void DefaultOperatorNewAlignmentCheck::registerMatchers(MatchFinder *Finder) { + // Check not applicable in C++17 (or newer). + if (getLangOpts().CPlusPlus17) + return; + + Finder->addMatcher(cxxNewExpr(unless(isPlacementNew())).bind("new"), this); +} + +void DefaultOperatorNewAlignmentCheck::check( + const MatchFinder::MatchResult &Result) { + // Get the found 'new' expression. + const auto *NewExpr = Result.Nodes.getNodeAs<CXXNewExpr>("new"); + + QualType T = NewExpr->getAllocatedType(); + // Dependent types do not have fixed alignment. + if (T->isDependentType()) + return; + const TagDecl *D = T->getAsTagDecl(); + // Alignment can not be obtained for undefined type. + if (!D || !D->getDefinition() || !D->isCompleteDefinition()) + return; + + ASTContext &Context = D->getASTContext(); + + // Check if no alignment was specified for the type. + if (!Context.isAlignmentRequired(T)) + return; + + // The user-specified alignment (in bits). + unsigned SpecifiedAlignment = D->getMaxAlignment(); + // Double-check if no alignment was specified. + if (!SpecifiedAlignment) + return; + // The alignment used by default 'operator new' (in bits). + unsigned DefaultNewAlignment = Context.getTargetInfo().getNewAlign(); + + bool OverAligned = SpecifiedAlignment > DefaultNewAlignment; + bool HasDefaultOperatorNew = + !NewExpr->getOperatorNew() || NewExpr->getOperatorNew()->isImplicit(); + + unsigned CharWidth = Context.getTargetInfo().getCharWidth(); + if (HasDefaultOperatorNew && OverAligned) + diag(NewExpr->getBeginLoc(), + "allocation function returns a pointer with alignment %0 but the " + "over-aligned type being allocated requires alignment %1") + << (DefaultNewAlignment / CharWidth) + << (SpecifiedAlignment / CharWidth); +} + +} // namespace cert +} // namespace tidy +} // namespace clang |