blob: 5f1eb38ece73b98a8fc0450d236fe172d91c3a7e [file] [log] [blame]
Cary Clarkac47b882018-01-11 10:35:44 -05001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "bookmaker.h"
9
Cary Clark4855f782018-02-06 09:41:53 -050010#ifdef SK_BUILD_FOR_WIN
11#include <windows.h>
12#endif
Cary Clarkac47b882018-01-11 10:35:44 -050013
Cary Clark78de7512018-02-07 07:27:09 -050014
15 /* SkDebugf works in both visual studio and git shell, but
16 in git shell output is not piped to grep.
17 printf does not generate output in visual studio, but
18 does in git shell and can be piped.
19 */
20#ifdef SK_BUILD_FOR_WIN
21#define PRINTF(...) \
22do { \
23 if (IsDebuggerPresent()) { \
24 SkDebugf(__VA_ARGS__); \
25 } else { \
26 printf(__VA_ARGS__); \
27 } \
28} while (false)
29#else
30#define PRINTF(...) \
31 printf(__VA_ARGS__)
32#endif
33
34
Cary Clarkac47b882018-01-11 10:35:44 -050035// Check that mutiple like-named methods are under one Subtopic
36
Cary Clarkac47b882018-01-11 10:35:44 -050037// Check that SeeAlso reference each other
38
39// Would be nice to check if other classes have 'create' methods that are included
40// SkSurface::makeImageSnapShot should be referenced under SkImage 'creators'
41
42class SelfChecker {
43public:
44 SelfChecker(const BmhParser& bmh)
45 : fBmhParser(bmh)
46 {}
47
48 bool check() {
49 for (const auto& topic : fBmhParser.fTopicMap) {
50 Definition* topicDef = topic.second;
51 if (topicDef->fParent) {
52 continue;
53 }
54 if (!topicDef->isRoot()) {
55 return fBmhParser.reportError<bool>("expected root topic");
56 }
57 fRoot = topicDef->asRoot();
Cary Clarkac47b882018-01-11 10:35:44 -050058 if (!this->checkSeeAlso()) {
59 return false;
60 }
Cary Clark4855f782018-02-06 09:41:53 -050061 // report functions that are not covered by related hierarchy
Cary Clarkab2621d2018-01-30 10:08:57 -050062 if (!this->checkRelatedFunctions()) {
63 return false;
64 }
Cary Clarkac47b882018-01-11 10:35:44 -050065 }
66 return true;
67 }
68
69protected:
Cary Clarkac47b882018-01-11 10:35:44 -050070
Cary Clark78de7512018-02-07 07:27:09 -050071 void checkMethod(string topic, const Definition* csChild, vector<string>* reported) {
72 if (MarkType::kSubtopic == csChild->fMarkType) {
73 for (auto child : csChild->fChildren) {
74 checkMethod(topic, child, reported);
75 }
76 return;
77 } else if (MarkType::kMethod != csChild->fMarkType) {
78 // only check methods for now
79 return;
80 }
81 bool containsMarkTypeIn = csChild->fDeprecated // no markup for deprecated
82 || Definition::MethodType::kConstructor == csChild->fMethodType
83 || Definition::MethodType::kDestructor == csChild->fMethodType
84 || Definition::MethodType::kOperator == csChild->fMethodType
85 || csChild->fClone;
86 for (auto child : csChild->fChildren) {
87 if (MarkType::kIn == child->fMarkType) {
88 containsMarkTypeIn = true;
89 string subtopic(child->fContentStart,
90 child->fContentEnd - child->fContentStart);
91 string fullname = topic + '_' + subtopic;
92 auto topEnd = fBmhParser.fTopicMap.end();
93 auto topFind = fBmhParser.fTopicMap.find(fullname);
94 auto reportEnd = reported->end();
95 auto reportFind = std::find(reported->begin(), reported->end(), subtopic);
96 if (topEnd == topFind) {
97 if (reportEnd == reportFind) {
98 reported->push_back(subtopic);
Cary Clark4855f782018-02-06 09:41:53 -050099 }
100 }
Cary Clark78de7512018-02-07 07:27:09 -0500101 }
102 }
103 if (!containsMarkTypeIn) {
104 PRINTF("No #In: %s\n", csChild->fName.c_str());
105 }
106 }
107
108 bool checkRelatedFunctions() {
109 const Definition* cs = this->classOrStruct();
110 if (!cs) {
111 return true;
112 }
113 const Definition* topic = cs->fParent;
114 SkASSERT(topic);
115 SkASSERT(MarkType::kTopic == topic->fMarkType);
116 string topicName = topic->fName;
117 vector<string> methodNames;
118 vector<string> reported;
119 string prefix = cs->fName + "::";
120 for (auto& csChild : cs->fChildren) {
121 checkMethod(topicName, csChild, &reported);
Cary Clarkab2621d2018-01-30 10:08:57 -0500122 }
Cary Clark78de7512018-02-07 07:27:09 -0500123 for (auto missing : reported) {
124 string fullname = topicName + '_' + missing;
125 PRINTF("No #Subtopic: %s\n", fullname.c_str());
126 }
Cary Clarkab2621d2018-01-30 10:08:57 -0500127 return true;
128 }
129
Cary Clarkac47b882018-01-11 10:35:44 -0500130 bool checkSeeAlso() {
131 return true;
132 }
133
Cary Clarkab2621d2018-01-30 10:08:57 -0500134 const Definition* classOrStruct() {
135 for (auto& rootChild : fRoot->fChildren) {
Cary Clark08895c42018-02-01 09:37:32 -0500136 if (rootChild->isStructOrClass()) {
Cary Clarkab2621d2018-01-30 10:08:57 -0500137 return rootChild;
138 }
139 }
140 return nullptr;
141 }
142
Cary Clark2dc84ad2018-01-26 12:56:22 -0500143 enum class Optional {
144 kNo,
145 kYes,
146 };
147
Cary Clarkac47b882018-01-11 10:35:44 -0500148private:
149 const BmhParser& fBmhParser;
150 RootDefinition* fRoot;
151};
152
153bool SelfCheck(const BmhParser& bmh) {
154 SelfChecker checker(bmh);
155 return checker.check();
156}