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