-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathKeyPathsAffectingVisitor.cpp
76 lines (56 loc) · 2.1 KB
/
KeyPathsAffectingVisitor.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//
// KeyPathsAffectingVisitor.cpp
// Created by Jonathon Mah on 2014-05-11.
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
#include "KeyPathsAffectingVisitor.h"
using namespace clang;
class ReturnSetVisitor : public RecursiveASTVisitor<ReturnSetVisitor> {
KeyPathValidationConsumer *Consumer;
QualType Type;
llvm::SmallSet<Selector, 2> *SetConstructorSelectors;
public:
ReturnSetVisitor(KeyPathValidationConsumer *Consumer, QualType Type, llvm::SmallSet<Selector, 2> *Selectors)
: Consumer(Consumer)
, Type(Type)
, SetConstructorSelectors(Selectors)
{}
bool VisitStmt(const Stmt *Node);
};
bool KeyPathsAffectingVisitor::VisitObjCMethodDecl(ObjCMethodDecl *D) {
if (!D->isClassMethod())
return true;
std::string Name = D->getNameAsString();
if (Name.length() <= Prefix.length() || !std::equal(Prefix.begin(), Prefix.end(), Name.begin()))
return true;
ASTContext &Context = Compiler.getASTContext();
QualType Type = Context.getObjCObjectPointerType(Context.getObjCInterfaceType(D->getClassInterface()));
ReturnSetVisitor(Consumer, Type, &SetConstructorSelectors).TraverseDecl(D);
return true;
}
bool ReturnSetVisitor::VisitStmt(const Stmt *Node) {
const ReturnStmt *Return = dyn_cast<ReturnStmt>(Node);
if (!Return)
return true;
const ObjCMessageExpr *E = dyn_cast<ObjCMessageExpr>(Return->getRetValue()->IgnoreImplicit());
if (!E)
return true;
QualType ClassReceiver = E->getClassReceiver();
if (ClassReceiver.isNull() || ClassReceiver.getAsString() != "NSSet")
return true;
if (!SetConstructorSelectors->count(E->getSelector()))
return true;
for (unsigned I = 0, N = E->getNumArgs(); I < N; ++I)
{
const Expr *Arg = E->getArg(I)->IgnoreImplicit();
const ObjCStringLiteral *KeyPathLiteral = dyn_cast<ObjCStringLiteral>(Arg);
if (!KeyPathLiteral)
continue;
Consumer->emitDiagnosticsForTypeAndKeyPath(Type, Arg, true);
const StringRef KeyPathString = KeyPathLiteral->getString()->getString();
llvm::outs() << KeyPathString << ", ";
}
return true;
}