1 #include "JsonTranslationInputCheck.h"
2
3 #include <clang/AST/Decl.h>
4 #include <clang/AST/Expr.h>
5 #include <clang/ASTMatchers/ASTMatchFinder.h>
6 #include <clang/ASTMatchers/ASTMatchers.h>
7 #include <clang/ASTMatchers/ASTMatchersInternal.h>
8 #include <clang/Basic/DiagnosticIDs.h>
9
10 using namespace clang::ast_matchers;
11
12 namespace clang
13 {
14 namespace tidy
15 {
16 namespace cata
17 {
18
registerMatchers(MatchFinder * Finder)19 void JsonTranslationInputCheck::registerMatchers( MatchFinder *Finder )
20 {
21 // <translation function>( ... <json input object>.<method>(...) ... )
22 Finder->addMatcher(
23 callExpr(
24 // <json input object>.<method>
25 callee( cxxMethodDecl(
26 // <json input object>
27 ofClass( hasAnyName( "JsonIn", "JsonArray", "JsonObject" ) )
28 ) ),
29 // <translation function>( ... )
30 hasAncestor(
31 callExpr( callee( decl( anyOf(
32 functionDecl(
33 hasAnyName( "_", "gettext", "pgettext", "ngettext", "npgettext" )
34 ).bind( "translationFunc" ),
35 functionDecl(
36 hasAnyName( "to_translation", "pl_translation" )
37 ) ) ) )
38 // no_translation is ok, it's used to load generated names such as artifact names
39 ).bind( "translationCall" ) )
40 ).bind( "jsonInputCall" ),
41 this
42 );
43 }
44
check(const MatchFinder::MatchResult & Result)45 void JsonTranslationInputCheck::check( const MatchFinder::MatchResult &Result )
46 {
47 const CallExpr *jsonInputCall = Result.Nodes.getNodeAs<CallExpr>( "jsonInputCall" );
48 const CallExpr *translationCall = Result.Nodes.getNodeAs<CallExpr>( "translationCall" );
49 if( jsonInputCall && translationCall ) {
50 const FunctionDecl *translationFunc = Result.Nodes.getNodeAs<FunctionDecl>( "translationFunc" );
51 if( translationFunc ) {
52 diag(
53 translationCall->getBeginLoc(),
54 "immediately translating a value read from json causes translation "
55 "updating issues. Consider reading into a translation object instead."
56 );
57 diag(
58 jsonInputCall->getBeginLoc(),
59 "value read from json",
60 DiagnosticIDs::Note
61 );
62 } else {
63 diag(
64 translationCall->getBeginLoc(),
65 "read translation directly instead of constructing it from "
66 "json strings to ensure consistent format in json."
67 );
68 diag(
69 jsonInputCall->getBeginLoc(),
70 "string read from json",
71 DiagnosticIDs::Note
72 );
73 }
74 }
75 }
76
77 } // namespace cata
78 } // namespace tidy
79 } // namespace clang
80