mirror of
https://github.com/dlang/tools.git
synced 2025-04-27 21:51:44 +03:00
88 lines
2.8 KiB
D
88 lines
2.8 KiB
D
/*
|
|
* Shared methods between style checkers
|
|
*
|
|
* Copyright (C) 2016 by D Language Foundation
|
|
*
|
|
* Distributed under the Boost Software License, Version 1.0.
|
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
|
* http://www.boost.org/LICENSE_1_0.txt)
|
|
*/
|
|
// Written in the D programming language.
|
|
|
|
import dparse.ast;
|
|
import std.algorithm;
|
|
import std.ascii : whitespace;
|
|
import std.conv : to;
|
|
import std.experimental.logger;
|
|
import std.range;
|
|
import std.stdio : File;
|
|
|
|
bool hasDdocHeader(const(ubyte)[] sourceCode, const Declaration decl)
|
|
{
|
|
import std.algorithm.comparison : min;
|
|
|
|
bool hasComment;
|
|
size_t firstPos = size_t.max;
|
|
|
|
if (decl.unittest_ !is null)
|
|
{
|
|
firstPos = decl.unittest_.location;
|
|
hasComment = decl.unittest_.comment.length > 0;
|
|
}
|
|
else if (decl.functionDeclaration !is null)
|
|
{
|
|
// skip the return type
|
|
firstPos = sourceCode.skipPreviousWord(decl.functionDeclaration.name.index);
|
|
if (auto stClasses = decl.functionDeclaration.storageClasses)
|
|
firstPos = min(firstPos, stClasses[0].token.index);
|
|
hasComment = decl.functionDeclaration.comment.length > 0;
|
|
}
|
|
else if (decl.templateDeclaration !is null)
|
|
{
|
|
// skip the word `template`
|
|
firstPos = sourceCode.skipPreviousWord(decl.templateDeclaration.name.index);
|
|
hasComment = decl.templateDeclaration.comment.length > 0;
|
|
}
|
|
|
|
// libdparse will put any ddoc comment with at least one character in the comment field
|
|
if (hasComment)
|
|
return true;
|
|
|
|
firstPos = min(firstPos, getAttributesStartLocation(decl.attributes));
|
|
|
|
// scan the previous line for ddoc header -> skip to last real character
|
|
auto prevLine = sourceCode[0 .. firstPos].retro.find!(c => whitespace.countUntil(c) < 0);
|
|
|
|
// if there is no comment annotation, only three possible cases remain.
|
|
// one line ddoc: ///, multi-line comments: /** */ or /++ +/
|
|
return prevLine.filter!(c => !whitespace.canFind(c)).startsWith("///", "/+++/", "/***/") > 0;
|
|
}
|
|
|
|
/**
|
|
The location of unittest token is known, but there might be attributes preceding it.
|
|
*/
|
|
private size_t getAttributesStartLocation(const Attribute[] attrs)
|
|
{
|
|
import dparse.lexer : tok;
|
|
|
|
if (attrs.length == 0)
|
|
return size_t.max;
|
|
|
|
if (attrs[0].atAttribute !is null)
|
|
return attrs[0].atAttribute.startLocation;
|
|
|
|
if (attrs[0].attribute != tok!"")
|
|
return attrs[0].attribute.index;
|
|
|
|
return size_t.max;
|
|
}
|
|
|
|
private size_t skipPreviousWord(const(ubyte)[] sourceCode, size_t index)
|
|
{
|
|
return index - sourceCode[0 .. index]
|
|
.retro
|
|
.enumerate
|
|
.find!(c => !whitespace.canFind(c.value))
|
|
.find!(c => whitespace.canFind(c.value))
|
|
.front.index;
|
|
}
|