Home | History | Annotate | Download | only in bookmaker
      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