aboutsummaryrefslogtreecommitdiff
path: root/lib/AST/CommentSema.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST/CommentSema.cpp')
-rw-r--r--lib/AST/CommentSema.cpp281
1 files changed, 258 insertions, 23 deletions
diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp
index bb0d03ebd2..7b42c861d3 100644
--- a/lib/AST/CommentSema.cpp
+++ b/lib/AST/CommentSema.cpp
@@ -11,6 +11,7 @@
#include "clang/AST/CommentDiagnostic.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringSwitch.h"
@@ -200,6 +201,90 @@ ParamCommandComment *Sema::actOnParamCommandFinish(ParamCommandComment *Command,
return Command;
}
+TParamCommandComment *Sema::actOnTParamCommandStart(SourceLocation LocBegin,
+ SourceLocation LocEnd,
+ StringRef Name) {
+ TParamCommandComment *Command =
+ new (Allocator) TParamCommandComment(LocBegin, LocEnd, Name);
+
+ if (!isTemplateDecl())
+ Diag(Command->getLocation(),
+ diag::warn_doc_tparam_not_attached_to_a_template_decl)
+ << Command->getCommandNameRange();
+
+ return Command;
+}
+
+TParamCommandComment *Sema::actOnTParamCommandParamNameArg(
+ TParamCommandComment *Command,
+ SourceLocation ArgLocBegin,
+ SourceLocation ArgLocEnd,
+ StringRef Arg) {
+ // Parser will not feed us more arguments than needed.
+ assert(Command->getNumArgs() == 0);
+
+ typedef BlockCommandComment::Argument Argument;
+ Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
+ ArgLocEnd),
+ Arg);
+ Command->setArgs(llvm::makeArrayRef(A, 1));
+
+ if (!isTemplateDecl()) {
+ // We already warned that this \\tparam is not attached to a template decl.
+ return Command;
+ }
+
+ SmallVector<unsigned, 2> Position;
+ if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
+ Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
+ llvm::StringMap<TParamCommandComment *>::iterator PrevCommandIt =
+ TemplateParameterDocs.find(Arg);
+ if (PrevCommandIt != TemplateParameterDocs.end()) {
+ SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
+ Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
+ << Arg << ArgRange;
+ TParamCommandComment *PrevCommand = PrevCommandIt->second;
+ Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
+ << PrevCommand->getParamNameRange();
+ }
+ TemplateParameterDocs[Arg] = Command;
+ return Command;
+ }
+
+ SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
+ Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
+ << Arg << ArgRange;
+
+ if (!TemplateParameters || TemplateParameters->size() == 0)
+ return Command;
+
+ StringRef CorrectedName;
+ if (TemplateParameters->size() == 1) {
+ const NamedDecl *Param = TemplateParameters->getParam(0);
+ const IdentifierInfo *II = Param->getIdentifier();
+ if (II)
+ CorrectedName = II->getName();
+ } else {
+ CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
+ }
+
+ if (!CorrectedName.empty()) {
+ Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
+ << CorrectedName
+ << FixItHint::CreateReplacement(ArgRange, CorrectedName);
+ }
+
+ return Command;
+}
+
+TParamCommandComment *Sema::actOnTParamCommandFinish(
+ TParamCommandComment *Command,
+ ParagraphComment *Paragraph) {
+ Command->setParagraph(Paragraph);
+ checkBlockCommandEmptyParagraph(Command);
+ return Command;
+}
+
InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
SourceLocation CommandLocEnd,
StringRef CommandName) {
@@ -387,6 +472,12 @@ bool Sema::isFunctionDecl() {
return IsFunctionDecl;
}
+bool Sema::isTemplateDecl() {
+ if (!IsThisDeclInspected)
+ inspectThisDecl();
+ return IsTemplateDecl;
+}
+
ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
if (!IsThisDeclInspected)
inspectThisDecl();
@@ -397,18 +488,56 @@ void Sema::inspectThisDecl() {
assert(!IsThisDeclInspected);
if (!ThisDecl) {
IsFunctionDecl = false;
+ IsTemplateDecl = false;
ParamVars = ArrayRef<const ParmVarDecl *>();
+ TemplateParameters = NULL;
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ThisDecl)) {
IsFunctionDecl = true;
+ IsTemplateDecl = false;
ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
FD->getNumParams());
+ TemplateParameters = NULL;
+ unsigned NumLists = FD->getNumTemplateParameterLists();
+ if (NumLists != 0) {
+ IsTemplateDecl = true;
+ TemplateParameters = FD->getTemplateParameterList(NumLists - 1);
+ }
} else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ThisDecl)) {
IsFunctionDecl = true;
+ IsTemplateDecl = false;
ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(),
MD->param_size());
+ TemplateParameters = NULL;
+ } else if (const FunctionTemplateDecl *FTD =
+ dyn_cast<FunctionTemplateDecl>(ThisDecl)) {
+ IsFunctionDecl = true;
+ IsTemplateDecl = true;
+ const FunctionDecl *FD = FTD->getTemplatedDecl();
+ ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
+ FD->getNumParams());
+ TemplateParameters = FTD->getTemplateParameters();
+ } else if (const ClassTemplateDecl *CTD =
+ dyn_cast<ClassTemplateDecl>(ThisDecl)) {
+ IsFunctionDecl = false;
+ IsTemplateDecl = true;
+ ParamVars = ArrayRef<const ParmVarDecl *>();
+ TemplateParameters = CTD->getTemplateParameters();
+ } else if (const ClassTemplatePartialSpecializationDecl *CTPSD =
+ dyn_cast<ClassTemplatePartialSpecializationDecl>(ThisDecl)) {
+ IsFunctionDecl = false;
+ IsTemplateDecl = true;
+ ParamVars = ArrayRef<const ParmVarDecl *>();
+ TemplateParameters = CTPSD->getTemplateParameters();
+ } else if (isa<ClassTemplateSpecializationDecl>(ThisDecl)) {
+ IsFunctionDecl = false;
+ IsTemplateDecl = true;
+ ParamVars = ArrayRef<const ParmVarDecl *>();
+ TemplateParameters = NULL;
} else {
IsFunctionDecl = false;
+ IsTemplateDecl = false;
ParamVars = ArrayRef<const ParmVarDecl *>();
+ TemplateParameters = NULL;
}
ParamVarDocs.resize(ParamVars.size(), NULL);
IsThisDeclInspected = true;
@@ -424,34 +553,136 @@ unsigned Sema::resolveParmVarReference(StringRef Name,
return ParamCommandComment::InvalidParamIndex;
}
+namespace {
+class SimpleTypoCorrector {
+ StringRef Typo;
+ const unsigned MaxEditDistance;
+
+ const NamedDecl *BestDecl;
+ unsigned BestEditDistance;
+ unsigned BestIndex;
+ unsigned NextIndex;
+
+public:
+ SimpleTypoCorrector(StringRef Typo) :
+ Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
+ BestDecl(NULL), BestEditDistance(MaxEditDistance + 1),
+ BestIndex(0), NextIndex(0)
+ { }
+
+ void addDecl(const NamedDecl *ND);
+
+ const NamedDecl *getBestDecl() const {
+ if (BestEditDistance > MaxEditDistance)
+ return NULL;
+
+ return BestDecl;
+ }
+
+ unsigned getBestDeclIndex() const {
+ assert(getBestDecl());
+ return BestIndex;
+ }
+};
+
+void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
+ unsigned CurrIndex = NextIndex++;
+
+ const IdentifierInfo *II = ND->getIdentifier();
+ if (!II)
+ return;
+
+ StringRef Name = II->getName();
+ unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
+ if (MinPossibleEditDistance > 0 &&
+ Typo.size() / MinPossibleEditDistance < 3)
+ return;
+
+ unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
+ if (EditDistance < BestEditDistance) {
+ BestEditDistance = EditDistance;
+ BestDecl = ND;
+ BestIndex = CurrIndex;
+ }
+}
+} // unnamed namespace
+
unsigned Sema::correctTypoInParmVarReference(
StringRef Typo,
ArrayRef<const ParmVarDecl *> ParamVars) {
- const unsigned MaxEditDistance = (Typo.size() + 2) / 3;
- unsigned BestPVDIndex = 0;
- unsigned BestEditDistance = MaxEditDistance + 1;
- for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
- const IdentifierInfo *II = ParamVars[i]->getIdentifier();
- if (II) {
- StringRef Name = II->getName();
- unsigned MinPossibleEditDistance =
- abs((int)Name.size() - (int)Typo.size());
- if (MinPossibleEditDistance > 0 &&
- Typo.size() / MinPossibleEditDistance < 3)
- continue;
-
- unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
- if (EditDistance < BestEditDistance) {
- BestEditDistance = EditDistance;
- BestPVDIndex = i;
- }
+ SimpleTypoCorrector Corrector(Typo);
+ for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
+ Corrector.addDecl(ParamVars[i]);
+ if (Corrector.getBestDecl())
+ return Corrector.getBestDeclIndex();
+ else
+ return ParamCommandComment::InvalidParamIndex;;
+}
+
+namespace {
+bool ResolveTParamReferenceHelper(
+ StringRef Name,
+ const TemplateParameterList *TemplateParameters,
+ SmallVectorImpl<unsigned> *Position) {
+ for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
+ const NamedDecl *Param = TemplateParameters->getParam(i);
+ const IdentifierInfo *II = Param->getIdentifier();
+ if (II && II->getName() == Name) {
+ Position->push_back(i);
+ return true;
+ }
+
+ if (const TemplateTemplateParmDecl *TTP =
+ dyn_cast<TemplateTemplateParmDecl>(Param)) {
+ Position->push_back(i);
+ if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
+ Position))
+ return true;
+ Position->pop_back();
}
}
+ return false;
+}
+} // unnamed namespace
- if (BestEditDistance <= MaxEditDistance)
- return BestPVDIndex;
- else
- return ParamCommandComment::InvalidParamIndex;
+bool Sema::resolveTParamReference(
+ StringRef Name,
+ const TemplateParameterList *TemplateParameters,
+ SmallVectorImpl<unsigned> *Position) {
+ Position->clear();
+ if (!TemplateParameters)
+ return false;
+
+ return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
+}
+
+namespace {
+void CorrectTypoInTParamReferenceHelper(
+ const TemplateParameterList *TemplateParameters,
+ SimpleTypoCorrector &Corrector) {
+ for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
+ const NamedDecl *Param = TemplateParameters->getParam(i);
+ Corrector.addDecl(Param);
+
+ if (const TemplateTemplateParmDecl *TTP =
+ dyn_cast<TemplateTemplateParmDecl>(Param))
+ CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
+ Corrector);
+ }
+}
+} // unnamed namespace
+
+StringRef Sema::correctTypoInTParamReference(
+ StringRef Typo,
+ const TemplateParameterList *TemplateParameters) {
+ SimpleTypoCorrector Corrector(Typo);
+ CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
+ if (const NamedDecl *ND = Corrector.getBestDecl()) {
+ const IdentifierInfo *II = ND->getIdentifier();
+ assert(II && "SimpleTypoCorrector should not return this decl");
+ return II->getName();
+ }
+ return StringRef();
}
// TODO: tablegen
@@ -465,7 +696,7 @@ bool Sema::isBlockCommand(StringRef Name) {
.Case("authors", true)
.Case("pre", true)
.Case("post", true)
- .Default(false) || isParamCommand(Name);
+ .Default(false) || isParamCommand(Name) || isTParamCommand(Name);
}
bool Sema::isParamCommand(StringRef Name) {
@@ -475,6 +706,10 @@ bool Sema::isParamCommand(StringRef Name) {
.Default(false);
}
+bool Sema::isTParamCommand(StringRef Name) {
+ return Name == "tparam";
+}
+
unsigned Sema::getBlockCommandNumArgs(StringRef Name) {
return llvm::StringSwitch<unsigned>(Name)
.Cases("brief", "short", 0)