Comment Sema: refactor handling of 'ParmVarDecl's and save them in Sema members.

llvm-svn: 160634
This commit is contained in:
Dmitri Gribenko 2012-07-23 17:40:30 +00:00
parent d73e4ce992
commit 4b7f5fe572
2 changed files with 72 additions and 30 deletions

View File

@ -38,8 +38,22 @@ class Sema {
DiagnosticsEngine &Diags;
/// Declaration this comment is attached to.
const Decl *ThisDecl;
/// Parameters that can be referenced by \\param if \c ThisDecl is something
/// that we consider a "function".
/// Contains a valid value if \c IsThisDeclInspected is true.
ArrayRef<const ParmVarDecl *> ParamVars;
/// True if we extracted all important information from \c ThisDecl into
/// \c Sema members.
unsigned IsThisDeclInspected : 1;
/// Is \c ThisDecl something that we consider a "function".
/// Contains a valid value if \c IsThisDeclInspected is true.
unsigned IsFunctionDecl : 1;
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
return Diags.Report(Loc, DiagID);
}
@ -140,16 +154,21 @@ public:
void checkBlockCommandEmptyParagraph(BlockCommandComment *Command);
bool isFunctionDecl();
ArrayRef<const ParmVarDecl *> getParamVars();
/// Extract all important semantic information from \c ThisDecl into
/// \c Sema members.
void inspectThisDecl();
/// Returns index of a function parameter with a given name.
unsigned resolveParmVarReference(StringRef Name,
const ParmVarDecl * const *ParamVars,
unsigned NumParams);
ArrayRef<const ParmVarDecl *> ParamVars);
/// Returns index of a function parameter with the name closest to a given
/// typo.
unsigned correctTypoInParmVarReference(StringRef Typo,
const ParmVarDecl * const *ParamVars,
unsigned NumParams);
ArrayRef<const ParmVarDecl *> ParamVars);
bool isBlockCommand(StringRef Name);
bool isParamCommand(StringRef Name);

View File

@ -19,7 +19,8 @@ namespace comments {
Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
DiagnosticsEngine &Diags) :
Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), ThisDecl(NULL) {
Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), ThisDecl(NULL),
IsThisDeclInspected(false) {
}
void Sema::setDecl(const Decl *D) {
@ -58,8 +59,7 @@ ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin,
ParamCommandComment *Command =
new (Allocator) ParamCommandComment(LocBegin, LocEnd, Name);
if (!ThisDecl ||
!(isa<FunctionDecl>(ThisDecl) || isa<ObjCMethodDecl>(ThisDecl)))
if (!isFunctionDecl())
Diag(Command->getLocation(),
diag::warn_doc_param_not_attached_to_a_function_decl)
<< Command->getCommandNameRange();
@ -142,25 +142,15 @@ ParamCommandComment *Sema::actOnParamCommandParamNameArg(
Arg);
Command->setArgs(llvm::makeArrayRef(A, 1));
if (!ThisDecl)
return Command;
const ParmVarDecl * const *ParamVars;
unsigned NumParams;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ThisDecl)) {
ParamVars = FD->param_begin();
NumParams = FD->getNumParams();
} else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ThisDecl)) {
ParamVars = MD->param_begin();
NumParams = MD->param_size();
} else {
if (!isFunctionDecl()) {
// We already warned that this \\param is not attached to a function decl.
return Command;
}
ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
// Check that referenced parameter name is in the function decl.
const unsigned ResolvedParamIndex = resolveParmVarReference(Arg, ParamVars,
NumParams);
const unsigned ResolvedParamIndex = resolveParmVarReference(Arg, ParamVars);
if (ResolvedParamIndex != ParamCommandComment::InvalidParamIndex) {
Command->setParamIndex(ResolvedParamIndex);
return Command;
@ -171,14 +161,13 @@ ParamCommandComment *Sema::actOnParamCommandParamNameArg(
<< Arg << ArgRange;
unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
if (NumParams == 1) {
if (ParamVars.size() == 1) {
// If function has only one parameter then only that parameter
// can be documented.
CorrectedParamIndex = 0;
} else {
// Do typo correction.
CorrectedParamIndex = correctTypoInParmVarReference(Arg, ParamVars,
NumParams);
CorrectedParamIndex = correctTypoInParmVarReference(Arg, ParamVars);
}
if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
const ParmVarDecl *CorrectedPVD = ParamVars[CorrectedParamIndex];
@ -362,6 +351,7 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
FullComment *Sema::actOnFullComment(
ArrayRef<BlockContentComment *> Blocks) {
SmallVector<ParamCommandComment *, 8> Params;
return new (Allocator) FullComment(Blocks);
}
@ -379,10 +369,44 @@ void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
}
}
bool Sema::isFunctionDecl() {
if (IsThisDeclInspected)
return IsFunctionDecl;
inspectThisDecl();
return IsFunctionDecl;
}
ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
if (IsThisDeclInspected)
return ParamVars;
inspectThisDecl();
return ParamVars;
}
void Sema::inspectThisDecl() {
if (!ThisDecl) {
IsFunctionDecl = false;
ParamVars = ArrayRef<const ParmVarDecl *>();
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ThisDecl)) {
IsFunctionDecl = true;
ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
FD->getNumParams());
} else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ThisDecl)) {
IsFunctionDecl = true;
ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(),
MD->param_size());
} else {
IsFunctionDecl = false;
ParamVars = ArrayRef<const ParmVarDecl *>();
}
IsThisDeclInspected = true;
}
unsigned Sema::resolveParmVarReference(StringRef Name,
const ParmVarDecl * const *ParamVars,
unsigned NumParams) {
for (unsigned i = 0; i != NumParams; ++i) {
ArrayRef<const ParmVarDecl *> ParamVars) {
for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
const IdentifierInfo *II = ParamVars[i]->getIdentifier();
if (II && II->getName() == Name)
return i;
@ -392,12 +416,11 @@ unsigned Sema::resolveParmVarReference(StringRef Name,
unsigned Sema::correctTypoInParmVarReference(
StringRef Typo,
const ParmVarDecl * const *ParamVars,
unsigned NumParams) {
ArrayRef<const ParmVarDecl *> ParamVars) {
const unsigned MaxEditDistance = (Typo.size() + 2) / 3;
unsigned BestPVDIndex = 0;
unsigned BestEditDistance = MaxEditDistance + 1;
for (unsigned i = 0; i != NumParams; ++i) {
for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
const IdentifierInfo *II = ParamVars[i]->getIdentifier();
if (II) {
StringRef Name = II->getName();