1 #ifndef CATA_TOOLS_CLANG_TIDY_PLUGIN_UTILS_H
2 #define CATA_TOOLS_CLANG_TIDY_PLUGIN_UTILS_H
3
4 #include <clang/AST/ASTContext.h>
5 #include <clang/AST/ASTTypeTraits.h>
6 #include <clang/AST/Decl.h>
7 #include <clang/AST/DeclCXX.h>
8 #include <clang/AST/ExprCXX.h>
9 #include <clang/ASTMatchers/ASTMatchFinder.h>
10 #include <clang/ASTMatchers/ASTMatchers.h>
11 #include <clang/ASTMatchers/ASTMatchersInternal.h>
12 #include <clang/Basic/LLVM.h>
13 #include <clang/Basic/SourceLocation.h>
14 #include <clang/Lex/Lexer.h>
15 #include <llvm/ADT/StringRef.h>
16 #include <llvm/Support/Casting.h>
17 #include <string>
18
19 namespace clang
20 {
21 class Decl;
22 class Stmt;
23
24 namespace tidy
25 {
26 namespace cata
27 {
28
getText(const ast_matchers::MatchFinder::MatchResult & Result,SourceRange Range)29 inline StringRef getText(
30 const ast_matchers::MatchFinder::MatchResult &Result, SourceRange Range )
31 {
32 return Lexer::getSourceText( CharSourceRange::getTokenRange( Range ),
33 *Result.SourceManager,
34 Result.Context->getLangOpts() );
35 }
36
37 template <typename T>
getText(const ast_matchers::MatchFinder::MatchResult & Result,T * Node)38 inline StringRef getText( const ast_matchers::MatchFinder::MatchResult &Result, T *Node )
39 {
40 if( const CXXDefaultArgExpr *Default = dyn_cast<clang::CXXDefaultArgExpr>( Node ) ) {
41 return getText( Result, Default->getExpr() );
42 }
43 return getText( Result, Node->getSourceRange() );
44 }
45
46 template<typename T, typename U>
getParent(const ast_matchers::MatchFinder::MatchResult & Result,const U * Node)47 static const T *getParent( const ast_matchers::MatchFinder::MatchResult &Result, const U *Node )
48 {
49 for( const ast_type_traits::DynTypedNode &parent : Result.Context->getParents( *Node ) ) {
50 if( const T *Candidate = parent.get<T>() ) {
51 return Candidate;
52 }
53 }
54
55 return nullptr;
56 }
57
58 template<typename T>
getContainingFunction(const ast_matchers::MatchFinder::MatchResult & Result,const T * Node)59 static const FunctionDecl *getContainingFunction(
60 const ast_matchers::MatchFinder::MatchResult &Result, const T *Node )
61 {
62 for( const ast_type_traits::DynTypedNode &parent : Result.Context->getParents( *Node ) ) {
63 if( const Decl *Candidate = parent.get<Decl>() ) {
64 if( const FunctionDecl *ContainingFunction = dyn_cast<FunctionDecl>( Candidate ) ) {
65 return ContainingFunction;
66 }
67 if( const FunctionDecl *ContainingFunction =
68 getContainingFunction( Result, Candidate ) ) {
69 return ContainingFunction;
70 }
71 }
72 if( const Stmt *Candidate = parent.get<Stmt>() ) {
73 if( const FunctionDecl *ContainingFunction =
74 getContainingFunction( Result, Candidate ) ) {
75 return ContainingFunction;
76 }
77 }
78 }
79
80 return nullptr;
81 }
82
isPointType(const CXXRecordDecl * R)83 inline bool isPointType( const CXXRecordDecl *R )
84 {
85 if( !R ) {
86 return false;
87 }
88 StringRef name = R->getName();
89 return name == "point" || name == "tripoint";
90 }
91
isPointType()92 inline auto isPointType()
93 {
94 using namespace clang::ast_matchers;
95 return cxxRecordDecl( anyOf( hasName( "point" ), hasName( "tripoint" ) ) );
96 }
97
isPointOrCoordPointType()98 inline auto isPointOrCoordPointType()
99 {
100 using namespace clang::ast_matchers;
101 return cxxRecordDecl(
102 anyOf( hasName( "point" ), hasName( "tripoint" ), hasName( "coord_point" ) )
103 );
104 }
105
isPointConstructor()106 inline auto isPointConstructor()
107 {
108 using namespace clang::ast_matchers;
109 return cxxConstructorDecl( ofClass( isPointType() ) );
110 }
111
112 // This returns a matcher that always matches, but binds "temp" if the
113 // constructor call is constructing a temporary object.
testWhetherConstructingTemporary()114 inline auto testWhetherConstructingTemporary()
115 {
116 using namespace clang::ast_matchers;
117 return cxxConstructExpr(
118 anyOf(
119 hasParent( materializeTemporaryExpr().bind( "temp" ) ),
120 hasParent(
121 implicitCastExpr( hasParent( materializeTemporaryExpr().bind( "temp" ) ) )
122 ),
123 hasParent( callExpr().bind( "temp" ) ),
124 hasParent( initListExpr().bind( "temp" ) ),
125 anything()
126 )
127 );
128 }
129
testWhetherParentIsVarDecl()130 inline auto testWhetherParentIsVarDecl()
131 {
132 using namespace clang::ast_matchers;
133 return expr(
134 anyOf(
135 hasParent( varDecl().bind( "parentVarDecl" ) ),
136 anything()
137 )
138 );
139 }
140
testWhetherGrandparentIsTranslationUnitDecl()141 inline auto testWhetherGrandparentIsTranslationUnitDecl()
142 {
143 using namespace clang::ast_matchers;
144 return expr(
145 anyOf(
146 hasParent(
147 varDecl(
148 hasParent( translationUnitDecl().bind( "grandparentTranslationUnit" ) )
149 )
150 ),
151 anything()
152 )
153 );
154 }
155
isXParam()156 inline auto isXParam()
157 {
158 using namespace clang::ast_matchers;
159 return matchesName( "[xX]" );
160 }
161
isYParam()162 inline auto isYParam()
163 {
164 using namespace clang::ast_matchers;
165 return matchesName( "[yY]" );
166 }
167
isPointMethod(const FunctionDecl * d)168 inline bool isPointMethod( const FunctionDecl *d )
169 {
170 if( const CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>( d ) ) {
171 const CXXRecordDecl *Record = Method->getParent();
172 if( isPointType( Record ) ) {
173 return true;
174 }
175 }
176 return false;
177 }
178
179 // Struct to help identify and construct names of associated points and
180 // coordinates
181 class NameConvention
182 {
183 public:
184 explicit NameConvention( StringRef xName );
185
186 enum MatchResult {
187 XName,
188 YName,
189 ZName,
190 None
191 };
192
193 MatchResult Match( StringRef name ) const;
194
195 bool operator!() const {
196 return !valid;
197 }
198
getRoot()199 const std::string &getRoot() const {
200 return root;
201 }
202 private:
203 std::string root;
204 bool capital;
205 bool atEnd;
206 bool valid = true;
207 };
208
209 } // namespace cata
210 } // namespace tidy
211 } // namespace clang
212
213 #endif // CATA_TOOLS_CLANG_TIDY_PLUGIN_UTILS_H
214