1 /* 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 10 #ifdef SK_BUILD_FOR_WIN 11 #include <windows.h> 12 #endif 13 14 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(...) \ 22 do { \ 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 35 // Check that mutiple like-named methods are under one Subtopic 36 37 // 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 42 class SelfChecker { 43 public: 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(); 58 if (!this->checkSeeAlso()) { 59 return false; 60 } 61 // report functions that are not covered by related hierarchy 62 if (!this->checkRelatedFunctions()) { 63 return false; 64 } 65 } 66 return true; 67 } 68 69 protected: 70 71 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); 99 } 100 } 101 } 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); 122 } 123 for (auto missing : reported) { 124 string fullname = topicName + '_' + missing; 125 PRINTF("No #Subtopic: %s\n", fullname.c_str()); 126 } 127 return true; 128 } 129 130 bool checkSeeAlso() { 131 return true; 132 } 133 134 const Definition* classOrStruct() { 135 for (auto& rootChild : fRoot->fChildren) { 136 if (rootChild->isStructOrClass()) { 137 return rootChild; 138 } 139 } 140 return nullptr; 141 } 142 143 enum class Optional { 144 kNo, 145 kYes, 146 }; 147 148 private: 149 const BmhParser& fBmhParser; 150 RootDefinition* fRoot; 151 }; 152 153 bool SelfCheck(const BmhParser& bmh) { 154 SelfChecker checker(bmh); 155 return checker.check(); 156 } 157