1 #include "PointInitializationCheck.h"
2
3 #include <clang/AST/Decl.h>
4 #include <clang/AST/DeclCXX.h>
5 #include <clang/AST/Expr.h>
6 #include <clang/AST/Type.h>
7 #include <clang/ASTMatchers/ASTMatchFinder.h>
8 #include <clang/ASTMatchers/ASTMatchers.h>
9 #include <clang/ASTMatchers/ASTMatchersInternal.h>
10 #include <clang/Basic/Diagnostic.h>
11
12 #include "Utils.h"
13
14 using namespace clang::ast_matchers;
15
16 namespace clang
17 {
18 namespace tidy
19 {
20 namespace cata
21 {
registerMatchers(MatchFinder * Finder)22 void PointInitializationCheck::registerMatchers( MatchFinder *Finder )
23 {
24 using CxxConstructorMatcher = clang::ast_matchers::internal::Matcher<Expr>;
25 const CxxConstructorMatcher ZeroConstructor = cxxConstructExpr( anyOf(
26 allOf(
27 argumentCountIs( 1 ),
28 hasArgument( 0, declRefExpr( to( varDecl(
29 anyOf( hasName( "point_zero" ), hasName( "tripoint_zero" ) )
30 ) ) ) ) ),
31 allOf(
32 hasArgument( 0, integerLiteral( equals( 0 ) ) ),
33 hasArgument( 1, integerLiteral( equals( 0 ) ) ),
34 anyOf(
35 argumentCountIs( 2 ),
36 allOf(
37 hasArgument( 2, integerLiteral( equals( 0 ) ) ),
38 argumentCountIs( 3 )
39 )
40 )
41 )
42 ) ).bind( "expr" );
43 Finder->addMatcher( varDecl(
44 unless( parmVarDecl() ),
45 hasType( isPointType() ),
46 hasInitializer( ZeroConstructor )
47 ).bind( "decl" ), this );
48 Finder->addMatcher( cxxCtorInitializer(
49 forField( hasType( isPointType() ) ),
50 withInitializer( ZeroConstructor )
51 ).bind( "init" ), this );
52 }
53
CheckDecl(PointInitializationCheck & Check,const MatchFinder::MatchResult & Result)54 static void CheckDecl( PointInitializationCheck &Check, const MatchFinder::MatchResult &Result )
55 {
56 const VarDecl *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>( "decl" );
57 if( !MatchedDecl ) {
58 return;
59 }
60 const Expr *MatchedExpr = Result.Nodes.getNodeAs<Expr>( "expr" );
61 if( !MatchedExpr ) {
62 return;
63 }
64 QualType Type = MatchedDecl->getType();
65 PrintingPolicy Policy( LangOptions{} );
66 Policy.adjustForCPlusPlus();
67 Type.removeLocalConst();
68 std::string Replacement = Type.getAsString( Policy ) + " " + MatchedDecl->getNameAsString();
69 SourceRange ToReplace( MatchedDecl->getTypeSpecStartLoc(), MatchedDecl->getEndLoc() );
70 Check.diag(
71 MatchedExpr->getBeginLoc(),
72 "Unnecessary initialization of %0. %1 is zero-initialized by default." )
73 << MatchedDecl << Type
74 << FixItHint::CreateReplacement( ToReplace, Replacement );
75 }
76
CheckInit(PointInitializationCheck & Check,const MatchFinder::MatchResult & Result)77 static void CheckInit( PointInitializationCheck &Check, const MatchFinder::MatchResult &Result )
78 {
79 const CXXCtorInitializer *MatchedInit = Result.Nodes.getNodeAs<CXXCtorInitializer>( "init" );
80 if( !MatchedInit ) {
81 return;
82 }
83 FieldDecl *Member = MatchedInit->getMember();
84 if( !Member ) {
85 return;
86 }
87 QualType Type = Member->getType();
88 Check.diag(
89 MatchedInit->getInit()->getBeginLoc(),
90 "Unnecessary initialization of %0. %1 is zero-initialized by default." ) <<
91 Member << Type;
92 }
93
check(const MatchFinder::MatchResult & Result)94 void PointInitializationCheck::check( const MatchFinder::MatchResult &Result )
95 {
96 CheckDecl( *this, Result );
97 CheckInit( *this, Result );
98 }
99
100 } // namespace cata
101 } // namespace tidy
102 } // namespace clang
103