78de751969
add self-check looking for #In markup on every method, pointing to an existing #Subtopic to reference the method. Docs-Preview: https://skia.org/?cl=104325 Bug: skia:6898 Change-Id: I749a25b9a43033ae68d193249b2c0b810dcf8fc8 Reviewed-on: https://skia-review.googlesource.com/104325 Commit-Queue: Cary Clark <caryclark@skia.org> Reviewed-by: Cary Clark <caryclark@skia.org>
157 lines
4.6 KiB
C++
157 lines
4.6 KiB
C++
/*
|
|
* Copyright 2018 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "bookmaker.h"
|
|
|
|
#ifdef SK_BUILD_FOR_WIN
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
|
|
/* SkDebugf works in both visual studio and git shell, but
|
|
in git shell output is not piped to grep.
|
|
printf does not generate output in visual studio, but
|
|
does in git shell and can be piped.
|
|
*/
|
|
#ifdef SK_BUILD_FOR_WIN
|
|
#define PRINTF(...) \
|
|
do { \
|
|
if (IsDebuggerPresent()) { \
|
|
SkDebugf(__VA_ARGS__); \
|
|
} else { \
|
|
printf(__VA_ARGS__); \
|
|
} \
|
|
} while (false)
|
|
#else
|
|
#define PRINTF(...) \
|
|
printf(__VA_ARGS__)
|
|
#endif
|
|
|
|
|
|
// Check that mutiple like-named methods are under one Subtopic
|
|
|
|
// Check that SeeAlso reference each other
|
|
|
|
// Would be nice to check if other classes have 'create' methods that are included
|
|
// SkSurface::makeImageSnapShot should be referenced under SkImage 'creators'
|
|
|
|
class SelfChecker {
|
|
public:
|
|
SelfChecker(const BmhParser& bmh)
|
|
: fBmhParser(bmh)
|
|
{}
|
|
|
|
bool check() {
|
|
for (const auto& topic : fBmhParser.fTopicMap) {
|
|
Definition* topicDef = topic.second;
|
|
if (topicDef->fParent) {
|
|
continue;
|
|
}
|
|
if (!topicDef->isRoot()) {
|
|
return fBmhParser.reportError<bool>("expected root topic");
|
|
}
|
|
fRoot = topicDef->asRoot();
|
|
if (!this->checkSeeAlso()) {
|
|
return false;
|
|
}
|
|
// report functions that are not covered by related hierarchy
|
|
if (!this->checkRelatedFunctions()) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
protected:
|
|
|
|
void checkMethod(string topic, const Definition* csChild, vector<string>* reported) {
|
|
if (MarkType::kSubtopic == csChild->fMarkType) {
|
|
for (auto child : csChild->fChildren) {
|
|
checkMethod(topic, child, reported);
|
|
}
|
|
return;
|
|
} else if (MarkType::kMethod != csChild->fMarkType) {
|
|
// only check methods for now
|
|
return;
|
|
}
|
|
bool containsMarkTypeIn = csChild->fDeprecated // no markup for deprecated
|
|
|| Definition::MethodType::kConstructor == csChild->fMethodType
|
|
|| Definition::MethodType::kDestructor == csChild->fMethodType
|
|
|| Definition::MethodType::kOperator == csChild->fMethodType
|
|
|| csChild->fClone;
|
|
for (auto child : csChild->fChildren) {
|
|
if (MarkType::kIn == child->fMarkType) {
|
|
containsMarkTypeIn = true;
|
|
string subtopic(child->fContentStart,
|
|
child->fContentEnd - child->fContentStart);
|
|
string fullname = topic + '_' + subtopic;
|
|
auto topEnd = fBmhParser.fTopicMap.end();
|
|
auto topFind = fBmhParser.fTopicMap.find(fullname);
|
|
auto reportEnd = reported->end();
|
|
auto reportFind = std::find(reported->begin(), reported->end(), subtopic);
|
|
if (topEnd == topFind) {
|
|
if (reportEnd == reportFind) {
|
|
reported->push_back(subtopic);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!containsMarkTypeIn) {
|
|
PRINTF("No #In: %s\n", csChild->fName.c_str());
|
|
}
|
|
}
|
|
|
|
bool checkRelatedFunctions() {
|
|
const Definition* cs = this->classOrStruct();
|
|
if (!cs) {
|
|
return true;
|
|
}
|
|
const Definition* topic = cs->fParent;
|
|
SkASSERT(topic);
|
|
SkASSERT(MarkType::kTopic == topic->fMarkType);
|
|
string topicName = topic->fName;
|
|
vector<string> methodNames;
|
|
vector<string> reported;
|
|
string prefix = cs->fName + "::";
|
|
for (auto& csChild : cs->fChildren) {
|
|
checkMethod(topicName, csChild, &reported);
|
|
}
|
|
for (auto missing : reported) {
|
|
string fullname = topicName + '_' + missing;
|
|
PRINTF("No #Subtopic: %s\n", fullname.c_str());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool checkSeeAlso() {
|
|
return true;
|
|
}
|
|
|
|
const Definition* classOrStruct() {
|
|
for (auto& rootChild : fRoot->fChildren) {
|
|
if (rootChild->isStructOrClass()) {
|
|
return rootChild;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
enum class Optional {
|
|
kNo,
|
|
kYes,
|
|
};
|
|
|
|
private:
|
|
const BmhParser& fBmhParser;
|
|
RootDefinition* fRoot;
|
|
};
|
|
|
|
bool SelfCheck(const BmhParser& bmh) {
|
|
SelfChecker checker(bmh);
|
|
return checker.check();
|
|
}
|