blob: 1193e0404a0ffa21256b18be592aee55c5b0ef71 [file] [log] [blame]
//===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/CommentSema.h"
#include "llvm/ADT/StringSwitch.h"
namespace clang {
namespace comments {
Sema::Sema(llvm::BumpPtrAllocator &Allocator) :
Allocator(Allocator) {
}
ParagraphComment *Sema::actOnParagraphComment(
ArrayRef<InlineContentComment *> Content) {
return new (Allocator) ParagraphComment(Content);
}
BlockCommandComment *Sema::actOnBlockCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Name) {
return new (Allocator) BlockCommandComment(LocBegin, LocEnd, Name);
}
BlockCommandComment *Sema::actOnBlockCommandArgs(
BlockCommandComment *Command,
ArrayRef<BlockCommandComment::Argument> Args) {
Command->setArgs(Args);
return Command;
}
BlockCommandComment *Sema::actOnBlockCommandFinish(
BlockCommandComment *Command,
ParagraphComment *Paragraph) {
Command->setParagraph(Paragraph);
return Command;
}
ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Name) {
return new (Allocator) ParamCommandComment(LocBegin, LocEnd, Name);
}
ParamCommandComment *Sema::actOnParamCommandArg(ParamCommandComment *Command,
SourceLocation ArgLocBegin,
SourceLocation ArgLocEnd,
StringRef Arg,
bool IsDirection) {
if (IsDirection) {
ParamCommandComment::PassDirection Direction;
std::string ArgLower = Arg.lower();
// TODO: optimize: lower Name first (need an API in SmallString for that),
// after that StringSwitch.
if (ArgLower == "[in]")
Direction = ParamCommandComment::In;
else if (ArgLower == "[out]")
Direction = ParamCommandComment::Out;
else if (ArgLower == "[in,out]" || ArgLower == "[out,in]")
Direction = ParamCommandComment::InOut;
else {
// Remove spaces.
std::string::iterator O = ArgLower.begin();
for (std::string::iterator I = ArgLower.begin(), E = ArgLower.end();
I != E; ++I) {
const char C = *I;
if (C != ' ' && C != '\n' && C != '\r' &&
C != '\t' && C != '\v' && C != '\f')
*O++ = C;
}
ArgLower.resize(O - ArgLower.begin());
bool RemovingWhitespaceHelped = false;
if (ArgLower == "[in]") {
Direction = ParamCommandComment::In;
RemovingWhitespaceHelped = true;
} else if (ArgLower == "[out]") {
Direction = ParamCommandComment::Out;
RemovingWhitespaceHelped = true;
} else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") {
Direction = ParamCommandComment::InOut;
RemovingWhitespaceHelped = true;
} else {
Direction = ParamCommandComment::In;
RemovingWhitespaceHelped = false;
}
// Diag() unrecognized parameter passing direction, valid directions are ...
// if (RemovingWhitespaceHelped) FixIt
}
Command->setDirection(Direction, /* Explicit = */ true);
} else {
if (Command->getArgCount() == 0) {
if (!Command->isDirectionExplicit()) {
// User didn't provide a direction argument.
Command->setDirection(ParamCommandComment::In, /* Explicit = */ false);
}
typedef BlockCommandComment::Argument Argument;
Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
ArgLocEnd),
Arg);
Command->setArgs(llvm::makeArrayRef(A, 1));
// if (...) Diag() unrecognized parameter name
} else {
// Diag() \\param command requires at most 2 arguments
}
}
return Command;
}
ParamCommandComment *Sema::actOnParamCommandFinish(ParamCommandComment *Command,
ParagraphComment *Paragraph) {
Command->setParagraph(Paragraph);
return Command;
}
InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
SourceLocation CommandLocEnd,
StringRef CommandName) {
ArrayRef<InlineCommandComment::Argument> Args;
return new (Allocator) InlineCommandComment(CommandLocBegin,
CommandLocEnd,
CommandName,
Args);
}
InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
SourceLocation CommandLocEnd,
StringRef CommandName,
SourceLocation ArgLocBegin,
SourceLocation ArgLocEnd,
StringRef Arg) {
typedef InlineCommandComment::Argument Argument;
Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
ArgLocEnd),
Arg);
return new (Allocator) InlineCommandComment(CommandLocBegin,
CommandLocEnd,
CommandName,
llvm::makeArrayRef(A, 1));
}
InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Name) {
ArrayRef<InlineCommandComment::Argument> Args;
return new (Allocator) InlineCommandComment(LocBegin, LocEnd, Name, Args);
}
TextComment *Sema::actOnText(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Text) {
return new (Allocator) TextComment(LocBegin, LocEnd, Text);
}
VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc,
StringRef Name) {
return new (Allocator) VerbatimBlockComment(
Loc,
Loc.getLocWithOffset(1 + Name.size()),
Name);
}
VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc,
StringRef Text) {
return new (Allocator) VerbatimBlockLineComment(Loc, Text);
}
VerbatimBlockComment *Sema::actOnVerbatimBlockFinish(
VerbatimBlockComment *Block,
SourceLocation CloseNameLocBegin,
StringRef CloseName,
ArrayRef<VerbatimBlockLineComment *> Lines) {
Block->setCloseName(CloseName, CloseNameLocBegin);
Block->setLines(Lines);
return Block;
}
VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
StringRef Name,
SourceLocation TextBegin,
StringRef Text) {
return new (Allocator) VerbatimLineComment(
LocBegin,
TextBegin.getLocWithOffset(Text.size()),
Name,
TextBegin,
Text);
}
HTMLOpenTagComment *Sema::actOnHTMLOpenTagStart(SourceLocation LocBegin,
StringRef TagName) {
return new (Allocator) HTMLOpenTagComment(LocBegin, TagName);
}
HTMLOpenTagComment *Sema::actOnHTMLOpenTagFinish(
HTMLOpenTagComment *Tag,
ArrayRef<HTMLOpenTagComment::Attribute> Attrs,
SourceLocation GreaterLoc) {
Tag->setAttrs(Attrs);
Tag->setGreaterLoc(GreaterLoc);
return Tag;
}
HTMLCloseTagComment *Sema::actOnHTMLCloseTag(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef TagName) {
return new (Allocator) HTMLCloseTagComment(LocBegin, LocEnd, TagName);
}
FullComment *Sema::actOnFullComment(
ArrayRef<BlockContentComment *> Blocks) {
return new (Allocator) FullComment(Blocks);
}
// TODO: tablegen
bool Sema::isBlockCommand(StringRef Name) {
return llvm::StringSwitch<bool>(Name)
.Case("brief", true)
.Case("result", true)
.Case("return", true)
.Case("returns", true)
.Case("author", true)
.Case("authors", true)
.Case("pre", true)
.Case("post", true)
.Default(false) || isParamCommand(Name);
}
bool Sema::isParamCommand(StringRef Name) {
return llvm::StringSwitch<bool>(Name)
.Case("param", true)
.Case("arg", true)
.Default(false);
}
unsigned Sema::getBlockCommandNumArgs(StringRef Name) {
return llvm::StringSwitch<unsigned>(Name)
.Case("brief", 0)
.Case("pre", 0)
.Case("post", 0)
.Case("author", 0)
.Case("authors", 0)
.Default(0);
}
bool Sema::isInlineCommand(StringRef Name) {
return llvm::StringSwitch<bool>(Name)
.Case("c", true)
.Case("em", true)
.Default(false);
}
bool Sema::HTMLOpenTagNeedsClosing(StringRef Name) {
return llvm::StringSwitch<bool>(Name)
.Case("br", true)
.Default(true);
}
} // end namespace comments
} // end namespace clang